Перераспределить массив структур

#c #arrays #struct #realloc

#c #массивы #структура #перераспределить

Вопрос:

Я пытаюсь динамически перераспределить память для массива структур (на самом деле это массив, каждый из 2 структур, но 1 включен здесь для простоты), который считывается из / в файл или вводится пользователем.

 typedef Struct
{
    char surname[21];
    char firstname[21];
    char username[21];
...
} User;
  

…в main():

 int size = 0; /* stores no. of structs */
User* user_array = (User *) calloc(1, sizeof(User));
if(user_array == NULL)
{
    printf("Cannot allocate initial memory for datan");
    exit(1);
}
else
    size  ;
  

Затем я пытаюсь использовать вызов функции для увеличения массива, когда это необходимо:

 int growArray(User user_array*, int size)
{
    User *temp;
    size  ;
    temp = (User *) realloc(user_array, (size * sizeof(User));
    if(temp == NULL)
    {
        printf("Cannot allocate more memory.n");
        exit(1);
    }
    else
        user_array = temp;
    return size;
}
  

К сожалению, перераспределение никогда не работает. Размер обеих структур составляет всего около 200 байт на экземпляр, и установка начального размера, скажем, 10, будет работать нормально, поэтому, должно быть, что-то не так с тем, как я пытаюсь использовать realloc.

Система — Win 7 64, на Core i5 с 4 ГБ, работает под управлением Quincy (графический интерфейс MinGW).

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

1. int growArray(User user_array, int size) ? Вам не хватает * ?

2. опубликуйте реальный код — он не будет компилироваться

3. @KennyTM Я думаю, что ему не хватает двух из них.

4. Если вы заставите это работать, вы можете упростить код, также выполнив первоначальное выделение с помощью growArray. Также имейте в виду, что ваш первоначальный calloc() инициализирует первую запись, в то время как последующий realloc () оставит расширенную область неинициализированной. Как отмечает cnicutar, «размер » не будет виден вызывающей стороне.

5. дантье — на данный момент я использую size для возвращаемого значения — извините, что не учитываю это

Ответ №1:

realloc изменяет размер памяти, на которую указывает user_array , на указанный размер, это не увеличивает его на размер. Видя, как вызывается ваша функция growArray , я бы предположил, что вы хотите, чтобы она увеличила размер массива на size , и в этом случае вам нужно:

 int growArray(User **user_array, int currentSize, int numNewElems)
{
    const int totalSize = currentSize   numNewElems;
    User *temp = (User*)realloc(*user_array, (totalSize * sizeof(User)));

    if (temp == NULL)
    {
        printf("Cannot allocate more memory.n");
        return 0;
    }
    else
    {
        *user_array = temp;
    }

    return totalSize;
}
  

Обратите внимание, что это growArray принимает адрес user_array , причина этого в том, что realloc это может привести к перемещению памяти, если не удастся расширить существующий блок до требуемого размера.

Чтобы использовать его:

 int size = 0;
User* user_array = (User *) calloc(1, sizeof(User));
if(user_array == NULL)
{
    printf("Cannot allocate initial memory for datan");
    exit(1);
}

/* add 10 new elements to the array */
size = growArray(amp;user_array, size, 10);
  

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

1. Размер равен количеству структур в массиве (до его увеличения), когда он передается в growArray. Размер в growArray увеличит это значение до нового числа (предполагается, что оно будет увеличиваться на 1 за раз — из-за неизвестного количества записей в файле или путем добавления пользователем), поэтому я считаю, что размер * sizeof (User) является правильным для этого подхода. Я заметил, что вы использовали оператор двойного косвенного обращения, как это сделал @cnicutar, я все еще пытаюсь разобраться в том, что там происходит. Должно быть, в этом я ошибаюсь… если я не сделаю это таким образом, я все равно буду использовать старый начальный адрес user_array?

2. Да, это может быть вашей проблемой. realloc возможно, не удастся расширить существующий user_array блок памяти указателей, чтобы он был достаточно большим для нового размера. Если это происходит, он выделяет новый блок памяти где-то в другом месте и копирует все с user_array начала. Возвращаемое значение — это новая ячейка памяти. Использование указателя на указатель позволяет growArray обновить значение user_array вызывающего объекта, поскольку его предыдущее значение теперь недействительно.

Ответ №2:

Вы меняете значение user_array локально. Значение теряется при возврате функции. Вместо этого передайте указатель на указатель user_array.

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

1. Извините, я забыл добавить * в свой приведенный выше код … теперь это исправлено.

2. Спасибо — это была проблема. Я не понимал, пока другие постеры не были более конкретными о том, как это сделать.