malloc
函数原型:
c
void* malloc(size_t size);
- 功能:在堆上分配size字节内存块,返回void*无类型指针
- 参数:size 需要分配的字节数,常用sizeof(类型)计算
- 返回值
○ 成功:返回内存首地址,需要强制类型转换后使用
○ 失败:返回NULL,必须判空 - 头文件:#include <stdlib.h>
- 要点
○ 分配的内存不会自动清零,里面是随机脏数据
○ 内存默认对齐(Windows 下一般 8 字节对齐)
○ 实际占用内存 ≥ 你申请的大小,多出部分是堆管理器的元数据(堆块头)
○ malloc(0):返回一个合法指针,但不能解引用读写
○ size_t:无符号整型别名
calloc
函数原型:
c
void* calloc(size_t num, size_t size);
- 功能:分配num个元素,每个占size字节,总大小 num * size
- 和 malloc 核心区别:分配完成自动把整块内存初始化为 0
- 等效写法
c
calloc(10, sizeof(int));
int* p = malloc(10 * sizeof(int));
memset(p,0,10*sizeof(int));
- 适用场景:数组,需要初始值全 0 的时候
realloc
函数原型:
c
void* realloc(void* ptr, size_t new_size);
- 功能:扩容 / 缩容已经分配好的堆内存
- 参数
○ ptr:之前 malloc/calloc/realloc 拿到的堆指针
○ new_size:目标总字节大小,不是增加多少字节 - 特性
○ 原有内存的数据会保留
○ 如果原地后面空间足够:直接原地扩容,返回原来地址
○ 如果后面空间不足:重新找一块足够大内存,拷贝旧数据,释放旧内存,返回新地址,旧 ptr 失效
○ 调试堆下:新扩展区域填充0xCD,边界保护标记0xFD - 重要坑:不要直接写 ptr = realloc(ptr, new_size);
如果 realloc 失败返回 NULL,你直接覆盖 ptr,原来的内存地址丢失,造成内存泄漏
推荐写法:
c
int* tmp = realloc(ptr, new_size);
if(tmp != NULL)
{
ptr = tmp;
}
三者共同点
- 返回void*,C 语言可以隐式转换,C++ 需要强制转换
- 分配失败统一返回NULL,一定要做判空检查
- 都在堆区分配,必须手动 free 释放,否则内存泄漏
- 用完 free 之后,原指针变成野指针,建议手动置 NULL
选型建议
● 单纯申请内存,不需要清零 → malloc
● 申请数组,内容需要初始化为 0 → calloc
● 已经分配好,需要动态扩大 / 缩小内存 → realloc
配套 free
c
void free(void* ptr);
- 参数:malloc/calloc/realloc 返回的堆指针
- 只能释放堆内存,不能释放栈指针
- free 之后这块内存还给堆管理器,指针本身不会自动变成 NULL
- 重复 free 同一指针 → 堆损坏
c
#include <stdio.h>
#include <stdlib.h>
int main()
{
// malloc
int* p1 = (int*)malloc(4 * sizeof(int));
if(p1 == NULL)
{
perror("malloc fail"); //打印系统错误信息
return -1;
}
// calloc,自动清零
int* p2 = (int*)calloc(4, sizeof(int));
// realloc扩容到8个int
int* tmp = (int*)realloc(p1, 8 * sizeof(int));
if(tmp != NULL)
{
p1 = tmp;
}
free(p1);
free(p2);
p1 = NULL;
p2 = NULL;
return 0;
}