fgets(3)

C library function

Reads a line into an array without going past its size, keeps the \n and always terminates the string. Returns NULL at end of file or on error.

Synopsis
#include <stdio.h>
char *fgets(char *restrict s, int n, FILE *restrict stream);

Description

fgets reads characters from stream and stores them in s, at most n - 1 of them. It stops after a \n, which it keeps in the array, or at end of file, and always adds a '\0' after the last character read. So it cannot overflow an array whose real size you pass it, which makes it the safe way to read a line. Its old cousin gets, which never knew the size of the array, was removed from the standard in C11.

To read from the keyboard, pass stdin as stream.

Return value

s if at least one character was read. NULL if end of file comes before the first character, or on error. Hence the classic loop: while (fgets(line, sizeof line, stdin) != NULL).

Pitfalls

  • The \n stays in the string. To remove it, whatever the length of the line: line[strcspn(line, "\n")] = '\0';.

  • A line longer than the array is cut, and the rest arrives on the next call, as in the example. A missing \n at the end of the array signals that cut, or a last line with no newline.

  • n must be the size of the array. sizeof line works on an array declared in the function, not on a pointer received as a parameter, which measures only 8 bytes.

  • After a scanf("%d", &age), the \n typed after the number stays in the input buffer, and the next fgets reads an empty line.

Example

fgets.c
#include <stdio.h>
int main(void){    char line[8];
    while (fgets(line, sizeof line, stdin) != NULL)        printf("[%s]\n", line);    return 0;}
Terminal
$ gcc -Wall -Wextra -g fgets.c -o fgets$ printf "Rabat\nCasablanca\n" | ./fgets[Rabat][Casabla][nca]

“Rabat” fits in the array with its \n, which pushes the closing bracket onto the next line. “Casablanca” does not fit: the first call takes 7 characters plus the '\0', the second one gets the rest.

C

line_reader_repair

Write read_next_line, which reads a descriptor with read and returns one allocated line per call, newline kept as fgets does, then NULL at end of file.

Open the exercise

Now write it yourself.