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

时间:2011-12-31 02:31:32

标签: c struct fwrite fread

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

首先,这是我的代码

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

和出口

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'指向的数据,“手动”读取该数据,然后复制该字符串为结构和“名称”成员分配内存。换句话说,我必须自己遍历任何指针,写入数据,然后以相同的顺序读回数据。

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

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

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

3 个答案:

答案 0 :(得分:10)

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

答案 1 :(得分:6)

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

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

答案 2 :(得分:1)

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