Понимание структур, содержащих структуры, и как их правильно инициализировать

#c #arrays #pointers #struct

#c #массивы #указатели #структура

Вопрос:

Я пытаюсь понять, как правильно инициализировать структуры, которые содержат другие структуры (особенно массивы структур!). Я сделал этот небольшой обзор, представляющий мое текущее понимание, и хотел спросить, является ли это правильным или неправильным способом сделать:

(Обратите внимание, что для краткости методы уничтожения и проверки malloc() опущены.)

Простейшая структура содержит только статические переменные:

 typedef struct simple {
    int variable;
} Simple;

Simple *create_simple(int value) {
    Simple *simple = malloc(sizeof(Simple));
    simple->variable = value;
    return simple;
}
  

Использование динамических переменных, таких как массивы, требует дополнительного выделения:

 typedef struct array {
    size_t length;
    int *element;
} Array;

Array *create_array(size_t length) {
    Array *array = malloc(sizeof(Array));
    array->length = length;
    array->element = malloc(length * sizeof(int));
    return array;
}
  

То же самое касается структур, содержащих указатели на другие структуры. В этом случае нам нужно выделить память для внутренней структуры отдельно:

 typedef struct container {
    Simple *internal;
} Container;

Container *create_container(int value) {
    Container *container = malloc(sizeof(Container));
    // Is this correct? Or should I just malloc(sizeof(Simple))?
    container->internal = create_simple(value);
    return container;
}
  

Более сложной является структура, содержащая динамический массив структурных указателей:

 typedef struct struct_array {
    size_t length;
    Simple **element;
} StructArray;

StructArray *create_struct_array(size_t length) {
    StructArray *structArray = malloc(sizeof(Array));
    structArray->length = length;
    // Would I alternatively need to loop over 
    // the array and call create_simple() on each index?
    structArray->element = malloc(length * sizeof(Simple));
    return structArray;
}
  

Теперь глубина вложенности структур может быть любой:

 typedef struct complex_container {
    size_t length;
    StructArray *element;
} ComplexContainer;

ComplexContainer *create_complex_container(size_t length) {
    ComplexContainer *complexContainer = malloc(sizeof(ComplexContainer));
    complexContainer->length = length;
    // Is this valid? My create_struct_array function should 
    // allocate the memory?
    complexContainer->element = create_struct_array(length);
    return complexContainer;
}
  

Комментарии:

1. Что заставляет вас думать, что это неверно?

2. В основном вопрос, использовать ли мои функции create внутри других функций create ИЛИ malloc внутри них.

3. И если не было бы лучше использовать массивы внутри определений структур вместо только указателей

4. Распространенной идиомой является использование sizeof object вместо sizeof (тип объекта). В долгосрочной перспективе это безопаснее, на случай, если объект меняет типы. Поэтому вместо этого напишите «foo * p = malloc(sizeof * p);». Имена ваших переменных слишком длинные и делают строки длиннее, чем они должны быть. В приведенных выше фрагментах это не представляет большой проблемы, но может снизить качество кода при обработке ошибок и добавлении большего количества элементов структуры.