C语言realloc函数详解:内存空间的“弹性伸缩术”

C语言realloc函数详解:内存空间的“弹性伸缩术”

编码文章call10242025-03-24 13:55:4710A+A-

核心定位

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

黄金法则

  1. 先用临时变量:new_ptr = realloc(old_ptr, size)
  2. 指数级扩容:每次扩容为原容量的1.5-2倍,减少调用次数
  3. 及时更新元数据:容量变化后同步记录数组大小等信息
  4. 缩容需谨慎:频繁缩小内存可能适得其反,建议在空闲时操作

脑洞应用:内存画布动态调整

// 创建可变大小的像素画布
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 如同获得内存空间的「时空门」,既能保留历史数据,又能灵活适应未来需求。记住:先试新门,再拆旧门(先用临时指针接收返回值),方能安全穿越内存世界!

点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4