我想你是说你想一次“增长”一个数组。
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 或采取进一步的努力。