2

The following program simply counts the number of key strokes until reaching EOF, and prints the count. It works as designed unless I press "Ctrl+Z" at some point, which actually resets (zeros out) the count. Why is this happening?

#include <stdio.h>

int main(){
    char ch;
    int cnt = 0;
    while ((ch = getchar()) != EOF)
    {
        cnt ++;
    }
    printf("%d",cnt);
    return 0;
}

Here, Ctrl+D activates EOF (note final count includes space):

Screenshot: Ctrl+D activates EOF, note final count includes space

But here, Ctrl+Z resets count to Zero:

Screenshot: Ctrl+D activates EOF, note final count includes space

And here, shows how count continues from zero after ctrl+z reset: Screenshot: shows how count continues from zero after ctrl+z reset

brunshte
  • 153
  • 2
  • 9
  • Control-Z on a Unix box normally triggers the 'suspend' signal, which puts the process into suspended animation and returns control to the (job control) shell. It's curious that isn't happening, but maybe that's because of the way you're running it from inside an editor (`vim`, perchance?). – Jonathan Leffler Nov 06 '18 at 06:31
  • Note that `getchar()` returns an `int`, not a `char`, so your code won't reliably detect EOF. It'll either never recognize it, or it will misrecognize some innocent character as EOF. – Jonathan Leffler Nov 06 '18 at 06:33
  • @JonathanLeffler I'm using Geany in a Linux VM off of a Mac. – brunshte Nov 06 '18 at 06:33
  • It detects EOF if I press Ctrl+D twice or if the cursor is at the beginning of a new line – brunshte Nov 06 '18 at 06:35
  • Yeah; if you're on Linux in a Mac-hosted VM, then plain `char` is a signed type and it detects EOF OK. If you use a character set such as 8859-1 or 8859-15, then typing ÿ (Latin small letter Y with diaeresis, U+00FF in Unicode) will also trigger EOF. However, if you're using a UTF-8 terminal, the 0xFF byte is not part of any valid UTF-8 encoded character, so you probably can't run into the problem. – Jonathan Leffler Nov 06 '18 at 06:38

1 Answers1

2

getchar() is buffered. So on each keypress, your loop isn't getting an opportunity to increment cnt. It stays at 0 as you type...and doesn't start getting incremented until until you hit enter or something like Ctrl-D.

When you use Ctrl-D, it goes ahead and flushes through the input--allowing your program to get the characters. But when you use Ctrl-Z, you are interrupting the in-progress line, and what you've typed so far is discarded. So your loop doesn't run.

As @JonathanLeffler points out, the fact that your program terminates instead of being suspended is some kind of artifact of your environment. But you would see the same effect on a typical setup if you just typed fg to resume the program...your in-progress input from the line you were typing is lost.

(It would help in situations like this to add more printf() statements, such as inside your loop--with fflush(stdout) to be cautious--just to get your bearings on the state of the system at each step.)

  • so are you saying that the looping is not occurring in real time? Interesting. Also I can actually use backspace to erase previously typed input, press ctrl+d and it will not count any of those key strokes either. – brunshte Nov 06 '18 at 06:49
  • @brunshte Yup. Unbuffered input is not part of the C standard, so if you want to go key-by-key you'll need to use something like termios. Search around on questions like ["Unbuffered I/O in ANSI C"](https://stackoverflow.com/questions/1647927/unbuffered-i-o-in-ansi-c) for more about that rabbit hole. Though I'll suggest that if you're trying to write some kind of game in platform-independent C for some reason, save yourself some trouble and make it a game that doesn't require unbuffered input. – HostileFork says dont trust SE Nov 06 '18 at 06:52