Search code examples
carraysstructurefwritefread

How to write/read data to/from structure array using write/fread?


I have spent quite a lot time attempting to find a solution how to write and read structure to/from file and completely get stuck.

The code should be very simple, but I think I've missed quite important details about fwrite/fread. I think write is working but I am not completely sure. Once I try to read into array I get segmentation fault error on the k=1.

I would be ultimately happy if someone could guide me in what direction should I move further.

#include <stdio.h>

struct Student {
char matrikl[6];
char shortName[6];
int value1;
int value2;
int value3;
int value4;
int money;
}xStudent;

int calcMoney(int,int,int,int);

int main(void)
{
int i=0;
printf("How much students to insert!\n");
scanf("%i",&i);
    struct Student S[i];

for (int var = 0; var < i; ++var) {
    printf("insert student data\n");
    printf("Matriklinumber\n");
    scanf("%s", S[var].matrikl);
    printf("Student name\n");
    scanf("%s", S[var].shortName);
    printf("Insert values!\n");
    scanf("%i%i%i%i",&S[var].value1,&S[var].value2,&S[var].value3,&S[var].value4);
    S[var].money=calcMoney(S[var].value1,S[var].value2,S[var].value3,S[var].value4);;
}

FILE*sourcefile;
sourcefile=fopen("text.txt","ab+");

for (int var = 0; var < i; ++var) {
    fwrite(&S[var],sizeof(struct Student),1,sourcefile);
}
fclose(sourcefile);


sourcefile=fopen("text.txt","rb+");
struct Student A[i];

if (sourcefile==NULL) perror ("Error opening file");
          else
          {
                  int k=0;
                  while (fgetc(sourcefile) != EOF) {
                  fread(&A[k],sizeof(struct Student),1,sourcefile);
                  k++;
                  }
          }
fclose(sourcefile);
return 0;
}

int calcMoney(int xvalue1, int xvalue2, int xvalue3, int xvalue4)
{
int Sum = xvalue1+xvalue2+xvalue3+xvalue4;
if(Sum==20)
    return 100;
else
    if(Sum>=16 && Sum<20)
        return 75;
    else return 0;
}

Solution

  • You have the right idea, but this should fix your problem.

    for (int var = 0; var < i; ++var) {
        fwrite(&S[i], sizeof(struct Student), 1, sourcefile);
    }
    

    The argument 1 in fwrite after the sizeof statement indicates you only want to add one Student at a time.

    Please see the doc for fwrite: http://www.cplusplus.com/reference/cstdio/fwrite/

    And also:

              while (fgetc(sourcefile) != EOF) {
              fread(&A[k], sizeof(struct Student), 1, sourcefile);
              k++;
              }
    

    Please see the doc for fread: http://www.cplusplus.com/reference/cstdio/fread/

    I know it's the cplusplus website, but it's the only place I could find good docs on the functions.

    Also, the below array initializes to 0 elements:

    struct Student A[k];
    

    You may want to try managing a linked list for this instead.

    Might end up looking something like:

    struct StudentList {
        struct Student* student;
        struct StudentList* next;
    };
    


    struct StudentList* students = NULL;
    
    while(!feof(sourcefile)) {
        struct StudentList* newlink = malloc(sizeof(struct StudentList));
        newlink->student = malloc(sizeof(struct Student));
        newlink->next = NULL;
    
        fread(newlink->student, sizeof(struct Student), 1, sourcefile); 
    
        if(NULL != students) {
            struct StudentList* iter;
            for(iter=students;
                NULL != iter->next;
                iter = iter->next); // iterate to last link
    
            iter->next = newlink; // add new link to the end
        } else students = newlink; // add new link to the beginning
    }
    



    Then to free your list, just use something like:

    struct StudentList* iter, *head;
    for(iter=students;
        NULL != iter;)
    {
        head = iter;
        free(iter->student);
        free(iter);
        iter = head;
    }