Как динамически расширить массив в C ++? {как в векторе} - PullRequest
12 голосов
/ 29 августа 2009

Допустим, у меня есть

int *p;
p = new int[5];
for(int i=0;i<5;i++)
   *(p+i)=i;

Теперь я хочу добавить 6-й элемент в массив. Как мне это сделать?

Ответы [ 5 ]

25 голосов
/ 29 августа 2009

Вы должны перераспределить массив и скопировать данные:

int *p;
p = new int[5];
for(int i=0;i<5;i++)
   *(p+i)=i;

// realloc
int* temp = new int[6];
std::copy(p, p + 5, temp); // Suggested by comments from Nick and Bojan
delete [] p;
p = temp;
8 голосов
/ 29 августа 2009

Вы не можете. Для этого вы должны использовать динамический контейнер, такой как вектор STL. Или же вы можете создать другой массив большего размера, а затем скопировать в него данные из вашего первого массива.

Причина в том, что массив представляет непрерывную область в памяти. В приведенном выше примере предположим, что p указывает на адрес 0x1000, а пять целых чисел соответствуют двадцати байтам, поэтому массив заканчивается на границе 0x1014. Компилятор может свободно размещать другие переменные в памяти, начиная с 0x1014; например, int i может занимать 0x1014..0x1018. Если вы расширите массив так, чтобы он занимал еще четыре байта, что произойдет?

3 голосов
/ 29 августа 2009

Если вы выделите начальный буфер с помощью malloc, вы можете использовать realloc для изменения размера буфера. Вы не должны использовать realloc для изменения размера new -бедного буфера.

int * array = (int*)malloc(sizeof(int) * arrayLength);
array = (int*)realloc(array, sizeof(int) * newLength);

Тем не менее, это обычный способ делать вещи. Вы должны рассмотреть возможность использования vector.

2 голосов
/ 29 августа 2009

Почему бы вам не посмотреть в источниках, как это делает vector? Вы можете увидеть реализацию этого механизма прямо в папке, в которой находятся включаемые файлы C ++!

Вот что он делает на gcc 4.3.2:

  1. Выделите новый непрерывный кусок памяти с использованием распределителя вектора (вы помните, что вектор равен vector<Type, Allocator = new_allocator>?). Распределитель по умолчанию вызывает operator new() (не просто new!) Для выделения этого чанка, позволяя себе таким образом не связываться с new[] / delete[] stuff;

  2. Скопировать содержимое существующего массива во вновь выделенный;

  3. Удалите ранее выровненный фрагмент с распределителем; по умолчанию используется operator delete().

(Обратите внимание, что если вы собираетесь написать свой собственный вектор, ваш размер должен увеличиться в «M раз», а не «на фиксированную величину». Это позволит вам получить постоянное время амортизации. Например, если при превышение предела размера, ваш вектор увеличивается в два раза, каждый элемент будет скопирован в среднем один раз.)

1 голос
/ 29 августа 2009

То же, что говорят другие, но если вы часто изменяете размер массива, одна из стратегий состоит в том, чтобы каждый раз изменять размер массива, удваивая размер. Необходимо постоянно создавать новое и разрушать старое, поэтому теория удвоения пытается смягчить эту проблему, обеспечивая достаточное пространство для будущих элементов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...