Как динамически расширять массив на С++? {как в векторе}
Скажем, у меня есть
int *p;
p = new int[5];
for(int i=0;i<5;i++)
*(p+i)=i;
Теперь я хочу добавить в массив 6-й элемент. Как это сделать?
Ответы
Ответ 1
Вам необходимо перераспределить массив и скопировать данные:
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;
Ответ 2
Вы не можете. Для этого вы должны использовать динамический контейнер, такой как вектор STL. Или вы можете сделать другой массив, который больше, а затем скопировать данные из вашего первого массива в него.
Причина в том, что массив представляет собой смежную область в памяти. Для вашего примера выше, скажем, что p указывает на адрес 0x1000, а пять ints соответствуют 20 байтам, поэтому массив заканчивается на границе 0x1014. Компилятор может размещать другие переменные в памяти, начиная с 0x1014; например, int i
может занимать 0x1014..0x1018. Если вы затем расширили массив так, чтобы он занял еще четыре байта, что произойдет?
Ответ 3
Если вы выделяете исходный буфер с помощью malloc
, вы можете использовать realloc
для изменения размера буфера. Вы не должны использовать realloc
для изменения размера буфера new
-ed.
int * array = (int*)malloc(sizeof(int) * arrayLength);
array = (int*)realloc(array, sizeof(int) * newLength);
Однако это C-ish способ делать что-то. Вы должны использовать vector
.
Ответ 4
Почему вы не смотрите в источники, как это делает vector
? Вы можете увидеть реализацию этого механизма прямо в папке, где хранятся ваши файлы на С++!
Вот что он делает на gcc 4.3.2:
-
Выделите новый непрерывный кусок памяти с помощью векторного распределителя (вы помните, что этот вектор равен vector<Type, Allocator = new_allocator>
?). Распределитель по умолчанию вызывает operator new()
(а не только new
!), Чтобы выделить этот кусок, позволяя себе не путаться с new[]
/delete[]
stuff;
-
Скопировать содержимое существующего массива в только что выделенный;
-
Утилизируйте ранее выровненный блок с распределителем; по умолчанию используется operator delete()
.
(Обратите внимание, что если вы собираетесь писать свой собственный вектор, ваш размер должен увеличиваться "М раз", а не "по фиксированной сумме". Это позволит вам получить амортизированное постоянное время. Например, если каждый отступ от ограничения размера, ваш вектор растет дважды, каждый элемент будет скопирован в среднем один раз.)
Ответ 5
То же, что говорят другие, но если вы часто изменяете размер массива, одной стратегией является изменение размера массива каждый раз за счет удвоения размера. Там расходы на постоянное создание новых и уничтожение старых, поэтому теория удвоения пытается смягчить эту проблему, гарантируя, что есть достаточно места для будущих элементов.