0

So I am trying to write a c file that has a student record database, once the file runs it is supposed to read student records from a binary file and add them to a linked list: the student struct looks like this :

typedef struct student {
    char lname[10], initial, fname[10];
    unsigned long SID;
    float GPA;

    struct student* next; /* pointer to the next student record */   
} studentList;

I am using single linked lists for my data, and my code runs fine if I read and write the data with fscanf. However, once I started using fwrite and fread, everytime my program loads it would not load up the data from the text file correctly, when I check the binary file it seems it has data in it. Here is what I have for my load and write data functions:

void printRecords() {
    FILE *fPointer = fopen("data.bin", "w");
    studentList *newStudent = head;
    while (newStudent != NULL) { /*Loop through linked list starting from head node*/
        fwrite(&newStudent, sizeof(newStudent), 1, fPointer);

        newStudent = newStudent->next;
    }
}

void loadRecords() {
    studentList *cStudent;
    FILE *fPointer = fopen("data.bin", "r");
    int counter = 0;
    int x = 0;
    int n = 0;
    while (n != 0) {
        printf("test\n");
        if (fPointer == NULL) {
            break;
        }
        cStudent = (studentList *)malloc(sizeof(studentList));
        n = fread(&cStudent, sizeof(cStudent), 1, fPointer);
        x = cStudent->GPA;
        printf("%d\n", x);
        if (feof(fPointer)) { break; }
        if (counter == 0) {
            head = cStudent;
            temp = (studentList *)malloc(sizeof(studentList));
            temp = cStudent;
            counter++;
        }

        temp->next = (studentList *)malloc(sizeof(studentList));
        temp->next = cStudent;
        temp = temp->next;
    }
    fclose(fPointer);
}

so what am I doing wrong as right now it does not read anything into my list, it seems like it writes but not sure if it even writes the correct data, I have spent a long time trying to figure this out and have been stuck on it for a while now, thanks in advance.

chqrlie
  • 131,814
  • 10
  • 121
  • 189

3 Answers3

1

To read write to binary files in c.

FILE   *fPointer=fopen("data.bin","wb");  //to write file
FILE *fPointer=fopen("data.bin","rb");    //to read file
Community
  • 1
  • 1
Mohan
  • 1,871
  • 21
  • 34
  • 1
    On Linux systems the `b` flag has no effect. So before providing this as an answer it would be good to clarify whether the OP is running on Linux. If it is Linux then this probably isn't the answer. – kaylum Dec 09 '15 at 10:30
  • Binary mode is advisable and necessary on some platforms such as Windows, but it is not the only problem with the code. – chqrlie Dec 09 '15 at 10:34
  • Yes, I am running on linux, I've implemnted chqrlie's fix, but now I am getting seg faults and am trying to figure it out. my struct and head node are declared as global variables, hope this can be useful to say as well. – Mohammed Al-Huneidi Dec 09 '15 at 19:54
1

There are multiple problems with your code.

printRecords has problems:

  • you should use binary mode.
  • you write the contents of the pointer and some indeterminate contents instead of whet the pointer points to. This is actually undefined behavior.
  • you forgot to close the file.
  • the value written to the file for the next member is meaningless. Writing the same records may produce different file contents for different runs.

Here is a corrected version that returns the number of records written or -1 if the file could not be opened:

int printRecords(void) {
    FILE *fPointer = fopen("data.bin", "wb");
    studentList *sp;
    int n = 0;

    if (fPointer == NULL)
        return -1;

    /* Loop through linked list starting from head node */
    for (sp = head; sp != NULL; sp = sp->next) {
        n += fwrite(sp, sizeof(newStudent), 1, fPointer);
    }
    fclose(fPointer);
    return n;
}

loadRecords has even more problems:

  • binary mode should be used too.
  • the way you test for end of file is incorrect.
  • the way you link records does not work either.

Here is a corrected version of loadRecords that returns the number of records read or -1 if the file could not be opened:

int loadRecords(void) {
    studentList student, *newsp, *sp;
    FILE *fPointer = fopen("data.bin", "rb");
    int n = 0;

    if (fPointer == NULL)
        return -1;

    while (fread(&student, sizeof(student), 1, fPointer) == 1) {
        n++;
        student.next = NULL;  // value read from file is meaningless
        newsp = malloc(sizeof(studentList));
        *newsp = student;
        if (head == NULL) {
            head = newsp;
        } else {
            /* append the new record to the list */
            for (sp = head; sp->next; sp = sp->next)
                continue;
            sp->next = newsp;
        }
    }
    fclose(fPointer);
    return n;
}

Be aware that storing binary data to the file system this way is not portable. The representation of integers and floats may differ from one platform to another, as well as alignment of the structure members, especially the next pointer which is useless in the file anyway. This file should only be read back on the same platform, with the same program that wrote it, making it a poor choice for backup or persistent storage.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Thank you so much for your answers, however I forgot to note that I am running on linux, thus that might be a problem. I am currently getting seg faults after I implemented your fixes, I don't know why exactly. – Mohammed Al-Huneidi Dec 09 '15 at 19:51
  • @MohammedAl-Huneidi: post your corrected program to a pastebin, there must be some other bug. – chqrlie Dec 09 '15 at 19:55
0

There are problems in the file write function, mainly the data pointer and size:

void printRecords(){
    FILE *fPointer = fopen("data.bin","wb");    // add "b" mode (MSVC)
    if (fPointer == NULL)                       // check file opened
        exit(1);                                // or report "Cannot open file"
    studentList *newStudent = head;
    while(newStudent !=NULL)
    {
        fwrite(newStudent, sizeof(*newStudent), 1, fPointer);   // remove the & and add a *
        newStudent = newStudent->next;
    }
    if (fclose(fPointer))                       // close the file
        exit(1);                                // or report "Failed to close file"
}
Weather Vane
  • 33,872
  • 7
  • 36
  • 56