今天在练习动态数组的增删差改,看过视频课程觉得还算简单,但实际写代码过程中发现了各种各样的问题,错误最多出现在realloc函数的使用,但在不断的出错改正过程中,也提升了对realloc函数的理解。于是重新梳理了realloc函数的定义和使用方式。
🧱 一、realloc 函数原型
void* realloc(void* ptr, size_t new_size);
ptr:之前malloc、calloc或realloc返回的指针(可以是NULL)new_size:新的总大小(以字节为单位)- 返回值:成功返回新地址,失败返回
NULL
🔥 核心:
realloc是“重新分配”,不是“增加”!
⚠️ 二、realloc 的 7 大注意事项(必看!)
❌ 注意事项 1:不能假设 realloc 返回原地
// ❌ 错误!
realloc(ptr, new_size);
// ptr 可能已失效!
// ✅ 正确:用临时指针接收
void* temp = realloc(ptr, new_size);
if (temp == NULL) {
// 处理失败,ptr 仍有效
return;
}
ptr = temp; // 成功后才更新
🔥 为什么?
realloc可能无法在原地扩展,会分配新内存并复制数据,返回新地址。
❌ 注意事项 2:realloc 失败时返回 NULL,但原内存仍有效
// ❌ 危险!
ptr = realloc(ptr, new_size);
if (ptr == NULL) {
// 此时 ptr 已被覆盖为 NULL,原内存丢失!→ 内存泄漏!
}
// ✅ 安全做法
void* temp = realloc(ptr, new_size);
if (temp == NULL) {
// 处理错误,但 ptr 仍指向原内存,可继续使用或释放
perror("realloc failed");
return ptr; // 或返回错误
}
ptr = temp; // 仅在成功时更新
🔥 黄金法则:永远用临时指针接收
realloc结果!
❌ 注意事项 3:不要对栈内存或未动态分配的内存使用 realloc
int arr[10];
realloc(arr, 20 * sizeof(int)); // ❌ 未定义行为!崩溃!
int* ptr = malloc(10 * sizeof(int));
free(ptr);
realloc(ptr, 20 * sizeof(int)); // ❌ 已释放的内存,未定义行为!
🔥
realloc只能用于malloc/calloc/realloc返回的指针。
❌ 注意事项 4:new_size 是“总大小”,不是“增加的大小”
// ❌ 错误理解:以为是“增加一个 int”
realloc(arr, sizeof(int));
// ✅ 正确:new_size 是总字节数
int new_length = old_length + 1;
void* temp = realloc(arr, new_length * sizeof(int));
❌ 注意事项 5:realloc 可能“原地扩展”
如果当前内存块后面有足够空闲空间,realloc 可能直接扩展它,不移动数据,返回原地址。
ptr = malloc(100);
ptr2 = realloc(ptr, 200); // 可能 ptr2 == ptr
🔥 这是
realloc的优化机制,返回相同地址不等于失败!
❌ 注意事项 6:realloc(ptr, 0) 的行为是实现定义的
realloc(ptr, 0); // 可能等价于 free(ptr),也可能返回特殊指针
🔥 不要依赖
realloc(ptr, 0),想释放内存就用free(ptr)。
❌ 注意事项 7:realloc(NULL, size) 等价于 malloc(size)
int* arr = realloc(NULL, 10 * sizeof(int)); // 等价于 malloc(10 * sizeof(int))
🔥 这是一个有用的技巧,可以统一内存分配逻辑。
🔄 三、realloc 的底层行为(图解)
假设内存布局如下:
[ 已用 ][ 空闲 ][ 其他 ]
- 如果
空闲足够:realloc直接扩展,不复制数据 - 如果
空闲不够:realloc分配新块,复制数据,释放旧块
👉 所以 realloc 可能快(原地扩展),也可能慢(搬家复制)
✅ 四、安全使用 realloc 的模板(收藏!)
int* safe_realloc(int* ptr, int old_size, int new_size) {
void* temp = realloc(ptr, new_size * sizeof(int));
if (temp == NULL) {
perror("realloc failed");
// 可以选择:返回原指针,或报错退出
return ptr; // 或返回 NULL 并处理
}
return (int*)temp; // 成功,返回新指针
}
// 使用:
arr = safe_realloc(arr, old_length, new_length);
🎯 五、性能优化:为什么用“2 倍扩容”?
| 策略 | 平均插入时间 | 总时间 |
|---|---|---|
| 每次 +1 | O(n) | O(n²) |
| 2 倍扩容 | O(1) 摊销 | O(n) |
🔥 摊销分析:虽然某次
realloc很慢,但平均下来每次插入只花常数时间。
🧩 六、常见错误代码对比
| 错误写法 | 正确写法 |
|---|---|
ptr = realloc(ptr, size); | temp = realloc(ptr, size); if (temp) ptr = temp; |
realloc(ptr, size); | ptr = realloc(ptr, size);(且检查 NULL) |
realloc(ptr, sizeof(int)) | realloc(ptr, new_count * sizeof(int)) |
✅ 七、总结:realloc 使用口诀
🔥 “一临二查三更新,大小总值莫弄混;
NULL 不放原内存,倍增扩容最划算。”
| 口诀 | 解释 |
|---|---|
| 一临 | 用临时指针接收 |
| 二查 | 检查临时指针是否为 NULL |
| 三更新 | 成功后再更新原指针 |
| 大小总值 | new_size 是总大小,不是增量 |
| NULL 不放 | realloc 失败时原内存仍有效 |
| 倍增扩容 | 用 2 倍策略摊销性能 |
408

被折叠的 条评论
为什么被折叠?



