What the standard says
According to the standard (C17 draft, 7.21.7.2), fgets
char *fgets(char * restrict s, int n, FILE * restrict stream);
reads from stream
at most n-1
characters (until the first '\n'
(which is in this case also written to the target) or EOF
) into s[]
, appending a '\0'
. It return
s:
NULL
:
- if
EOF
is encountered immediately (s[]
remains unchanged)
- if there was a read error (
s[]
has indeterminate contents)
s
: otherwise ("success")
(What happens in the case of n <= 1
is not clear from the standard; see here and here.)
How this answers your questions
I assume that your input ends in newlines. (For input without final newlines, see the very bottom of my answer.) For both "car\n"
and "carb\n"
as input, fgets(line, 5, stream)
reads 4
characters from stream
into line
. (It doesn't stop early because the input is at least 4 characters long, and there is no newline '\n'
among the first 3 characters.) It then appends a null terminator '\0'
.
The results are thus:
"car\n"
: "car\n"
(null-terminated, ie: 'c'
, 'a'
, 'r'
, '\n'
, '\0'
)
"carb\n"
: "carb"
(null-terminated, ie: 'c'
, 'a'
, 'r'
, 'b'
, '\0'
)
That is, the newline is cut off in this case, because it doesn't fit in. Actually, it isn't even read in by fgets
.
Note that, while fgets
always writes a null terminator '\0'
at the end, it doesn't add a newline '\n'
. It only keeps an input-final newline if it encounters one. (There can be maximally one, and it will be at the end of the resulting string (but of course before the null terminator), because fgets
stops reading input upon encountering a newline.)
Testing this with code
#include <stdio.h>
int main(void) {
FILE *fp;
char line[5];
fp = fopen("input.txt", "r");
if (fp == NULL) {
puts("couldn't open file");
return 1;
}
fgets(line, 5, fp);
printf("<%s>\n", line);
fclose(fp);
return 0;
}
This code requires an input file input.txt
; that way we can also easily test input not ending in newlines.
With car\n
(with newline) we get:
"car
"
Incidentally, with car
(no newline) we get:
"car"
With both carb\n
(with newline) and carb
(no newline) we get:
"carb"
This matches the expected results.