Распределение памяти только для одного элемента массива - PullRequest
0 голосов
/ 16 мая 2018

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

Как я могу сделать это в целочисленных массивах?

Ответы [ 2 ]

0 голосов
/ 16 мая 2018

Я думаю, вы говорите, что хотите «увеличивать» массив по одному элементу за раз.

realloc() - это опция в C для массива целых чисел (*).

size_t n=0;//Length of array.
int* arr=NULL;

//Some code...

//Now we want to grow our array
//This is probably in a loop or called in a function from a loop (not shown).
++n;
int* temp=realloc(arr,n*sizeof(int));
if(temp==NULL){
    free(arr);
    return 1;//Error...
}
arr=temp;

//More code....

//Now we're done with arr.
free(arr);

В первом проходе arr равен NULL, а realloc(NULL,..) просто действует как malloc().Но при последующих проходах, когда arr не равен NULL, realloc пытается увеличить массив «на месте» (если в конце имеется память).Если нет, он пытается выделить место в другом месте, а затем копирует существующие данные и освобождает старое местоположение.Если он не может перераспределить, он ничего не делает и возвращает NULL, поэтому вы несете ответственность за освобождение этого пространства (free(arr)).

Примечание: всегда выделяйте возврат realloc() для временной переменной(т.е. не первый аргумент).В противном случае, если выделение не удастся, вы вытекли из существующей памяти.

realloc - это быстрый прием для уменьшения объема выделения и копирования, необходимого для увеличения массива - альтернатива.

Если это не такдостаточно эффективной, нормальная модель заключается в том, чтобы отслеживать «емкость» и «длину» примерно так:

 const size_t chunk=10;
 size_t cap=0;
 size_t n=0;
 int* arr=NULL;

 ++n;
 if(n>cap){
     cap+=chunk;
     int* temp=realloc(arr,cap);
     if(temp==NULL){
         free(arr);
         return 1;//Error
     }
 }

 //Later...
 free(arr);

Это дает вам преимущество в том, что вы можете настраивать, сколько «лишних» накладных расходов вам нужно настроитькак часто происходит перераспределение.Другая стратегия - cap=cap*2;, хотя, очевидно, пространство имеет тенденцию к экспоненциальному росту!Можно написать книгу о стратегиях для этой классики.Часто можно выделить достаточно для наиболее реалистичных случаев одним ударом, но по-прежнему обрабатывать исключительные случаи.

У вас также есть возможность выделить обратно, чтобы восстановить свободное пространство, если вы знаете, что массив теперь является полноразмерным.

В случае, если это не очевидно, если массив перемещается, любые указатели на него или на него должны быть перенаправлены.Это аргумент только для индексации с [.].Вам нужно будет удерживать старое местоположение, пока вы не выполните перенаправление.ptr=temp+(ptr-arr) заставляет ptr указывать на новое местоположение элемента, на который указывает ptr.

Это стандартный подход, встречающийся в Java ArrayList и большинстве реализаций std::vector<>.Это инженерный компромисс.Преимущества массива (O (1) произвольного доступа по индексу) и связанного списка (O (1) роста).

Это асимптотически все еще линейно, но в практических случаях дает большую выгоду.Информатика занимается асимптотическими скоростями и проектированием с фактическими значениями в конечных реальных случаях.

(*) Копия является необработанной копией памяти.Это нормально для int, но сложные структуры struct не могут быть скопированы на сумму, равную memmove, или требуют дополнительных усилий.

0 голосов
/ 16 мая 2018

Используйте концепцию динамического выделения памяти для определения размера массива во время выполнения как:

int n;
scanf("%d",&n);
ptr = (int*) malloc(n*sizeof(int));

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

...