Search code examples
cfilefwritefreadfseek

Understanding fseek() in C


I was learing File I/O in C and was interested in using it to read and write structures to files via fwrite() and fread() functions, now after my code ran successfully I was wondering if I could read a specific structure from an array of structures and put it in some given structure.


Here is my attempt at it

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

typedef struct tools {
    int recordno;
    char toolname[50];
    int quantity;
    float cost;
} tools;

void recordprinter(tools a) {
    printf("%d %s %d %f\n", a.recordno, a.toolname, a.quantity, a.cost);
}

int main() {
    FILE * fp;
    
    fp = fopen("file.txt", "rb+");
    tools * a = (tools * ) malloc(100 * sizeof(tools));
    for (int i = 0; i < 100; i++) {
        a[i].cost = 0;
        a[i].toolname[0] = 'a';
        a[i].toolname[1] = '\0';
        a[i].quantity = 0;
        a[i].recordno = i + 1;
    }
    for (int i = 0; i < 100; i++) {
        fwrite(a + i, sizeof(tools), 1, fp);
        fseek(fp, sizeof(tools), SEEK_CUR);
        // I used fseek here just because fwrite doesnot move the cursor when\
        it writes something to the file.(and fwrite(a + i, sizeof(tools), 100, fp) gives weird gliches)
    }

    fseek(fp, 0, SEEK_SET); // to bring cursor back to start of the file.

    fread(a, sizeof(tools), 1, fp);

    fseek(fp, sizeof(tools) * 50, SEEK_SET); // now I expect the cursor to be at 51th structure.

    fread(a + 3, sizeof(tools), 1, fp); // I am now writing the 51th structure in a[3]    

    recordprinter(a[3]);
    // this gives output 26 and not 51   

    return 0;
}

Now when I ran the programm I expected 51 a 0 0.00000 as output, but to my surprise it is picking up the 26th structure and putting it in a[3]
Any help will be appritiated!!


Solution

  • Try changing fopen to use w+ instead of rb+

    Also, remove the fseek when creating the file, as mentioned, fwrite definitely advances the file offset after writing data (provided fwrite does write data at all).

    Here is the output observed using the modified code below.

    gcc main.c
    ./a.out
    51 a 0 0.000000
    
    // main.c
    
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct tools {
        int recordno;
        char toolname[50];
        int quantity;
        float cost;
    } tools;
    
    void recordprinter(tools a) {
        printf("%d %s %d %f\n", a.recordno, a.toolname, a.quantity, a.cost);
    }
    
    int main() {
        FILE * fp;
        
        // recommend for this example using w+
        // w because it creates the file if the file doesn't exist
        // r fails if the file doesn't exist (and that doesn't seem useful here)
        // + because you are reading and writing
        // avoiding b and choosing POSIX - linux
        // may be wrong, if libc docs says b is needed then use b
        // my doc "man fopen" says b is ignored
        fp = fopen("file.txt", "w+");
        // check return values, file pointer exist? fail if not
        if (fp==NULL) { printf( "oops file not opened\n" ); return 1; }
        tools * a = (tools * ) malloc(100 * sizeof(tools));
        for (int i = 0; i < 100; i++) {
            a[i].cost = 0;
            a[i].toolname[0] = 'a';
            a[i].toolname[1] = '\0';
            a[i].quantity = 0;
            a[i].recordno = i + 1;
        }
        // alternative way to save 100 objects
        // if ( fwrite(a, sizeof(tools), 100, fp) != 100 )
        // {
        //   printf( "oops 100 objects not written to file\n" );
        //  return 1;
        // }
        for (int i = 0; i < 100; i++) {
            fwrite(a + i, sizeof(tools), 1, fp);
            // remove fseek, not needed, fwrite does what is needed here
            //fseek(fp, sizeof(tools), SEEK_CUR);
            // I used fseek here just because fwrite doesnot move the cursor when
            // it writes something to the file.(and fwrite(a + i, sizeof(tools), 100, fp) gives weird gliches)
        }
    
        // no review after this line, it seems to do what author intends
    
        fseek(fp, 0, SEEK_SET); // to bring cursor back to start of the file.
    
        fread(a, sizeof(tools), 1, fp);
    
        fseek(fp, sizeof(tools) * 50, SEEK_SET); // now I expect the cursor to be at 51th structure.
    
        fread(a + 3, sizeof(tools), 1, fp); // I am now writing the 51th structure in a[3]    
    
        recordprinter(a[3]);
        // this gives output 51 as desired   
    
        return 0;
    }