The Ins and Outs of fgets()

With the demise of the gets() function, fgets() remains the top C language text-input function. Whether reading from a file or from standard input, the function is quite useful, but it’s not without some quirks.

The key to understanding how fgets() works, is to know how it reads characters. First, the format:

char *fgets(char *buffer, int size, FILE *stream);

buffer is a char array or chunk of memory where the characters fetched are stored.

size is the size of the buffer, the same value. The fgets() function reads one less than the size value to ensure that the input string is capped with a null character, \0. When a newline (\n) is encountered before the size value is reached, input stops, the newline is retained, and the null character appended.

stream is the handle of an open file or, typically, the stdin constant representing standard input.

Here is a typical implementation of the fgets() function to read from standard input:

#include <stdio.h>

int main()
{
    char name[8];

    printf("Your first name: ");
    fgets(name,8,stdin);
    printf("Pleased to meet you, %s.\n",name);

    return(0);
}

The fgets() statement at Line 8 reads up to 7 characters (one less than 8) from standard input (stdin) and stores the string in the name buffer. Here’s a sample run:

Your first name: Anabell
Pleased to meet you, Anabell.

Looks ducky, right? The name Anabell is input and output all neat and tidy. But, as you’ll discover, this output is coincidental; because fgets() is stream-oriented, input isn’t always guaranteed to be neat and tidy.

Consider the input stream illustrated in Figure 1.

Figure 1. How fgets() reads 8 characters of input (7 characters plus the null character).

This input stream represents text typed at the Your first name: prompt. In this case, Anabell was typed, followed by the Enter key press. That character, newline (\n), terminated input for fegts(), which processed and displayed the first 7 characters of input and transformed the newline into the null character to cap the string.

Suppose that the fgets() statement is changed to fgets(name,10,stdin) in the code and the buffer size updated to 10 characters of storage. With the same input stream illustrated in Figure 1 provided, here is the output:

Your first name: Anabell
Pleased to meet you, Anabell
.

In this example, the newline character is read and terminates the input. Figure 2 updates how the stream is read.

Figure 2. The fgets() function stops reading input when the newline is encountered.

Though the cut off is at 10 characters, the newline terminated input. Also, the newline appears in the output, which is why the period shows up on the third line.

Now suppose I change the fgets() statement to read fgets(name,16,stdin) and update the buffer size to 16 as well. Assume that Figure 3 illustrates the input stream.

Figure 3. Reading in 16 characters, though the Enter key (newline) was pressed at character 20.

Here’s the output:

Your first name: Anabell Sweet Kitty
Pleased to meet you, Anabell Sweet K.

The input stream is read up until the 15th character, K. The 16th character is set to \0 by the fgets() function. The rest of the input stream is ignored. In the output, you see the truncated stream, where the K is the last displayable character. The period appears on the same line because the newline (unread at position 20 in the stream) wasn’t processed.

I hope these examples and illustrations help you to better understand how the fgets() statement processes text input. The method is quite consistent, though it does take some getting used to.

Leave a Reply