Reputation: 163
I wrote a simple program to test the scanf() function in C. It basically reads from the terminal, char
by char
, reprinting the return value
and the char
read; and to terminate if EOF/EOT is met or if a \n newline
is read.
#include <stdio.h>
#include <stdbool.h>
int main(void) {
char c; int ret;
printf("Enter the chars to test: ");
//LOOP (scan & print) only when return is not EOF and char is not newline
while ( ((ret = scanf("%c", &c)) != EOF) && c!='\n' ) {
printf("%i %c\n", ret, c);
}
return 0;
}
It terminates correctly, if newline (Enter
) is pressed. But the it won't just terminate with a single Ctrl-D
. A single Ctrl-D
will flush the typed 'chars' and printing them. Then after that it will wait again for input, although an EOF
has been sent with the Ctrl-D
. If we press Ctrl-D
again the 2nd time directly after the 1st (2x) or just Enter
it will terminate. So you will need two consecutive Ctrl-D
to terminate the program (or the loop in this case).
Example:
If you input 987
on the terminal, then press Enter
; then 1 9
, 1 8
, 1 7
will be printed on newline each.
If you input 987
on the terminal, then press Ctrl-D
; then 1 9
will be printed on the same line (because there is no Enter
typed after inputing the 987
input), 1 8
, 1 7
will be printed on newline. Then it will still wait for more inputs, unless it is terminated by directly entering a 2nd consecutive Ctrl-D
or with a newline (Enter
). So it (the program) will only stop (exit the loop) after a newline
or 2nd consecutive Ctrl-D
.
I am confused. Shouldn't a single Ctrl-D
sent stop the loop here? What should I do to stop the program (scanf loop) after receiving just a single Ctrl-D
?
I tested the code on Lubuntu 19.10 with gcc 9.2.1.
Upvotes: 2
Views: 2581
Reputation: 38498
Test the returned value for one, not EOF
. When eof is reached first time, zero is returned. The next scanf after zero returns EOF
.
while ( ((ret = scanf("%c", &c)) == 1) && c!='\n' ) {
printf("%i %c\n", ret, c);
}
This behavior is specified for the standard C library.
On success, the function returns the number of items of the argument list successfully filled. This count can match the expected number of items or be less (even zero) due to a matching failure, a reading error, or the reach of the end-of-file.
If a reading error happens or the end-of-file is reached while reading, the proper indicator is set (feof or ferror).
You can add if (feof(stdin) != 0) break;
into the loop body, if you use more complex input format.
If you read chars only, is it not better use fgetc
?
Upvotes: 0
Reputation: 84561
The issue is scanf()
does not return EOF
until there is no more input waiting and EOF
is encountered. (your "%c"
conversion specifier will otherwise accept any character, including the '\n'
character, as valid and consider it a successful conversion)
When you type a line of characters, e.g. "abcdefg"
and attempt to press Ctrl+d (indicating end-of-input), the input ("abcdefg"
) is processed and when 'g'
is reached, then scanf()
blocks waiting on your next input. (because a successful conversion took place and no matching or input failure occurred)
Once Ctrl+d is typed a 2nd time (indicating end-of-input), when there is no input to process, EOF
is reached before the first successful conversion and an input-failure occurs,scanf()
then returns EOF
.
See: man 3 scanf -- RETURN VALUE section and C11 Standard - 7.21.6.2 The fscanf function(p16)
Upvotes: 2