Writing an array of structs to a binary file in C

23,665

Solution 1

struct Person* people;

This allocates just a pointer to struct, but you don't have any allocated space for actual struct contents. Either use malloc similarly to your write program, or try something like:

struct Person people;
fread(&people, sizeof(people), 1, data);

Solution 2

You need to allocate memory for the person first. Change: struct Person* people; into struct Person* people = malloc(sizeof(struct Person));. And don't forget to free your memory at the end: free(people);.

Solution 3

You either need to malloc memory into the pointer variable people before you do the fread, or (easier) just read directly into a local variable:

struct Person people;

fread(&people, sizeof(struct Person) * 1/* Just read one person */, 1, data);

Solution 4

You need to allocate space for the data you are reading in:

people = malloc(sizeof(*people)*numPeople);
Share:
23,665
John Jacquay
Author by

John Jacquay

Updated on December 09, 2020

Comments

  • John Jacquay
    John Jacquay over 3 years

    I have an array of structs I would like to write to a binary file. I have a write.c program and a read.c program. The write.c program seems to be working properly but when I run the read.c program I get a segmentation fault. I'm new to C so It would be great if someone could look over my code for any obvious errors. I promise it's not too long :)

    write.c:

    #include <stdlib.h>
    #include <stdio.h>
    
    struct Person 
    {
        char f_name[256];
        char l_name[256];
        int age;
    };
    
    int main(int argc, char* argv[])
    {
        struct Person* people;
        int people_count;
    
        printf("How many people would you like to create: ");
        scanf("%i", &people_count);
        people = malloc(sizeof(struct Person) * people_count);  
    
        int n;
        for (n = 0; n < people_count; n++)
        {
            printf("Person %i's First Name: ", n);
            scanf("%s", people[n].f_name);
    
            printf("Person %i's Last Name: ", n);
            scanf("%s", people[n].l_name);
    
            printf("Person %i's Age: ", n);
            scanf("%i", &people[n].age);
        }
    
        FILE* data;
        if ( (data = fopen("data.bin", "wb")) == NULL )
        {
            printf("Error opening file\n");
            return 1;   
        }
    
        fwrite(people, sizeof(struct Person) * people_count, 1, data);
        fclose(data);
    
        return 0;
    }
    

    read.c:

    #include <stdlib.h>
    #include <stdio.h>
    
    struct Person 
    {
        char f_name[256];
        char l_name[256];
        int age;
    };
    
    int main(int argc, char* argv[])
    {
        FILE* data;
        if ((data = fopen("data.bin", "rb")) == NULL)
        {
            printf("Error opening file\n");
            return 1;
        }
    
        struct Person* people;
    
        fread(people, sizeof(struct Person) * 1/* Just read one person */, 1, data);
        printf("%s\n", people[0].f_name);
    
        fclose(data);
    
        return 0;
    }
    

    Thanks for the help!

  • Steve Townsend
    Steve Townsend over 13 years
    This seems more extensible once OP decides to read > 1 element. Could loop on a single local variable instead.
  • John Jacquay
    John Jacquay over 13 years
    Can you explain when the (struct Person*) means before the malloc(sizeof(struct Person))? Is that a cast?
  • Przemek Kryger
    Przemek Kryger over 13 years
    @jjacquay712 Yes it is. I just like to not relay too much on default compiler options.
  • Karl Knechtel
    Karl Knechtel over 13 years
    Please do not cast the result from malloc. It is standard and well-defined C behaviour, and idiomatic C to leave it out. You are guaranteed to get an implicit cast. If you do cast, the compiler is no longer able to diagnose the error if you forget to #include <stdlib.h>.
  • Przemek Kryger
    Przemek Kryger over 13 years
    @Karl Knechtel Thanks, for pointing this out. Edited and removed casting.