Search code examples
clinuxfgets

Why doesn't fgets read whole line in while loop but works in for loop?


If my fgets is in a while loop, it only returns half the string. If it's in a for loop, it returns the whole string.. Any idea why?

Code below:

    FILE *fp; // File pointer
    char filename[] = "results.tsv";
    fp = fopen(filename, "r"); // Open file argv[1] for READ


    char s[4096];

    int num = atoi(fgets(s, sizeof(s), fp)); // Get first line (number of units in file)

    int i;
    for(i = 0; i < num; i++)
    {
        printf("%s", fgets(s, sizeof(s), fp)); // Prints everything
    }


    while (fgets(s, sizeof(s), fp) != NULL) // Loop until no more lines
    {
        printf("%s\n", s); // Only prints the x's
    }

    fclose(fp); // Close file

And the files contents:

1
xxxxxxxx       yyyy       eee

Where the big spaces are tabs (\t).

If I run it, I get:

For loop only:

xxxxxxxx       yyyy       eee

While loop only:

xxxxxxxx

Thanks.


Solution

  • As already diagnosed, your code 'works for me'. Here's the SSCCE I created for it. If invoked with no arguments, it uses the while loop. If invoked with any arguments, it uses the for loop. Either way, it works correctly for me. Note that the code doesn't use the return value from fgets() directly; it checks that the input operation succeeded before doing so. It also echos what it is doing and reading as it goes.

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char **argv)
    {
        FILE *fp;
        char filename[] = "results.tsv";
    
        if ((fp = fopen(filename, "r")) == 0)
        {
            fprintf(stderr, "%s: failed to open file %s\n", argv[0], filename);
            exit(1);
        }
    
        char s[4096];
    
        if (fgets(s, sizeof(s), fp) == 0)
        {
            fprintf(stderr, "Premature EOF\n");
            exit(1);
        }
    
        int num = atoi(s);
        printf("Num lines: %d\n", num);
    
        if (argc > 1)
        {
            printf("For loop:\n");
            for (int i = 0; i < num; i++)
            {
                if (fgets(s, sizeof(s), fp) == 0)
                {
                    fprintf(stderr, "Premature EOF\n");
                    exit(1);
                }
                printf("%d: %s", i+1, s);
            }
        }
        else
        {
            int i = 0;
            while (fgets(s, sizeof(s), fp) != NULL)
            {
                printf("While loop:\n");
                printf("%d: %s", ++i, s);
            }
        }
    
        fclose(fp);
    
        return 0;
    }
    

    If you use this code and it fails on your system, then you could submit your evidence. Amongst other things, you should identify the platform on which you're working, and you should give a hex dump (or equivalent) of the data in the file results.tsv. The data file I used, for example, contained the bytes:

    0x0000: 31 0A 78 78 78 78 78 78 78 78 09 79 79 79 79 09   1.xxxxxxxx.yyyy.
    0x0010: 65 65 65 65 0A                                    eeee.
    0x0015: