Leo S
Leo S

Reputation: 339

when read from binary segmentation fault

I have 2 files that are creator.c and reader.c

creator.c:

#include <stdio.h>
#include <string.h>

struct Person{
  char *name;
  int numb;
  char *kind;
};

int main() {

  struct Person *per1=malloc(sizeof(struct Person));
  struct Person *per2=malloc(sizeof(struct Person));
  struct Person *per3=malloc(sizeof(struct Person));
  struct Person *per4=malloc(sizeof(struct Person));
  struct Person *per5=malloc(sizeof(struct Person));
  struct Person *per6=malloc(sizeof(struct Person));

  char per1_name[]="a1";
  char per2_name[]="b1";
  char per3_name[]="c1";
  char per4_name[]="d1";
  char per5_name[]="e1";
  char per6_name[]="f1";

  per1->name=malloc(strlen(per1_name)+1);
  per2->name=malloc(strlen(per2_name)+1);
  per3->name=malloc(strlen(per3_name)+1);
  per4->name=malloc(strlen(per4_name)+1);
  per5->name=malloc(strlen(per5_name)+1);
  per6->name=malloc(strlen(per6_name)+1);

  strcpy(per1->name,per1_name);
  strcpy(per2->name,per2_name);
  strcpy(per3->name,per3_name);
  strcpy(per4->name,per4_name);
  strcpy(per5->name,per5_name);
  strcpy(per6->name,per6_name);

  per1->numb=1;
  per2->numb=2;
  per3->numb=3;
  per4->numb=4;
  per5->numb=5;
  per6->numb=6;


  char per1_kind[]="x";
  char per2_kind[]="y";
  char per3_kind[]="z";
  char per4_kind[]="q";
  char per5_kind[]="w";
  char per6_kind[]="e";

  per1->kind=malloc(strlen(per1_kind)+1);
  per2->kind=malloc(strlen(per2_kind)+1);
  per3->kind=malloc(strlen(per3_kind)+1);
  per4->kind=malloc(strlen(per4_kind)+1);
  per5->kind=malloc(strlen(per5_kind)+1);
  per6->kind=malloc(strlen(per6_kind)+1);

  strcpy(per1->kind,per1_kind);
  strcpy(per2->kind,per2_kind);
  strcpy(per3->kind,per3_kind);
  strcpy(per4->kind,per4_kind);
  strcpy(per5->kind,per5_kind);
  strcpy(per6->kind,per6_kind);



  FILE *write_ptr;
  write_ptr = fopen("save.bin","wb");
  fwrite(per1,sizeof(struct Person),1,write_ptr);
  fwrite(per2,sizeof(struct Person),1,write_ptr);
  fwrite(per3,sizeof(struct Person),1,write_ptr);
  fwrite(per4,sizeof(struct Person),1,write_ptr);
  fwrite(per5,sizeof(struct Person),1,write_ptr);
  fwrite(per6,sizeof(struct Person),1,write_ptr);


  return 0;
}

reader.c

#include <stdio.h>

struct Person{
  char *name;
  int numb;
  char *kind;
};

int main(){
  FILE *fp=fopen("./save.bin","rb");
  struct Person *person1=malloc(sizeof(struct Person));
  fread(person1,sizeof(struct Person),1,fp);
  printf("%s\n",person1->name );
}

creator.c file create a binary file called save.bin and push the person struct data as binary, reader.c read from that file and print the name of the person but this code getting segmentation fault, what is the point that i missed out?

Upvotes: 0

Views: 45

Answers (2)

Jonathan Wood
Jonathan Wood

Reputation: 67195

This code:

fread(person1,sizeof(struct Person),1,fp);

... reads a Person structure from the file.

And this code:

printf("%s\n",person1->name );

.. attempts to access the memory that Person.name points to.

But what does it point to? name contains a memory address that you read from the file, but no memory has been allocated for the name. You are reading the memory at that address but that address is no longer a valid memory address. And you get a segmentation fault when you attempt to access invalid memory.

There are several ways to deal with this but the easiest is to store the name in the same block of memory. You can do that like this:

#define MAX_NAME 80

struct Person{
  char name[MAX_NAME + 1];
  int numb;
  char *kind;
};

Now, reading the person also reads the name. You'll also need to do the same thing with kind or you'll have the same problem there.

Upvotes: 1

Paul Ogilvie
Paul Ogilvie

Reputation: 25286

write does not write the values of the things pointed to. It will write the pointers. When you read, you read the pointers, but they are invalid.

Either declare name and kind as fixed-sized arrays, or write their values separately and then don't forget to malloc new memory before you read them.

EDIT: it is better to first write the length of the name and then read exactly that length, because more records can follow.

int main() {

  struct Person *per1=malloc(sizeof(struct Person));
  per1->name=malloc(strlen("hello")+1);
  strcpy(per1->name,"hello");

  FILE *write_ptr;
  write_ptr = fopen("save.bin","wb");
  fwrite(per1,sizeof(struct Person),1,write_ptr);
  int len= strlen(per1->name);
  fwrite(&len,sizeof(int), 1, write_ptr;   // first write the length
  fwrite(per1->name,len,1,write_ptr);      // then write those bytes
  fclose(write_ptr);                       // don't forget!
  return(0);
}
// reader
int main(){
  FILE *fp=fopen("./save.bin","rb");
  struct Person *person1=malloc(sizeof(struct Person));
  fread(person1,sizeof(struct Person),1,fp);
  int len;
  fread(&len,sizeof(int),1,fp);                // now read the length
  person1->name=malloc(len+1);                 // allocate memory for it,
  fread(person1->name,len,1,fp);               // read it
  person1->name[len]= '\0';                    // and terminate it
  printf("%s\n",person1->name );
}

Upvotes: 3

Related Questions