Stefan Stefan - 6 days ago 6
C Question

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

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

Answer

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.

Comments