Динамически выделяйте элемент структуры, который также является структурой

#arrays #c #pointers #multidimensional-array #dynamic-memory-allocation

Вопрос:

 struct A {
int num,
struct B *data0, *data1 , *data2
};
 

Для приведенного выше примера кода количество «данных» может измениться. В настоящее время это 3.
Предположим, я хочу получить ввод от пользователя и соответственно выделить ему память.
Я думал о преобразовании его в массив, что-то вроде *data[].

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

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

1. Один из подходов: Исследование гибкого элемента массива

Ответ №1:

Перед началом динамического выделения элементов структуры полезно знать синтаксис структуры языка Си.

 struct A 
{
    size_t num;
    struct B data[];
};

struct A *alloc(size_t numdata)
{
    struct A *data = malloc(szieof(*data)   numdata * sizeof(data -> data[0]));

    if(data) data -> num = numdata;
    return data;
}
 

Если вы хотите хранить указатели:

 struct A 
{
    size_t num;
    struct B *data[];
};
 

или 2D массив:

 #define NCOLUMNS  100

struct A 
{
    size_t num;
    struct B data[][NCOLUMNS];
};
 

или 3D массив

 #define NCOLUMNS  200
#define NROWS     100

struct A 
{
    size_t num;
    struct B data[][NROWS][NCOLUMNS];
};
 

и т. д. и т. д.

Функция выделения останется прежней (здесь вы можете увидеть, почему использование объектов намного лучше, чем типов в sizeof )

Ответ №2:

Конечно, вам следует использовать стиль, подобный массиву, когда количество элементов «данных» может измениться.

Гибкий элемент массива, как предложено @O__________ в другом ответе хорошо, если struct A всегда выделено динамическое значение, и вам не нужно изменять количество указателей в создании массива.

Если вы хотите struct A быть локальной переменной (автоматическая продолжительность хранения) или вам нужно изменить размер после создания, вы можете это сделать:

 struct A 
{
    int num;
    struct B **data;
};
 

и распределять, как:

 struct A a;
a.num = getSizeFromUser();
a.data = malloc(a.num * sizeof *a.data);
 

Теперь a.data его можно использовать в качестве массива struct B указателей. Пример:

 struct B b;

a.data[0] = amp;b;                        // Point to an object with automatic storage

a.data[1] = malloc(sizeof *a.data[0]); // Point to an object with allocated storage
 

и тогда вы можете, например, сделать

 a.data[1]->SomeDataMemberOfStructB = someValue;
 

С помощью realloc вы даже можете изменить количество указателей во время выполнения программы, например, начать с 8 указателей, а затем увеличить до 16 указателей.