I guess, ungetc() may fail after scanf("%d"), because scanf may implicitly call ungetc() for the first non-numeric character.
But if the format ends with %c, this won't happen, right?

- 3,949
- 2
- 27
- 63
-
You mean if `ungetc` is always executed inside a `scanf`? – Stefano Sanfilippo May 07 '13 at 12:18
-
`ungetc() pushes c back to stream, cast to unsigned char, where it is available for subsequent read operations. Pushed-back characters will be returned in reverse order; only one pushback is guaranteed.` `ungetc() returns c on success, or EOF on error.` you are not making any sense – mf_ May 07 '13 at 12:29
3 Answers
If you read the source code for scanf (actually, the internal function that operates scanf
), you will see that a %c
specifier will trigger execution of the CT_CHAR
switch case, which does not call ungetc
on the standard input. So you are right.
This applies to GNU libc only, but I expect other implementations to behave similarly.

- 32,265
- 7
- 79
- 80
The other answers are correct for glibc. Unfortunately, this is a difficult question to answer from a standards perspective.
POSIX specifies both fscanf(3)
and ungetc(3)
, but it doesn't describe their interaction. It has this to say about the former:
An item shall be read from the input, unless the conversion specification includes an
n
conversion specifier. An input item shall be defined as the longest sequence of input bytes (up to any specified maximum field width, which may be measured in characters or bytes dependent on the conversion specifier) which is an initial subsequence of a matching sequence. The first byte, if any, after the input item shall remain unread.
The only mention of ungetc
in the whole document is irrelevant to OP's question. However, it does confirm that fscanf
is meant to return characters pushed back via ungetc
. That was not in serious doubt, but ungetc
never defines what it means by "read operations" so it is helpful to have a specific line in the standard to point to.
The standard does not specify what it means by "the first byte [...] shall remain unread." I interpret it as meaning that the C library is required to behave as if the character were not read, even though any implementation will have to read the character to know when the input item ends. That, in turn, means that it should not prevent the use of ungetc
, regardless of the format string.
(While this reading may appear strained, POSIX certainly does not say "the first byte [...] shall remain unread or be pushed onto the input stream as if by ungetc()", which is what they would have written if they wanted to allow ungetc
to fail after an fscanf
call.)
Fortunately, ungetc
's specification is loose enough that this can actually work. POSIX allows multiple bytes of pushback, and even specifies what happens in that case:
The pushed-back bytes shall be returned by subsequent reads on that stream in the reverse order of their pushing.
[...]
One byte of push-back shall be provided. If ungetc() is called too many times on the same stream without an intervening read or file-positioning operation on that stream, the operation may fail.
It also conveniently does not specify that implementations must always provide the same number of bytes of pushback, only that they are allowed to fail after the first. That means a conforming implementation could simply provide two bytes of ungetc
pushback, so long as fscanf
only used one.
In theory, I would argue that the standard actually requires ungetc
to be available after any call to fscanf
or its sister functions. fscanf
is a read operation, and read operations are supposed to leave you with at least one byte of pushback. In practice, this is a very subtle reading of the standard, and you should expect implementations to differ on this point.
Finally, as a practical matter, I found that this program executes successfully on my system, which has an Ubuntu variation of glibc 2.21:
#include <stdio.h>
int main(int argc, char **arv){
FILE *file = fopen("/tmp/file.txt", "w+");
if(file == NULL){
perror("fopen");
return 2;
}
if(fprintf(file, "123\n") == EOF){
printf("fprintf failed.");
}
if(fseek(file, 0, SEEK_SET) == -1){
perror("fseek");
return 1;
}
if(ungetc((int)'1', file) == EOF){
printf("First ungetc failed");
return 3;
}
int value;
if(fscanf(file, "%d", &value) == EOF){
printf("fscanf failed");
return 4;
}
if(ungetc((int)'2', file) == EOF){
printf("Second ungetc failed");
return 5;
}
return 0;
}
This is not a guarantee that glibc always does the right thing, but it apparently does the right thing in this specific case.
-
1You seem to read that from the POSIX specification. In the C99 specification there's a footnote saying " fscanf pushes back at most one input character onto the input stream. Therefore, some sequences that are acceptable to strtod, strtol, etc., are unacceptable to fscanf." which at least says that the byte is (of course) actually read and then pushed back (the method for pushing back is not specified AFAIK though). – skyking Nov 03 '16 at 15:14
-
You need to test the code on an unbuffered input stream, preferably one which is not seekable. – rici Jun 04 '17 at 23:09
-
@rici: What is that supposed to accomplish? ungetc necessarily uses a buffer, otherwise it wouldn't have anywhere to stuff the extra bytes. – Kevin Jun 05 '17 at 00:10
-
@Kevin: ungetc only has to succeed once, so it could just use a field in the FILE structure, resorting to the file buffer in the case where the file happened to be buffered and there is unused space in the file buffer (which is likely the case in the typical use case, since the ungetc's will follow a read.) Forcing the file to be unbuffered would remove that possibility. But it turns out that glibc allocates a pushback buffer on demand, so it can actually handle unlimited pushback (for some definition of unlimited, but its a lot.) – rici Jun 05 '17 at 03:44
Of course, it does not depend alone on whether the format ends with %c, since conversion specifiers before that might fail.

- 18,255
- 14
- 57
- 171