Как динамически выделить указатель структуры внутри структуры?

avatar
Jane Doe
9 августа 2021 в 03:44
76
2
1

В настоящее время у меня есть структура Struct1 с указателем на Struct2, который выделяется несколько раз на основе некоторых условий в коде. Я попытался выделить его test->Struct2Pair[i] = malloc(sizeof(struct Struct2)); таким образом, но, похоже, это не удалось. Есть идеи, что я делаю неправильно?

Вот упрощенная версия того, что я пытаюсь сделать.

struct Struct2 {
    int x;
    int y;
};

struct Struct1 {
    struct Struct2 *Struct2Pair;
    int val;
};

int main()
{

    struct Struct1 *test = malloc(sizeof(struct Struct1));
    for ( int i = 0; i < 5; i++ )
    {
        test->Struct2Pair[i] = malloc(sizeof(struct Struct2));
    }
    return 0;
}

Спасибо!

Источник
paddy
9 августа 2021 в 03:51
2

Struct2Pair не инициализирован — вы не можете просто начать присваивать ему значения, как если бы это был допустимый массив. По крайней мере, вам понадобится test->Struct2Pair = malloc(5 * sizeof(struct Struct2));, который выделяет память для 5 элементов типа struct Struct2. Но если вы собираетесь просто жестко запрограммировать массив, почему бы не определить его просто как struct Struct2 Struct2Pair[5]; в первую очередь?

Jane Doe
9 августа 2021 в 03:55
0

@paddy, как я уже сказал, 5 - это просто пример. Это число зависит от некоторых входных данных и некоторых вычислений. Я просто хочу знать, как malloc test->Struct2Pair каждый раз, когда выполняется какое-то условие. Это может быть 1... может быть 100. Я не знаю, как это сделать.

InQusitive
9 августа 2021 в 03:58
0

@JaneDoe: Когда вы делаете test->Struct2Pair[i], вы пытаетесь получить доступ к ячейке памяти Struct2Pair, которая пока не указывает ни на что значимое.

paddy
9 августа 2021 в 04:00
0

Если вам нужно знать, сколько элементов содержится в массиве, вам нужно где-то сохранить это значение (возможно, в дополнительной переменной в Struct1). В противном случае у вас нет возможности узнать, достаточно ли велик массив (если вы планируете изменить его размер позже с помощью realloc или чего-то еще). Я поддерживаю свой комментарий о том, как выделить массив с помощью malloc. Ты делаешь это неправильно. Единственная модификация здесь заключается в использовании переменного размера вместо жесткого кодирования 5 и сохранении значения где-нибудь.

Jane Doe
9 августа 2021 в 04:04
0

Это время выполнения и неизвестно при распределении Struct2Pair. Он продолжает выделяться один за другим, если выполняются определенные условия. Будет ли ваше решение работать в этом случае?

paddy
9 августа 2021 в 04:04
0

Да. Вы несете ответственность за отслеживание подсчета и распределения соответственно. Если вы не знаете количество элементов в начале, вы можете установить счетчик на ноль и указатель на NULL. Затем в любое время, когда вам нужно добавить элемент, увеличьте количество и вызовите realloc. Это не самое эффективное решение, но оно будет работать и будет самым простым для понимания новичком.

Jane Doe
9 августа 2021 в 04:21
0

А, имеет смысл. Спасибо @падди

Ответы (2)

avatar
TruthSeeker
9 августа 2021 в 04:17
0

Чтобы сделать Struct2Pair точкой 5 последовательных объектов памяти типа Struct2, вы должны выделить 5*sizeof(Struct2). поэтому в последней части кода вы можете получить к нему доступ как к массиву размером 5.

Вы должны выполнить null проверку возвращаемого значения malloc.

    struct Struct1 *test = malloc(sizeof(struct Struct1));

        //   |-----change is here and here--------------|
        //   v                                          v
        test->Struct2Pair = malloc(sizeof(struct Struct2) * 5);
    
    //access can be as follows for all the index from 0  to 4
    test->Struct2Pair[2].x = 10;
    test->Struct2Pair[2].y = 20;

Для лучшей визуализации обратитесь к этому и этому.

avatar
avonbied
9 августа 2021 в 03:57
-1

Ваша проблема связана с циклом for и числом доступных Struct2s в массиве test->Struct2Pair.

Вы не выделили места для test->Struct2Pair до того, как поместили в него Struct2s

test->Struct2Pair[i] = malloc(sizeof(struct Struct2));

Затем выполните цикл по большему количеству индексов, чем доступно для массива test->Struct2Pair

for ( int i = 0; i < 5; i++ )

Вы можете добавить еще одну переменную для хранения размера массива test->Struct2Pair:

int size = 5;
struct Struct1 *test = malloc(sizeof(struct Struct1));
test->Struct2Pair = malloc(size * sizeof(struct Struct2));
for ( int i = 0; i < size; i++ )
{
    test->Struct2Pair[i].x = 0;
    test->Struct2Pair[i].y = 0;
}

Ссылка на malloc: https://en.cppreference.com/w/c/memory/malloc

alex01011
9 августа 2021 в 04:02
0

Это неправильно. Struct2Pair не инициализирован. Доступ к нему будет UB.

avonbied
9 августа 2021 в 04:11
0

Отвечайте, приобретайте и адаптируйтесь. Я посмотрел на вопрос, а затем скорректировал ответ. Просто открыл оболочку и протестировал скорректированный код, и он компилируется и запускается.

avonbied
9 августа 2021 в 04:36
0

Нет проблем @JaneDoe. Я заметил, что realloc был упомянут без какой-либо ссылки. Если вы выберете этот маршрут, вот общий пример его использования: en.cppreference.com/w/c/memory/realloc

avonbied
9 августа 2021 в 04:39
0

А вот еще один справочник по управлению динамической памятью: eskimo.com/~scs/cclass/notes/sx11.html

Jane Doe
9 августа 2021 в 05:43
0

В итоге я пошел по пути realloc. Сначала сделал test->Struct2Pair = calloc(0, sizeof(struct Struct2));, а затем test->Struct2Pair = realloc(test->Struct2Pair, (i+1) * sizeof(struct Struct2)); Это, похоже, решило мои проблемы!