一、核心作用
普通数组大小必须编译期确定;
动态内存可以程序运行时申请内存,堆(heap)上分配,用完手动释放。
bash
头文件:<stdlib.h>
二、4 个核心函数
1. malloc
• 功能:分配size 字节连续内存,不初始化,内容随机垃圾值
• 返回:成功→内存首地址;失败→NULL
bash// 分配能存5个int的空间 int *p = (int *)malloc(5 * sizeof(int)); if(p == NULL) { // 必须判空! perror("malloc fail"); return -1; }
2. calloc
void *calloc(size_t num, size_t size);• 功能:分配num个、每个size字节的内存,自动初始化为 0
bashint *p = (int *)calloc(5, sizeof(int));
3. realloc 重新调整大小
void *realloc(void *ptr, size_t new_size);• 扩容 / 缩容已有动态内存
• 注意:
不要直接 p = realloc(p, ...),失败会返回 NULL,丢失原地址造成内存泄漏
扩容不一定原地,可能拷贝数据到新地址
bashint *tmp = realloc(p, 10 * sizeof(int)); if(tmp != NULL){ p = tmp; }
4. free 释放内存
bashvoid free(void *ptr);• 归还堆内存,必须配对使用
• 规则:
- free 只能释放 malloc/calloc/realloc 得到的指针
- 不能重复 free、不能 free 栈上变量
- free 之后指针变成野指针,建议手动置 NULL
bashfree(p); p = NULL;
三、完整示例
bash
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int n = 5;
// 堆区申请内存,不初始化
int *arr = (int *)malloc(n * sizeof(int));
// ⚠重点:必须判断分配是否成功
if(arr == NULL){
printf("malloc fault\n");
return 1; // 异常退出
}
for(int i = 0; i < n; i++){
arr[i] = i + 1;
}
// ⚠易错:realloc先用临时指针接收,失败不会覆盖原地址
int *tmp = realloc(arr, 10 * sizeof(int));
if(tmp == NULL)
{
printf("realloc fault\n");
free(arr);
arr = NULL;
return 1;
}
arr = tmp;
// ⚠扩容新增区域数据随机,如需使用要手动赋值
free(arr); // ⚠堆内存使用完必须释放
arr = NULL; // ⚠防止野指针
return 0; // 正常退出
}
四、常见坑
忘记 free → 内存泄漏
free 之后继续使用指针 → 野指针访问(程序崩溃)
重复 free 同一地址
realloc 直接赋值原指针,分配失败丢失内存
不判断 malloc 返回 NULL,内存不足直接崩溃
sizeof( )写错,大小分配不足造成越界
五、栈内存 vs 堆内存
| 区域 | 分配方式 | 释放 | 生命周期 |
|---|---|---|---|
| 栈 (stack) | 局部数组、局部变量 | 函数结束自动回收 | 函数内有效 |
| 堆 (heap) | malloc/calloc | 手动 free | 直到 free 或程序结束 |