Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What makes fgets() actually wait for user input if pointed to stdin?

Tags:

c

stdin

fgets

I am new to C, and I am trying to understand what goes on in fgets() when pointed to stdin.

Basically my question is this, forgive me I might not actually understand fgets() that well:

If I specify a pointer to some file to use in fgets(), then fgets() reads from that location onwards up to either \n, EOF, or the specified limit-1

So why does it behave differently if I point to stdin, in the sense, what makes it wait for user input rather than simply finding nothing to read and hence returning NULL?

Thank you for your time

like image 617
Stefan Avatar asked Nov 27 '16 21:11

Stefan


2 Answers

fgets() reads from the argument stream. If this stream is tied to a device or a pipe, it blocks until input is obtained from the device/pipe or until an end of file is detected.

stdin is usually tied to the terminal. Reading from the terminal reads any pending input and in the case of fgets() keeps reading until a newline is typed or enough characters are input. There is one extra layer to understand here: the kernel driver for the terminal performs its own buffering by default, causing the input operation to block until a newline is typed even if more characters are typed than fgets() expects. These extra characters are left pending in the terminal buffer.

The terminal can be configured for raw mode (as opposed to the default cooked mode) with the stty system call (on Posix systems). Doing this would remove the buffering in the device driver, but buffering would still be performed in the FILE * stream. fgets() can only access characters from the stream after this buffering is performed. Streams tied to devices are usually line buffered by default, causing the stream buffering to match the device drive buffering. If you set both the device to raw mode and the stream as unbuffered, characters will be available to fgets() as they are typed and fgets() will stop reading when it gets a newline or when it has read size-1 characters.

Note also that you can enter an end of file in cooked mode by typing Control-D on unix and OS/X systems and Control-Z Enter on Windows systems.

like image 141
chqrlie Avatar answered Nov 14 '22 21:11

chqrlie


If I specify a pointer to some file to use in fgets(), then fgets() reads from that location onwards up to either \n, EOF, or the specified limit-1

It doesn't read from that location, it reads from that file.

So why does it behave differently if I point to stdin, in the sense, what makes it wait for user input rather than simply finding nothing to read and hence returning NULL?

It doesn't behave any differently. The fgets function only accepts a pointer to a file and it always reads from that file.

I suspect you're confusing fgets with some other function that does something else. The fgets function is, and only is, a function to do a blocking read from a file.

like image 28
David Schwartz Avatar answered Nov 14 '22 21:11

David Schwartz