I tried the following code (compiled with GCC 13, on Ubuntu 22.04)
int x;
int ret = scanf("%d", &x);
char ch;
scanf("%c", &ch);
printf("%c, %d\n", ch, ret);
with the input
-*
It prints *, 0
, which suggests that the first input to x
failed (the return value is 0
), but the first minus sign was consumed. This also happens when I change the minus sign to +
, but not for other characters.
Is this sign treated as the beginning of an integer? If so, why this input is seen as failure? If not, why is it consumed? Or is this totally undefined behavior?
Plus, the same thing happens for double
when the input is .
.
Is this sign treated as the beginning of an integer? If so, why this input is seen as failure? If not, why is it consumed? Or is this totally undefined behavior?
The following applies from fscanf()
:
An input item is read from the stream, ... . An input item is defined as the longest sequence of input characters which does not exceed any specified field width and which is, or is a prefix of, a matching input sequence.348 The first character, if any, after the input item remains unread. If the length of the input item is zero, the execution of the directive fails; this condition is a matching failure ... .
C23dr § 7.23.6.2 9
348
fscanf
pushes back at most one input character onto the input stream. Therefore, some sequences that are acceptable tostrtod
,strtol
, etc., are unacceptable tofscanf
.
As I read this, with OP's input of "-*"
, it wasn't until the '*'
was read that scanf()
realized the input matching failure and push the '*'
back into stdin
(as required by the spec.). Some systems will successfully push back the '-'
also (note that the footnote itself is informative - not a spec.), but OP's system did not.
Moral of the story:
(f)scanf()
is difficult to use with faulty input. Instead for line input, use fgets()
to read the line into a string and then parse the string.
Note that optional leading white-space characters (with "%d"
) are also consumed.
Note there are longer input sequences such as "-.*"
for "%f"
which cause trouble.