Как динамически объявить массив, присутствующий внутри структуры, используя malloc - PullRequest
2 голосов
/ 31 января 2012

В настоящий момент в моей программе есть следующий код:

struct mystruct
{
    int x;
    struct y *list[10];
}

mystruct *h1=(mystruct *)malloc(sizeof(mystruct));

Я хочу объявить массив list динамически (используя malloc()), когда я объявляю структуру.Может ли кто-нибудь сказать мне, как это сделать?

Ответы [ 2 ]

1 голос
/ 01 февраля 2012

Если вы собираетесь портировать только на машины (компиляторы), которые поддерживают C99, то вы можете использовать «члены гибкого массива», которые являются переносимой версией «struct hack».

§6.7.2.1 Структура и объединение спецификаторов

¶16 В особом случае последний элемент структуры с более чем одним именованным элементом может иметь неполный тип массива; это называется гибкий член массива . С двумя исключения, гибкий член массива игнорируется. Во-первых, размер структуры должен быть равно смещению последнего элемента в остальном идентичной структуры, которая заменяет элемент гибкого массива с массивом неопределенной длины. 106) Секунда, когда . (или ->) Оператор имеет левый операнд, который является (указатель) на структуру с членом гибкого массива и правильный операнд называет этот член, он ведет себя так, как если бы этот член был заменен с самым длинным массивом (с тем же типом элемента), который не сделал бы структуру больше, чем объект, к которому осуществляется доступ; смещение массива должно оставаться смещение гибкий элемент массива, даже если это будет отличаться от элемента массива замены. Если это массив не имеет элементов, он ведет себя так, как если бы он имел один элемент, но поведение не определено, если делается какая-либо попытка получить доступ к этому элементу или создать указатель один раз это.

EX17 ПРИМЕР Предполагая, что все элементы массива выровнены одинаково после объявлений:

struct s { int n; double d[]; };
struct ss { int n; double d[1]; };

Три выражения:

sizeof (struct s)
offsetof(struct s, d)
offsetof(struct ss, d)

имеют одинаковое значение. Структура struct s имеет гибкий элемент массива d.

106) Длина не указана, чтобы учесть тот факт, что реализации могут давать разные элементы массива выравнивания в соответствии с их длиной.


В контексте это означает, что вы можете написать:

typedef struct mystruct
{
    int x;
    struct y *list[];
} mystruct;  // Note that this is necessary; C++ automatically recognizes mystruct; C does not.

Чтобы выделить место, вы можете использовать:

mystruct *h1 = (mystruct *)malloc(sizeof(mystruct) + 10 * sizeof(struct y *));

Это выделяет mystruct с достаточным пространством для 10 указателей в массиве. Позже вы можете изменить размер памяти с помощью:

mystruct *new_h1 = (mystruct *)realloc(h1, sizeof(mystruct) + 20 * sizeof(struct y *));
if (new_h1 == 0)
    ...handle out of memory error, but note that h1 is still valid...
h1 = new_h1; // Safe

(Обратите внимание, что я тщательно не назначаю h1 при перераспределении; это приведет к утечке памяти в случае сбоя выделения памяти.)

Вы можете ссылаться на них, как если бы массив был там:

h1->list[0] = ...;

Обратите внимание, что вы не можете иметь массив mystruct, но вы можете иметь массив указателей на mystruct. Вы также должны следить за размером массива; вы обычно делаете что-то вроде того, чтобы один из фиксированных членов записал выделенный размер.

1 голос
/ 31 января 2012

Вы должны сделать это явно.Обычно я делаю это с помощью функции-обертки, подобной этой.

Редактировать: Теперь есть полный рабочий пример внизу.

struct mystruct *mystruct_init()
{
    struct mystruct *mystruct = calloc(1, sizeof(*mystruct));

    // loop through and allocate memory for each element in list
    for (int i = 0; i < 10; i++) {
        mystruct->list[i] = calloc(1, sizeof(*(mystruct->list[i])));
    }

    return mystruct;
}

Таким образом, вы просто вызываетеэто в вашем коде:

struct mystruct *h1 = mystruct_init();

Вы также захотите написать соответствующую mystruct_free() функцию.

Вот рабочий пример (для меня):

#include <stdlib.h>
#include <stdio.h>

struct y {
    int a;
};

struct mystruct {
    int x;
    struct y **list;
    int list_length;
};

struct mystruct *mystruct_init()
{
    struct mystruct *mystruct = calloc(1, sizeof(*mystruct));

    // loop through and allocate memory for each element in list
    mystruct->list_length = 10;
    mystruct->list = calloc(1, sizeof(struct y *) * mystruct->list_length);
    for (int i = 0; i < mystruct->list_length; i++) {
        mystruct->list[i] = calloc(1, sizeof(struct y));
    }

    return mystruct;
}

void mystruct_free(struct mystruct *mystruct)
{
    for (int i = 0; i < mystruct->list_length; i++) {
        free(mystruct->list[i]);
    }

    free(mystruct->list);
    free(mystruct);
}

int main(int argc, char *argv[])
{
    struct mystruct *h1 = mystruct_init();
    h1->x = 6;
    printf("%d\n", h1->x);
    mystruct_free(h1);
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...