Размещение переменных внутри динамически размещаемых структур

Предположим, что у вас есть структура, содержащая указатель на массив и его размер, например:

typedef struct {
    int * array;
    int arr_size;
}IntArray;

и хотите иметь это внутри другой структуры, это можно сделать двумя способами:

typedef struct{
    IntArray ia;
    //other variables
}Base1;

typedef struct{
    IntArray * ia;
    //other variables
}Base2;

Что происходит, когда я динамически выделяю Base1 и Base2 (например, Base1 b1 = (Base1 *)malloc(sizeof(Base1));) и почему я должен выбирать один способ, а не другой?


person riciloma    schedule 21.07.2018    source источник
comment
это можно сделать двумя способами - эти две разные структуры очень и очень разные.   -  person Dai    schedule 22.07.2018
comment
Всегда стремитесь использовать меньше указателей. Если вы можете объяснить, почему вам абсолютно необходим указатель, отлично. Если вы не можете, вам это не нужно. Таким образом, Base1, если вам не нужна Base2 по какой-то конкретной причине, которую вы можете защитить.   -  person n. 1.8e9-where's-my-share m.    schedule 22.07.2018
comment
@н.м. и если array имеет известный размер, то массив также может существовать на месте: int array[1234] что позволяет полностью избежать динамического выделения (или указания на массив, размещенный в стеке).   -  person Dai    schedule 22.07.2018


Ответы (2)


  1. Пространство вложенных структур существует как пространство в их родительской структуре, что означает, что им не нужно собственное выделение (но им все же может потребоваться собственная инициализация), тогда как поля структуры, которые являются указателями, должны быть одновременно выделены и освобождены, когда родительский объект запускается (это частая причина утечек памяти в C, поскольку в нем нет автоматических деструкторов объектов, как в C++). Хотя, используя указатель, вы можете указать на другой массив/объект, который может существовать в стеке (таким образом избегая malloc/free), но тогда вы можете столкнуться с ошибками времени жизни объекта в зависимости от разницы в области действия и времени жизни ваших объектов.

  2. Вложенные структуры существуют на месте, поэтому они не могут использоваться другими экземплярами. Это может быть или не быть идеальным (вы можете решить это с помощью шаблона на C++, в C вам придется довольствоваться отвратительный макрос препроцессора).

  3. Поскольку динамически размещаемые объекты (например, ваш массив и вложенный элемент ia вашего типа Base2) существуют в разных местах физической памяти, это означает, что ваш код не будет использовать преимущества пространственной локальности, которые могут использовать кэши ЦП. из и вы подвергнетесь двойному разыменованию указателя. Таким образом, ваш код будет работать медленнее.

В любом случае: когда вы работаете в C, вы обычно должны пытаться свести к минимуму использование указателя.

person Dai    schedule 21.07.2018

По сути, вопрос такой же, как выделить структуру или указатель на структуру? То есть:

IntArray myStruct;

or

IntArray *myStructPtr;

Тот факт, что рассматриваемые переменные находятся внутри структуры, не имеет значения, вы можете выбрать любой из них.

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

Base1 содержит фактическую структуру IntArray, поэтому вы

Base1 *b1 = malloc(sizeof(*b1));
b1->ia.array = malloc(yourSizeHere);

Base2 содержит указатель на структуру IntArray, поэтому вам нужно указать для нее существующую структуру IntArray или память malloc(), а затем получить к ней доступ как к указателю.

Base2 *b2 = malloc(sizeof(*b2));
b2->ia = malloc(sizeof(*(b2->ia)));
b2->ia->array = malloc(yourSizeHere);
person Stephen Docy    schedule 21.07.2018
comment
Поскольку C не имеет модификаторов доступа, возникает вопрос о том, кому принадлежат внутренние объекты, на которые указывают, и кто отвечает за вызов free для этих внутренних объектов. С элементами по значению это происходит автоматически. - person Dai; 22.07.2018