核心定位
realloc 是C语言中的「内存变形金刚」,它能动态调整已分配内存的大小,实现内存的智能扩容或缩容。就像橡皮筋一样,根据需要拉长或缩短,同时尽可能保留原有数据!
函数原型与参数
void *realloc(void *ptr, size_t new_size);
- 入口参数:
- ptr:指向已分配内存的指针(malloc/calloc/realloc分配的指针)
- 特殊用法:若 ptr 为 NULL,则等价于 malloc(new_size)
- new_size:新内存块的总字节数(可大于或小于原大小)
- 返回参数:
- 成功:返回新内存指针(可能与原指针不同)
- 失败:返回 NULL,原内存保持不变
基础用法四步曲
// 初始分配(示例:创建含3个int的数组)
int *arr = (int*)malloc(3 * sizeof(int));
arr[0]=1, arr[1]=2, arr[2]=3;
// 1 尝试扩容到5个元素
int *new_arr = (int*)realloc(arr, 5 * sizeof(int));
// 2 检查是否成功
if (new_arr == NULL) {
free(arr); // 扩容失败,释放原内存
perror("内存扩容失败!");
exit(EXIT_FAILURE);
}
// 3 更新指针(原内存可能已被释放!)
arr = new_arr;
// 4 使用新内存
arr[3] = 4;
arr[4] = 5;
// 最终释放
free(arr);
arr = NULL;
三大核心特性
特性1智能扩容策略
- 原地扩容:若后续内存空间足够,直接扩展(地址不变)
- 异地迁移:若空间不足,自动寻找新区域,复制旧数据并释放原内存
int *p1 = malloc(100);
printf("原地址: %p\n", p1);
int *p2 = realloc(p1, 200);
printf("新地址: %p\n", p2); // 可能相同或不同
特性2多功能模式切换
原指针 | new_size | 等效操作 |
NULL | >0 | malloc(new_size) |
非NULL | 0 | free(ptr) |
非NULL | <原大小 | 缩小内存保留数据 |
特性3数据完整性保障
- 异地迁移时会自动复制有效数据部分(不会复制超出新大小的旧数据)
char *str = malloc(5);
strcpy(str, "Hello");
// 缩小到3字节(保留'H','e','l')
str = realloc(str, 3);
printf("%.3s", str); // 输出:Hel
四大致命陷阱
陷阱 | 后果 | 防御方案 |
直接覆盖原指针 | 内存泄漏/崩溃 | 先用临时指针接收返回值 |
不检查返回值 | 丢失原内存 | 严格判断是否为NULL后再处理 |
计算新大小错误 | 数据截断/溢出 | 使用 sizeof 配合变量计算 |
频繁小幅度扩容 | 性能下降/内存碎片 | 采用指数级扩容策略 |
实战代码:动态数组自动扩容
#include
#include
typedef struct {
int *data; // 数据存储
size_t size; // 当前元素数
size_t capacity;// 总容量
} DynamicArray;
// 初始化动态数组(容量=2)
void init_array(DynamicArray *arr) {
arr->data = (int*)malloc(2 * sizeof(int));
arr->size = 0;
arr->capacity = 2;
}
// 添加元素(自动扩容)
void push_back(DynamicArray *arr, int value) {
if (arr->size >= arr->capacity) {
// 容量翻倍(指数增长策略)
size_t new_cap = arr->capacity * 2;
int *temp = (int*)realloc(arr->data, new_cap * sizeof(int));
if (!temp) {
free(arr->data);
fprintf(stderr, "内存扩容失败!");
exit(EXIT_FAILURE);
}
arr->data = temp;
arr->capacity = new_cap;
printf("扩容至 %zu 元素\n", new_cap);
}
arr->data[arr->size++] = value;
}
int main() {
DynamicArray arr;
init_array(&arr);
// 添加10个元素(触发多次扩容)
for (int i=0; i<10; i++) {
push_back(&arr, i*10);
}
// 输出结果
for (int i=0; i<arr.size; i++) {
printf("%d ", arr.data[i]);
}
free(arr.data);
return 0;
}
输出示例:
扩容至 4 元素
扩容至 8 元素
扩容至 16 元素
0 10 20 30 40 50 60 70 80 90
黄金法则
- 先用临时变量:new_ptr = realloc(old_ptr, size)
- 指数级扩容:每次扩容为原容量的1.5-2倍,减少调用次数
- 及时更新元数据:容量变化后同步记录数组大小等信息
- 缩容需谨慎:频繁缩小内存可能适得其反,建议在空闲时操作
脑洞应用:内存画布动态调整
// 创建可变大小的像素画布
unsigned char *canvas = malloc(100*100*3); // 初始100x100 RGB图像
// 用户拖拽调整画布大小到200x200
size_t new_size = 200*200*3;
unsigned char *new_canvas = realloc(canvas, new_size);
if (new_canvas) {
canvas = new_canvas;
// 新区域自动保留原图像数据,超出部分为随机值
// 可手动初始化新增区域为背景色...
}
掌握 realloc 如同获得内存空间的「时空门」,既能保留历史数据,又能灵活适应未来需求。记住:先试新门,再拆旧门(先用临时指针接收返回值),方能安全穿越内存世界!