#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 указателей.