Search code examples
cinputfgets

Why do multiple fgets require more than sizeof(type)


I hope somebody can help me in explaining the following behaviour when using multiple fgets.

The following code works and the user needs to enter something for each fgets :

char input[1]; // to store a character
fgets(input,3,stdin); // read a character from the keyboard

char test[5];// for second fgets
fgets(test,3,stdin); // to test if this asks for user input too

printf("The character input is %c",input[0]);

==========OUTPUT============
Enter a character please: 
e
f
The character input is e
=============================

However the following code will only let the user enter input for the FIRST fgets:

char input[1]; 
fgets(input,2,stdin); // THIS IS THE DIFFERENCE, USING 2 INSTEAD OF 3

char test[5];
fgets(test,3,stdin);

printf("The character input is %c",input[0]);
=====OUTPUT=============
Enter a character please: 
e
The character input is e
=========================

The difference is this line:

fgets(input,2,stdin);

Where using less than 3 means that the following fgets does not ask for user input. I think this might be because with size 3, when the user presses Enter after inputting a character, the \n is consumed by the first fgets when the size is 3 or more. But if the size is less than 3, the \n is not consumed by first fgets, leaving it on stdin, and so it is consumed by the 2nd fgets which is why the 2nd fgets terminates without waiting for user input.

If I use sizeof(char) as that value, then I get output:

=============OUTPUT============
Enter a character please: 
e
The character input is 
===============================

Which is weird because I have seen people recommending using sizeof(type) for that parameter.

I hope somebody can explain why 3 is needed to consume the \n, I would have expected 2 would be enough, e.g. 1 byte for the char and 1 byte to consume the \n, and also if that is the case then the recommended choice of sizeof(type) is wrong, because you would need sizeof(type)+1, but it seems you actually need sizeof(type) + 2 to allow the \n to be consumed and removed from stdin. Please help me with your understanding of this, thankyou.


Solution

  • You have two different problems:

    The first is that you write out of bounds of your array input, which leads to undefined behavior.

    For the second problem, when you tell fgets that the size of the buffer is 3 it will read the character and the newline and add both to the buffer you provide and add the string null-terminator. When you say that the size is 2 it will read the character but not the newline, since the size includes the string null-terminator. That means the next fgets call will read the newline and think it's an empty line.

    You solve the problems by using a buffer large enough to fit all the characters, plus the newline and the string null-terminator. For a single characters, that means your array must contain three elements:

    char input[3];
    fgets(input, sizeof input, stdin);
    

    As an optional solution, you could read a single character (for example with getchar or getc or fgetc).

    Then you need to read (but don't store) characters in a loop until you have read the newline.

    Perhaps something like this:

    int input = getchar();
    
    // Discard the rest of the line
    for (int temp = getchar(); temp != '\n' && temp != EOF; temp = getchar())
    {
        // Empty
    }