Search code examples
cfilefgetsfgetc

How to use fgets after using fgetc?


I'm trying to write a specific program that reads data from a file but I realized that when I read the file with fgetc, if I use fgets later, it doesn't have any output.

For example, this code:

#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE * arq = fopen("arquivo.txt", "r");
    char enter = fgetc(arq);
    int line_count = 1;
    
    while(enter != EOF) {
        if (enter == '\n') line_count++;
        enter = fgetc(arq);
    }

    printf("%d", line_count);
    char str[128];

    while(fgets(str, 128, arq)) printf("%s", str);
}

the second while doesn't print anything but if I delete the first while, the code prints the file content. Why is that happening?


Solution

  • TLDR: rewind(arq); is what you want

    When you read from a file, the internal file pointer advances as you read, so that each subsequent read will return the next data in the file. When you get to the end, all subsequent reads will return EOF as there is nothing more to read.

    You can manipulate the internal file pointer with the fseek and ftell functions. fseek allows you to set the internal file pointer to any point in the file, relative to the beginning, the end, or the current position. ftell will tell you the current position. This allows you to easily remember any position in the file and go back to it later.

    SYNOPSIS

     #include <stdio.h>
    
     int fseek(FILE *stream, long offset, int whence);
    
     long ftell(FILE *stream);
    
     void rewind(FILE *stream);
    

    DESCRIPTION

    The fseek() function sets the file position indicator for the stream pointed to by stream. The new position, measured in bytes, is obtained by adding offset bytes to the position specified by whence. If whence is set to SEEK_SET, SEEK_CUR, or SEEK_END, the offset is relative to the start of the file, the current position indicator, or end-of-file, respec‐ tively. A successful call to the fseek() function clears the end-of-file indicator for the stream and undoes any effects of the ungetc(3) function on the same stream.

    The ftell() function obtains the current value of the file position indicator for the stream pointed to by stream.

    The rewind() function sets the file position indicator for the stream pointed to by stream to the beginning of the file. It is equivalent to:

      (void) fseek(stream, 0L, SEEK_SET)
    

    except that the error indicator for the stream is also cleared (see clearerr(3)).

    One caveat here is that the offsets used by fseek and returned by ftell are byte offsets, not character offsets. So when accessing a non-binary file (anything not opened with a "b" modifier to fopen) the offsets might not correspond to characters exactly. It should always be ok to pass an offset returned by ftell back to fseek unmodifed to get to the same spot in the file, but trying to compute offsets otherwise may be tricky.