8

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?

Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
caramel1995
  • 2,968
  • 10
  • 44
  • 57

2 Answers2

18

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".

Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
Brian Roach
  • 76,169
  • 12
  • 136
  • 161
  • Thanks a lot. I was so confused about printing things twice in the terminal and some other odd behaviors of my programs. So from your answer, I found that the first print is by the terminal driver, and the second is by my program and just after hitting the Enter key. thank you!!!! – AMIR REZA SADEQI Mar 24 '20 at 14:22
5

^Z is only translated by the console to an EOF signal to the program when it is typed at the start of a line. That's just the way that the Windows console works. There is no "workaround" to this behaviour that I know of.

Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • Then why ^z is not counted as a character when i place it after a stream of characteres in one line??For example "abcdefg^z" only return me "There are 7 characters inpit" instead of 8 after i input ^z after that line. – caramel1995 Sep 10 '11 at 17:59
  • @caramel23: I believe that the windows console simply ignores it and doesn't pass a character to the program being run. I don't know why this happens. – CB Bailey Sep 10 '11 at 18:05