C fread () magically reads dynamically allocated structure members, how?

This is a test program that I wrote for a larger project that I am working on. This involves writing structure data to disk using the fwrite () function, and then reading this data using fread (). One member of the structure is dynamically allocated.

Firstly, here is my code

#include <stdio.h> #include <stdlib.h> #include <string.h> #define STRING_LEN 128 struct Person { int age; char *name; }; int main(int argc, const char *argv[]) { struct Person *person = calloc(1, sizeof(struct Person)); person->age = 22; person->name = calloc(STRING_LEN, sizeof(char)); char *name = "Name that is really, really, really, really, really, really, long."; strncpy(person->name, name, STRING_LEN); FILE *out_file = fopen("rw.out", "w"); fwrite(person, sizeof(struct Person), 1, out_file); fclose(out_file); FILE *in_file = fopen("rw.out", "r"); struct Person *person_read = calloc(1, sizeof(struct Person)); fread(person_read, sizeof(struct Person), 1, in_file); fclose(in_file); printf("%d %s\n", person_read->age, person_read->name); free(person->name); free(person); free(person_read); return 0; } 

And outpout

 22 Name that is really, really, really, really, really, really, long. 

My question is: why does this work? Shouldn't fwrite () write only the address that contains the "name" (ie, the address of the beginning of the line)? That is, I pass sizeof (struct Person) to fwrite (), and yet it writes the line pointed to by 'name'.

Even more confusing for me is the behavior of fread (). Again, if I pass sizeof (struct Person), how is the actual value of the "name" read? How is memory allocated for him?

My previous understanding of how to use fwrite () + fread () was that I would have to "manually" write the data pointed to by "name", "read" this data manually, and then copy this line after highlighting memory for both the structure and the member 'name'. In other words, I would have to go through any pointers, write the data, and then read this data in the same order.

EDIT : Dan and the others are true. I looked at the output file using xxd:

 0000000: 1600 0000 0000 0000 30a0 d900 0000 0000 ........0....... 

If I print the address that 'name' contains before writing and after reading, the same (0xd9a030), which corresponds to the output from xxd.

+6
source share
3 answers

You write data to a struct, which is an int followed by a pointer to a string. It is just data, like everything else, and you know how long it takes, because struct is a fixed length is int plus a pointer. You are reading the same pointer to the same name string as the original. The name itself is not written or read.

+9
source

Both person->name and person_read->name terminate, pointing to the same memory location. Since you did not release person->name before reading the file, the value of the pointer in person_read->name remains valid.

If you freed person->name or read a file from another program, the pointer value will no longer be valid, and trying to refer to it will cause undefined behavior - you either printed gibberish or received a segmentation error.

+5
source

The * * pointer remains valid in all fwrite and fread calls that seem random to you. If you select (person-> name) before printf, you will get a result or error awaiting you.

+1
source

Source: https://habr.com/ru/post/904786/


All Articles