简体   繁体   中英

Misunderstanding of binary file writing/reading in C

Can someone please explain why the following code segfaults whenever I attempt to do anything with either of the character arrays inside of the struct after I read it in from the binary file? The code is as follows:

struct my_struct {
    int filename_len;
    char *filename;
    int size;
    char *contents;
};

int main() {
    FILE *fp = fopen("test.bin", "wb");
    char *one = "list1";
    char *two = "test file";
    int one_len = strlen(one);
    int two_len = strlen(two);

    fwrite(&one_len, sizeof(int), 1, fp);
    fwrite(&one, one_len, 1, fp);
    fwrite(&two_len, sizeof(int), 1, fp);
    fwrite(&two, two_len, 1, fp);
    fclose(fp);



    struct x *temp = malloc(sizeof(struct x));
    fp = fopen("test.bin", "rb");

    fread(&(temp->filename_len), sizeof(int), 1, fp);
    fread(&(temp->filename), sizeof(char), temp->filename_len, fp);
    fread(&(temp->size), sizeof(int), 1, fp);
    fread(&(temp->contents), sizeof(char), temp->size, fp);

    // This  does not segfault
    printf("%d\n", temp->filename_len);

    // This does
   printf("%s\n", temp->filename);
   fclose(fp);

   return 0;
}

Thank you!

fwrite(&one, one_len, 1, fp);

&one is the address of the pointer one on the stack, not the location it points to. This means that, instead of writing the string pointed to by one , you're writing the bytes that make up its address, potentially along with whatever happens to come after that in memory.

fread(&(temp->filename), sizeof(char), temp->filename_len, fp);

Similarly, this reads a pointer (or part of a pointer) into temp->filename , and may additionally overwrite whatever happens to be after it.

What you need to do is:

fwrite(one, one_len, 1, fp);

Write the actual contents of the string, not its address.

temp->filename = calloc(temp->filename_len + 1, sizeof(char));
fread(temp->filename, sizeof(char), temp->filename_len, fp);

Allocate a buffer sized appropriately for the filename, then read data into that buffer.

1) You are calling fread with the address of temp->filename .

fread(&(temp->filename), sizeof(char), temp->filename_len, fp)

You don't want to do this. temp->filename is already a pointer to a char. Instead pass simply temp->filename .

2) You aren't allocating any space for temp->filename . You need to do this after you read temp->filename_len .

fread(&(temp->filename_len), sizeof(int), 1, fp);
temp->filename = malloc((temp->filename_len + 1) * sizeof(char))
fread(temp->filename, sizeof(char), temp->filename_len, fp);
temp->filename[temp->filename_len] = '\0';

Similarly for temp->contents

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM