跳转到内容

C 语言 realloc 函数

来自代码酷

模板:Note

realloc函数概述[编辑 | 编辑源代码]

realloc(全称re-allocation)是C标准库(<stdlib.h>)中用于动态调整已分配内存块大小的函数。它解决了以下核心问题:

  • 当程序运行时发现原先分配的内存不足时,无需手动创建新内存块并复制数据
  • 当分配的内存过大时,可以缩小内存块以减少内存占用

函数原型[编辑 | 编辑源代码]

void *realloc(void *ptr, size_t size);
  • ptr:指向先前由malloc/calloc/realloc分配的内存块的指针
  • size:内存块的新大小(字节数)
  • 返回值:指向重新分配内存块的指针(可能与ptr不同)

工作原理[编辑 | 编辑源代码]

graph TD A[原内存指针ptr] --> B{size变化?} B -->|增大| C[尝试原地扩展] C --> D{连续空间足够?} D -->|是| E[直接扩展] D -->|否| F[分配新内存并迁移数据] B -->|缩小| G[可能释放尾部内存] B -->|size=0| H[等价于free]

关键行为说明: 1. 原地扩展:当原内存块后续的地址空间未被占用时,直接扩大分配 2. 迁移扩展:当无法原地扩展时,自动完成:

  * 分配新内存块
  * 复制原数据(仅复制到min(旧大小,新大小))
  * 释放原内存块

3. 缩小内存:可能释放多余内存,但实现依赖具体编译器

使用示例[编辑 | 编辑源代码]

基础示例[编辑 | 编辑源代码]

#include <stdio.h>
#include <stdlib.h>

int main() {
    // 初始分配10个int的空间
    int *arr = (int*)malloc(10 * sizeof(int));
    
    // 检查分配是否成功
    if(arr == NULL) {
        printf("内存分配失败!\n");
        return 1;
    }

    // 使用内存(示例填充数据)
    for(int i=0; i<10; i++) arr[i] = i;

    // 需要更多空间,扩展到20个int
    int *new_arr = (int*)realloc(arr, 20 * sizeof(int));
    
    if(new_arr == NULL) {
        printf("内存重新分配失败!\n");
        free(arr);  // 原始指针仍需释放
        return 1;
    }
    
    arr = new_arr;  // 更新指针

    // 使用新增的空间
    for(int i=10; i<20; i++) arr[i] = i;

    // 打印结果(部分示例)
    printf("扩展后数组[15]: %d\n", arr[15]);

    free(arr);  // 最终释放
    return 0;
}

输出示例

扩展后数组[15]: 15

错误处理模式[编辑 | 编辑源代码]

正确使用realloc应遵循以下模式:

void *tmp = realloc(ptr, new_size);
if (tmp == NULL) {
    // 处理错误,原ptr仍然有效
    // 可能需要执行清理操作
} else {
    ptr = tmp;  // 只有成功时才覆盖原指针
}

进阶注意事项[编辑 | 编辑源代码]

性能考量[编辑 | 编辑源代码]

realloc可能触发内存复制操作,时间复杂度为O(n)。对于大型内存块:

  • 频繁调整大小会导致性能下降
  • 推荐策略:采用指数级增长(如每次扩大为原大小的1.5-2倍)

数学表达式: new_size=old_size×α(α[1.5,2.0])

特殊边界情况[编辑 | 编辑源代码]

情况 行为 等效操作
ptr为NULL 等同于malloc(size) malloc(size)
size为0 释放内存块 free(ptr)
ptr未指向动态内存 未定义行为 -

实际应用案例[编辑 | 编辑源代码]

动态数组实现[编辑 | 编辑源代码]

以下展示如何用realloc实现动态数组的自动扩容:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int *data;
    size_t size;
    size_t capacity;
} DynamicArray;

void push_back(DynamicArray *da, int value) {
    if (da->size >= da->capacity) {
        // 容量不足时扩容(初始容量为1的情况)
        size_t new_capacity = da->capacity == 0 ? 1 : da->capacity * 2;
        int *new_data = realloc(da->data, new_capacity * sizeof(int));
        
        if (!new_data) {
            printf("扩容失败!\n");
            return;
        }
        
        da->data = new_data;
        da->capacity = new_capacity;
    }
    
    da->data[da->size++] = value;
}

内存池优化[编辑 | 编辑源代码]

在游戏开发等性能敏感场景中,可采用「预分配+realloc」策略: 1. 初始化时分配预估内存 2. 运行时根据实际需求精细调整 3. 避免频繁调用malloc/free

常见问题[编辑 | 编辑源代码]

页面模块:Message box/ambox.css没有内容。

ptr = realloc(ptr, new_size);  // 若失败会导致内存泄漏

页面模块:Message box/ambox.css没有内容。

realloc(ptr, new_size);  // 未处理可能失败的情况

最佳实践总结[编辑 | 编辑源代码]

  • 总是检查返回值
  • 使用临时指针接收结果
  • 考虑内存对齐的影响(某些系统对realloc有特殊对齐要求)
  • 对于多线程环境,需要同步机制保护realloc操作

扩展阅读[编辑 | 编辑源代码]

  • 内存碎片化与realloc的关系
  • 对比C++的vector.resize()实现
  • 各标准库实现差异(glibc vs musl等)