Bruce
Bruce

Reputation: 35255

What happens when fgets encounters EOF in the middle of an input?

The man page says:

fgets() return s on success, and NULL on error or when end of file occurs while no characters have been read.

I wrote a small C file which calls fgets to test its behavior. I particularly wanted to see what happens when EOF occurs after some characters have been inputted. I used the eof key combination (Ctrl+D) on bash. I had to press Ctrl+D twice for fgets to return. It printed out the characters inputted until I pressed Ctrl+D twice. Pressing Ctrl+D once after some characters had been inputted had no effect at all. If I inputted some characters after this they were stored in the passed array. Why does fgets behave this way?

Upvotes: 4

Views: 4176

Answers (3)

CB Bailey
CB Bailey

Reputation: 791849

You should find that if the input ends after at least some characters were read but before a newline is encountered that fgets returns non-null (a pointer to the supplied buffer) and the supplied buffer won't contain a newline but will be null terminated.

This is just what the documentation for fgets says.

E.g.

#include <stdio.h>

int main(void)
{
    char buffer[200];

    char* ret = fgets(buffer, sizeof buffer, stdin);

    printf("exit code = %p\n", (void*)ret);

    if (ret != 0)
    {
        printf("read code = %s<--END\n", buffer);
    }

    return 0;
}

output:

$ printf "no newline here->" | ./a.out
exit code = 0x7fff6ab096c0
read code = no newline here-><--END

or:

$ printf "newline here->\nmore text\n" | ./a.out
exit code = 0x7fff6f59e330
read code = newline here->
<--END

on no input:

$ printf "" | ./a.out
exit code = (nil)

Upvotes: 4

Keith Thompson
Keith Thompson

Reputation: 263257

It's just like reading from text file stored on disk that doesn't happen to have a new-line character at the end of the last line. The C standard's description of fgets() specifies what it does, including in this case:

char *fgets(char * restrict s, int n, FILE * restrict stream);

The fgets function reads at most one less than the number of characters specified by n from the stream pointed to by stream into the array pointed to by s. No additional characters are read after a new-line character (which is retained) or after end-of-file. A null character is written immediately after the last character read into the array.

fgets() can give you a string without a new-line if the input line is too long to fit, or if there's no new-line before end-of-file.

When you're reading from a disk file, an end-of-file condition occurs when you reach the end of the file. When you're reading from an interactive device such as a keyboard, the way an end-of-file condition is triggered is not specified by the C standard. On Unix-like systems, it's triggered by typing Control-D at the beginning of a line, or by typing Control-D twice in the middle of a line (though the control character can be reconfigured).

Whether this is even possible depends on the implementation.

C99 7.19p2 says:

A text stream is an ordered sequence of characters composed into lines, each line consisting of zero or more characters plus a terminating new-line character. Whether the last line requires a terminating new-line character is implementation-defined.

Unix-like systems generally don't require the trailing new-line character.

Upvotes: 2

William Pursell
William Pursell

Reputation: 212248

The behavior you describe has nothing to do with fgets. The shell does not close the input stream until you press ctrl-D the 2nd time.

Upvotes: 6

Related Questions