C fread()神奇地读取动态分配的struct成员,怎么样?

这是我为一个我正在研究的大型项目编写的测试程序。 它与使用fwrite()将struct数据写入磁盘然后使用fread()读取该数据有关。 结构的一个成员是动态分配的。

首先,这是我的代码

#include  #include  #include  #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; } 

和出门口

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

我的问题是,为什么这有效? 不应该fwrite()只写’name’包含的地址(即字符串开头的地址)? 也就是说,我将sizeof(struct Person)传递给fwrite(),但它正在编写’name’指向的字符串。

对我来说更令人困惑的是fread()的行为。 再次,如果我传递sizeof(struct Person),那么’name’的实际值是如何读取的? 如何分配内存?

我之前对如何使用fwrite()+ fread()的理解是,我必须“手动”写入’name’指向的数据,“手动”读取该数据,然后在分配内存后复制该字符串结构和’名称’成员。 换句话说,我必须自己遍历任何指针,写入数据,然后以相同的顺序读回数据。

编辑 :丹和其他人是正确的。 我用xxd查看了输出文件:

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

如果我在写入之前打印出’name’包含的地址,并且在读取之后它是相同的(0xd9a030),它与xxd的输出匹配。

您正在结构中写入数据,该结构是一个int,后跟一个指向字符串的指针。 它就像其他任何数据一样,你知道它有多长,因为结构是固定长度的 – 一个int加一个指针。 您读取与原始名称字符串相同的指针。 名称本身既不是书面也不是读书。

person_read->name person->nameperson_read->name都指向同一个内存位置。 由于在重新读取文件之前未释放person_read->name ,因此person_read->name的指针值仍然有效。

如果您已取消分配person->name或从其他程序读取该文件,则指针值将不再有效,并且尝试引用它将调用未定义的行为 – 您将打印出乱码或得到段错误。

* name指针在整个fwrite和fread调用中保持有效,这对您来说似乎是一个侥幸。 如果您在printf之前释放(person-> name),您将得到您期望的结果或错误。