如何在C ++中动态扩展数组?{类似于vector}

19

假设我有

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

现在我想要向数组中添加第六个元素。我该怎么做?


1
如果您在编辑器中缩进四个空格,您的代码将看起来像代码。 - Jesse Beder
3
如果你需要这种功能,你需要使用std::vector。如果你不使用std::vector,那么你应该对C++有足够的了解(因为你问了这个问题,可能还不够),并且你应该有一个非常好的理由。根据这个理由,答案可能会有所不同。 - sbi
5个回答

34

你需要重新分配数组并复制数据:

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
这对于“int”类型来说是可以的,但对于用户定义的类型,“memcpy/delete []”方法可能会导致问题。 - Nick Dandoulakis
2
你可以使用std::copy代替memcpy - 它适用于POD以及具有用户定义赋值运算符的对象,并且很可能对于整数类型进行了优化,但是优化是实现质量问题。 - Bojan Resnik
1
谢谢大家,我改用了std::copy。 - Kim Gräsman
4
这个问题得以解决,多亏了一个匿名用户的被拒绝的编辑。感谢您发现了这个错误!这个问题是在我从memcpy更改为std::copy时,没有检查参数顺序而悄悄地出现的。 http://stackoverflow.com/review/suggested-edits/1775715 <-- 这个应该被接受! - Kim Gräsman
请问您能否解释一下与memcpy相关的问题。它只是针对长度和内存访问进行安全检查,还是存在实际的底层问题? - Jeremy Trifilo
2
@JeremyTrifilo 这个问题是针对自定义类型提出的。如果你有一个带有用户定义赋值运算符(例如,它们需要释放/分配私有内存)的对象数组,memcpy 将会失效,因为它仅仅复制字节而不是调用每个元素的赋值函数。 - Kim Gräsman

11

无法这样做。您必须使用动态容器,例如STL向量(vector),才能实现此功能。或者您可以创建另一个较大的数组,然后将第一个数组中的数据复制到其中。

原因在于,数组表示内存中连续的区域。对于上面的示例,假设p指向地址0x1000,五个整数对应二十个字节,因此数组结束于0x1014的边界处。编译器可以自由地将其他变量放置在从0x1014开始的内存中;例如,int i可能占用0x1014..0x1018。如果您将数组扩展到占用四个以上的字节,会发生什么呢?


3

如果你使用malloc来分配初始缓冲区,那么可以使用realloc来调整缓冲区的大小。但是不应该使用realloc来调整一个new分配的缓冲区的大小。

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

然而,这是一种类似于C语言的做法。你应该考虑使用 vector


2
仅适用于纯旧数据类型。 - peterchen
你可能应该补充一下,如果想要模拟vector的话,它所做的是分配一个新的更大的数组,并将元素复制到其中。OP知道vector,因此可能有不使用它的原因(也许是作业)。 - jalf

2

和其他人说的一样,但如果您经常调整数组大小,则一种策略是每次将数组大小加倍。不断创建新的并销毁旧的会产生成本,因此加倍理论试图通过确保未来元素有足够的空间来缓解这个问题。


1
那基本上就是重新实现向量,不是吗? - Naveen
1
如果你不想使用向量,这可能是你要做的事情。但是,如果你实现了向量,你就不会问这个问题了。 - Glenn

2
为什么不看看源代码,了解一下vector是如何实现的呢?你可以在C++头文件所在的文件夹中直接查看这个机制的实现!
以下是gcc 4.3.2上的实现方式:
1. 使用vector的allocator(你还记得vector是“vector”吗?)来分配一个新的连续内存块。默认的allocator调用“operator new()”(而不是“new”!)来分配这个块,从而避免了与“new[]”/“delete[]”相关的问题;
2. 将现有数组的内容复制到新分配的数组中;
3. 使用allocator释放先前对齐的内存块;默认的allocator使用“operator delete()”。
(请注意,如果您要编写自己的vector,您的大小应该增加“M次”,而不是“固定数量”。这将使您实现摊销常数时间。例如,如果每次超过大小限制时,您的vector都会增加两倍,则平均每个元素将被复制一次。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接