darylnak
darylnak

Reputation: 239

Trying to Understand fgets()

I'm writing a program to read a file line by line. I know fgets() will read up until a new line, n-1 characters, or EOF. What confuses me is how does fgets() know to advance to a new line/where it is in a file?

To be clearer, I know in Java you have to explicitly tell the scanner to read the next line. But in C, I just put fgets() in a while loop and trust that is does it's job.

How can I logically reassure myself that fgets() is actually advancing to the next line, and not reading the same line over and over again in that while loop (yes, I know I can print things out)?

Upvotes: 2

Views: 1881

Answers (1)

chqrlie
chqrlie

Reputation: 144685

The semantics of fgets() are quite straight forward: read bytes from the FILE* stream pointer until either:

  • the destination array is full (n-1 bytes have been read and stored into it).
  • a newline was read from the stream and stored into the destination array.
  • the end of file has been reached or a read error occurred (EOF was returned by the fgetc() call or equivalent). end-of-file and read-error conditions can be distinguished by calling ferr() and/or feof() after fgets() returns NULL.

A null terminator is always stored into the array after the bytes read from the stream, unless end of file was reached immediately (fgets() returns NULL) or if the buffer size is specified as having a size of 0.

fgets() behaves as if the stream was read one byte at a time with fgetc().

fgets() consumes the bytes read from the stream and stores them into the destination array. It cannot read the same bytes again unless you explicitly seek backwards into the stream with rewind(), fseek() or fsetpos(), if the stream supports seeking at all. Streams attached to regular files usually support seeking, but files open in text mode require specific handling on some systems, notably Microsoft Windows. Note also that a byte pushed back into the stream with ungetc() will be read by fgets() before any bytes from the actual stream.

fgets() stores the newline character into the destination array if the line was short enough to fit in the array before the null terminator.

fgets() breaks long lines into smaller chunks if the line exceeds the available space in the destination array. Handling long lines is tricky and error prone. Note that when fgets() reads a partial line due to lack of space in the destination array, the next call to fgets() will continue reading from the same line at the point where the previous call stopped.

If upon return from fgets(), the destination array does not end with a newline, one of the following occurred:

  • the current line was too long and only as many bytes as fit in the array were read from the stream.
  • the line read was the last in the file and the file does not end with a newline sequence.
  • a null byte was read from the file.

Mishandling these cases may result in potential undefined behavior and/or exploitable flaws.

Upvotes: 7

Related Questions