Behavior of fgets(), newline character and how it gets stored in the memory

Viewed 491

I have this code below and I'm curious what would be stored in the memory if I entered

"Hi" then I'll press enter, will 'H' 'i' '\n' '\0' be stored in the memory

and if I enter

"Hello" then I'll press enter, will 'H' 'e' 'l' 'l' '\0' be stored in the memory then 'o' '\n' be in the buffer

and lastly, if I enter

"Hell" then I'll press enter, will 'H' 'e' 'l' 'l' '\0' be stored in the memory then '\n' be in the buffer

char str [5];

fgets(str, 5, stdin);
printf("%s", str);
3 Answers

fgets(buf, n, stream) reads input and saves it into buf until 1 of 4 things happen.

  • Buffer is nearly full. Once n-1 characters read (and saved), '\0' is appended to buf. Function returns buf. There is likely remaining characters in stream to read.1

  • '\n' is read from stream. '\n' is appended to buf. '\0' is appended to buf. Function returns buf. The line has been completely read.

  • End-of-file occurs. Had some characters been read before, '\0' is appended to buf. Function returns buf. Else NULL is returned.

  • Input error (rare). NULL is returned. state of buf is indeterminate.

The only thing different about reading '\n' versus other characters is that it informs fgets() to stop reading.


1 Should a full buffer get read without '\n', to read and toss the rest of the line:

int ch;
while ((ch = fgetc(stream)) != '\n' && c != EOF) {
  ;
}

Given the definition of fgets():

char *fgets( char *str, int count, FILE *stream ); (until C99)

char *fgets( char *restrict str, int count, FILE *restrict stream ); (since C99)

Reads at most count - 1 characters from the given file stream and stores them in the character array pointed to by str. Parsing stops if a newline character is found, in which case str will contain that newline character, or if end-of-file occurs. If bytes are read and no errors occur, writes a null character at the position immediately after the last character written to str.

The behavior is undefined if count is less than 1. It is also not specified whether a null character is written if count==1.

fgets stores the inputed line with the maximum length (size) of 5 in the str variable and null terminates it.

Since the size you provide is 5, if you input "Hello" it will store H e l l \0 replacing the 'o', 'o' is not stored and, normally, 'o' and '\n' will remain in the stdin buffer though this is not standard mandated.

If you intput "Hell" the stdin buffer will have H e l l \n so when its stored '\n' will be replaced by '\0', and '\n' will remain in the buffer.

In the same way if the line is smaller than 5 - 1, nothing is replaced, the char array is null terminated i.e. "Hel" will be stored as H e l \n \0, and the stdin buffer will be emptied.

This is why you normally declare your char array 1 char bigger than the actual max size expected, and pass its size to fgets:

fgets(str, sizeof(str), stdin);

Note that you should not use fflush(stdin).

From man fgets on my machine:

char * fgets(char * restrict str, int size, FILE * restrict stream);

The fgets() function reads at most one less than the number of characters specified by size from the given stream and stores them in the string str. Reading stops when a newline character is found, at end-of-file or error. The newline, if any, is retained. If any characters are read and there is no error, a `\0' character is appended to end the string.

This means that you are correct about what will be stored in your str buffer. The unread characters can presumably be read by a subsequent read on stdin, but this will depend on the OS and where you are reading from. The C standard doesn't mandate it.

Related