1

I have a rather simple question about the fgets function.

As I understand, the fgets function tries to add a newline '\n' and a null terminator '\0' to the end.

Thus, if I give it car as input and write the result into an array char line[5], it will contain {'c', 'a', 'r', '\n', '\0'}, is that right?

But what if I give it carb as input? Will the result then be {'c', 'a', 'r', 'b', '\0'}?

That is, does fgets always force a null terminator '\0' into the receiving char array?

int main(void) {
    char line[5];
    printf("Give an input. Please give max length of 3 characters so fgets can put newline and NULL inside ");
    fgets(line, 5, stdin);
    return 0;
}
Lover of Structure
  • 1,561
  • 3
  • 11
  • 27
cosman
  • 23
  • 5

1 Answers1

0

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 returns:

  • 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.

Lover of Structure
  • 1,561
  • 3
  • 11
  • 27