C 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'. Другими словами, мне пришлось бы самому пройти по указателям, записать данные, а затем прочитать эти данные в том же порядке.

РЕДАКТИРОВАТЬ : Дэн и другие правы. Я просмотрел выходной файл с xxd:

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

Если я распечатаю адрес, который 'name' содержит до записи, и после чтения, он будет таким же (0xd9a030), что соответствует выходным данным из xxd.

7
задан tsliwkan 31 December 2011 в 02:50
поделиться