fgetc(stdin) in a loop is producing strange behaviour
Asked Answered
J

4

8

I have this code

while(1){
    printf("hello world !\n");
    fgetc(stdin);
}

when this runs and I enter a letter like this:

hello world !
a

it ignores the fgetc(stdin) in the next loop and prints hello world twice without waiting for input.

hello world !
a
hello world !
hello world !
a
hello world !
hello world !
a
hello world !
hello world !
a
hello world !
hello world !

I have tried putting fflush(stdin) before or after the fgetc(stdin) but it still produces the same behaviour, what am I doing wrong ?

Jonme answered 21/8, 2012 at 22:18 Comment(0)
T
7

Terminals tend to be line-buffered, meaning that stream contents are accessible on a line-by-line basis.

So, when fgetc starts reading from STDIN, it's reading a full line, which includes the newline character that ended that line. That's the second character you're reading.

As for fflush, that's for flushing output buffers, not input buffers.

So, what you want to do here is to purge the input buffer by reading from it until its empty, or just explicitly ignore newline characters.

Tyeshatyg answered 21/8, 2012 at 22:24 Comment(1)
Your advice worked, I purged the input buffer with this line while(fgetc(stdin) != '\n'); then the problem disappearedJonme
M
10

That's because you actually enter two characters: 'a' and a newline. Also, since terminal is normally line-buffered your program will only see your input once you hit the newline. It'll be informative to enter a longer line of text, too.

If you want to change this behavior you have two options: reading entire lines (i.e. all characters up to a newline or end-of-file) or switching terminal to non-canonical mode. The latter makes sense if you're working on an interactive terminal application like a text editor. See termios manpage for details. In short, you'll want to set MIN and TIME options to zero to make reads from terminal return immediately as data becomes available. If you do go down this path, make sure you switch the terminal back when you exit, including due to reception of a signal.

fflush() affects the output, not the input.

Morentz answered 21/8, 2012 at 22:21 Comment(0)
T
7

Terminals tend to be line-buffered, meaning that stream contents are accessible on a line-by-line basis.

So, when fgetc starts reading from STDIN, it's reading a full line, which includes the newline character that ended that line. That's the second character you're reading.

As for fflush, that's for flushing output buffers, not input buffers.

So, what you want to do here is to purge the input buffer by reading from it until its empty, or just explicitly ignore newline characters.

Tyeshatyg answered 21/8, 2012 at 22:24 Comment(1)
Your advice worked, I purged the input buffer with this line while(fgetc(stdin) != '\n'); then the problem disappearedJonme
D
3

There are two characters: a and \n (newline). Your loop reads reads the a, then loops and prints "hello world !". It then sees \n and loops and prints "hello world !". When you type a+\n in the terminal, it's storing the two characters in the stdin buffer. fgetc(stdin); will read from the stdin buffer if there is a char available, otherwise it waits until a char is added to the buffer.

Since terminals are line-buffered (ie, do not send the content to the program until a newline is reached) you have a few options:

  • read the entire line into a buffer, but take only the first character
  • ignore newlines
  • turn off line-buffering

To turn off line buffering, look at http://c-faq.com/osdep/cbreak.html and http://www.flipcode.com/archives/_kbhit_for_Linux.shtml and http://ubuntuforums.org/showthread.php?t=225713 (although I have not tested any of the code here).

Dahlgren answered 21/8, 2012 at 22:21 Comment(5)
So how would I read the a and the \n character at once ? To stop the behaviourJonme
@lilroo- Try scanf("%c\n", &temp);Wrac
@lilroo: use scanf(" %c", &temp); - the leading space in the format string tells the %c conversion specifier to skip over any leading whitespace.Semblable
@lilroo: your best option is probably to just turn off line bufferingDahlgren
You can use gets(buffer) or fgets(buffer,size,stdin)Chiasmus
C
2

You have two characters there, 'a' and '\n'. That is the problem, because fgetc will only read ONE character. This is the documentation.

If you enter only a '\n' - hit enter only - you will have the expected behaviour.

Hope it helps!

Clare answered 21/8, 2012 at 22:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.