Search code examples
cfgets

Null terminating char array in C and difference between using read and fgets


I did something like this to read from standard input.

char *lines[50];
char buffer[50];

while((fgets(buffer, sizeof(buffer), stdin))!=NULL) {
    buffer[strlen(buffer)-1] = '\0';
    lines[i] = malloc(strlen(buffer));
    memcpy(lines[i++], buffer, strlen(buffer));
}

I wanted to do something similar using the read system call.

while((nread=read(0, buffer, sizeof(buffer)))>0) {
    buffer[strlen(buffer)-1] = '\0';
    lines[i] = malloc(strlen(buffer));
    memcpy(lines[i++], buffer, strlen(buffer));
}

Resetting i to 0 and printing out the strings using printf("%s", lines[i]), I get correct results for the first method but do not always corresponding results in the second method. Why is this?

Also, when reading from standard input using read, is it necessary to append a null character to the end of the string or does read do it for you?

I directed input from a file containing the following:

This is test input
This is another test input

Not reading correctly, not reading correctly

When I print after getting input using fgets() I get the exact same as output.

When I print after getting input using read() I get this:

This is test input
This is another test input

Not
reading correctly, not reading correctly
put

No

ADDITIONAL NOTES:

If I change char buffer[50] to something larger, the second case works, but I don't see why it shouldn't work for this particular instance.

The problem seems to be that read reads all 50 characters when I redirect input from a file. Is there some way that read can read up to a newline character and stop there on each iteration? It seems to do this when receiving input from the console.


Solution

  • read doesn't add anything; there is no terminating 0. After read, strlen(buffer) returns whatever depending on what was there in the buffer before read. Good news are, you don't need to call strlen at all, because read returns a number of characters transmitted:

    while((nread = read(0, buffer, sizeof(buffer) - 1))>0) {
        buffer[nread] = '\0';
        lines[i] = malloc(nread + 1));
        memcpy(lines[i], buffer, nread + 1);
    }
    

    PS: Don't forget to test nread against -1.