caramel1995 caramel1995 - 10 months ago 51
C Question

EOF in Windows command prompt doesn't terminate input stream

Code:

#include <stdio.h>
#define NEWLINE '\n'
#define SPACE ' '

int main(void)
{
int ch;
int count = 0;

while((ch = getchar()) != EOF)
{
if(ch != NEWLINE && ch != SPACE)
count++;
}
printf("There are %d characters input\n" , count);

return 0;
}


Question:


  1. Everything works just fine, it will ignore spaces and newline and output the number of characters input to the screen (in this program I just treat comma, exclamation mark, numbers or any printable special symbol character like ampersand as character too) when I hit the EOF simulation which is
    ^z
    .

  2. But there's something wrong when I input this line to the program. For example I input this:
    abcdefg^z
    , which means I input some character before and on the same line as
    ^z
    . Instead of terminating the program and print out total characters, the program would continue to ask for input.

  3. The EOF terminating character input only works when I specify
    ^z
    on a single line or by doing this:
    ^zabvcjdjsjsj
    . Why is this happening?


Answer Source

This is true in almost every terminal driver. You'll get the same behavior using Linux.

Your program isn't actually executing the loop until \n or ^z has been entered by you at the end of a line. The terminal driver is buffering the input and it hasn't been sent to your process until that occurs.

At the end of a line, hitting ^z (or ^d on Linux) does not cause the terminal driver to send EOF. It only makes it flush the buffer to your process (with no \n).

Hitting ^z (or ^d on Linux) at the start of a line is interpreted by the terminal as "I want to signal EOF".

You can observe this behavior if you add the following inside your loop:

printf("%d\n",ch);

Run your program:

$ ./test
abc                      <- type "abc" and hit "enter"
97
98
99
10
abc97                    <- type "abc" and hit "^z"
98
99

To better understand this, you have to realize that EOF is not a character. ^z is a user command for the terminal itself. Because the terminal is responsible for taking user input and passing it to processes, this gets tricky and thus the confusion.

A way to see this is by hitting ^v then hitting ^z as input to your program.

^v is another terminal command that tells the terminal, "Hey, the next thing I type - don't interpret that as a terminal command; pass it to the process' input instead".