动态数组扩容通过分配更大内存并复制数据实现。1.分配新内存;2.复制原有数据;3.释放旧内存;4.更新指针和容量。手动实现相比realloc更灵活可控,但代码复杂易出错。扩容策略有固定大小和倍增两种,前者节省内存但可能频繁扩容,后者减少次数但可能浪费空间。内存迁移需注意重叠、数据类型、异常安全和性能问题,可使用memmove、正确sizeof、手动错误处理和dma优化。其他方法包括链表、混合结构和内存池,适用于不同场景需求。

指针实现动态数组扩容,本质上就是在内存中分配一块更大的空间,并将原有数据复制过去。
realloc

动态数组的核心在于一个指向内存块的指针和一个记录当前容量的变量。扩容时,我们需要:
下面是一个简单的 C 代码示例,展示了如何使用指针手动实现动态数组的扩容:

#include <stdio.h>
#include <stdlib.h>
#include <string.h> // for memcpy
typedef struct {
int *data;
int size;
int capacity;
} DynamicArray;
// 初始化动态数组
void initDynamicArray(DynamicArray *arr, int initialCapacity) {
arr->data = (int *)malloc(initialCapacity * sizeof(int));
arr->size = 0;
arr->capacity = initialCapacity;
}
// 扩容函数
int resizeDynamicArray(DynamicArray *arr, int newCapacity) {
if (newCapacity <= arr->capacity) {
return 0; // 不需要扩容,或者容量太小
}
int *newData = (int *)malloc(newCapacity * sizeof(int));
if (newData == NULL) {
return -1; // 内存分配失败
}
memcpy(newData, arr->data, arr->size * sizeof(int)); // 复制数据
free(arr->data); // 释放旧内存
arr->data = newData;
arr->capacity = newCapacity;
return 1; // 扩容成功
}
// 添加元素
void pushBack(DynamicArray *arr, int value) {
if (arr->size == arr->capacity) {
// 满了,扩容
if (resizeDynamicArray(arr, arr->capacity * 2) == -1) {
fprintf(stderr, "扩容失败!\n");
exit(EXIT_FAILURE);
}
}
arr->data[arr->size] = value;
arr->size++;
}
// 释放动态数组
void freeDynamicArray(DynamicArray *arr) {
free(arr->data);
arr->data = NULL;
arr->size = 0;
arr->capacity = 0;
}
int main() {
DynamicArray arr;
initDynamicArray(&arr, 2); // 初始容量为2
pushBack(&arr, 10);
pushBack(&arr, 20);
pushBack(&arr, 30); // 触发扩容
printf("数组大小: %d, 容量: %d\n", arr.size, arr.capacity);
for (int i = 0; i < arr.size; i++) {
printf("arr[%d] = %d\n", i, arr.data[i]);
}
freeDynamicArray(&arr);
return 0;
}这个例子中,
resizeDynamicArray
DynamicArray
pushBack
resizeDynamicArray
realloc
realloc
realloc
realloc
realloc

手动实现扩容的优势在于:
realloc
realloc
NULL
手动实现的劣势在于:
选择合适的扩容策略取决于应用场景。
固定大小扩容: 每次扩容增加固定数量的元素。 这种策略适合于你知道数组大小的大致范围,并且希望减少内存浪费的情况。 例如,如果你的数组最多只需要存储 100 个元素,那么每次扩容增加 10 个元素可能是一个不错的选择。 缺点是,如果数组大小增长超过预期,可能会导致频繁的扩容,降低性能。
倍增扩容: 每次扩容将容量翻倍。 这种策略适合于你不知道数组大小的范围,并且希望尽可能减少扩容次数的情况。 例如,C++ 的
std::vector
一般来说,倍增扩容 是一个更常见的选择,因为它在时间和空间之间做了一个较好的平衡。 但是,在特定场景下,固定大小扩容可能更合适。 可以根据实际情况进行权衡。
内存迁移(即复制数据到新的内存空间)可能遇到以下问题:
内存重叠: 如果源内存和目标内存有重叠,使用
memcpy
memmove
memmove
数据类型: 确保复制的数据类型大小正确。 在上面的例子中,我们使用
sizeof(int)
int
异常安全: 如果在复制过程中发生异常(例如,内存错误),可能会导致数据不一致。 应该使用异常处理机制来捕获异常,并进行相应的处理,例如回滚操作,或者释放已分配的内存。 在 C 语言中,没有异常处理机制,需要手动进行错误检查和资源释放。
性能: 大数据量的复制可能会影响性能。 可以考虑使用 DMA (Direct Memory Access) 等技术来加速数据复制。 DMA 允许硬件直接访问内存,而不需要 CPU 的参与,从而提高数据传输速度。 DMA 的使用取决于具体的硬件平台和操作系统。
realloc
除了
realloc
使用链表: 可以使用链表来实现动态数组。 链表的优点是可以动态地添加和删除元素,而不需要预先分配固定大小的内存。 缺点是,链表访问元素的效率较低,因为需要遍历链表才能找到指定位置的元素。
使用混合结构: 可以将数组和链表结合起来使用。 例如,可以使用一个数组来存储一部分元素,然后使用链表来存储超出数组容量的元素。 这种方法可以结合数组和链表的优点,提高访问效率和动态性。
使用内存池: 可以使用内存池来管理内存。 内存池预先分配一块大的内存空间,然后将这块空间分割成小的内存块。 当需要分配内存时,从内存池中分配一个小的内存块。 当需要释放内存时,将内存块返回到内存池中。 内存池可以减少内存分配和释放的开销,提高性能。
选择哪种方法取决于具体的应用场景和性能要求。 一般来说,
realloc
以上就是怎样用指针实现动态数组的扩容 realloc替代方案与内存迁移的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号