C语言 malloc 和 free 怎么用?内存泄漏怎么排查?
C 语言用 malloc/calloc/realloc 在堆上分配内存,用 free 释放。和栈上变量不同,堆内存的生命周期由程序员手动控制——分配了不释放就是内存泄漏,释放了再访问就是悬空指针。
追问
malloc、calloc、realloc 有什么区别?
malloc(size) 分配 size 字节,内容不确定(可能是垃圾值)。calloc(n, size) 分配 n×size 字节并全部清零。realloc(ptr, new_size) 在已分配内存基础上调整大小——如果新空间够大就在原地扩展,不够就另找一块新地方拷贝过去。realloc 返回新地址,旧指针可能失效,所以务必用返回值更新指针。
cint *arr = malloc(5 * sizeof(int)); // 5 个未初始化的 int int *arr2 = calloc(5, sizeof(int)); // 5 个全零 int int *arr3 = realloc(arr, 10 * sizeof(int)); // 扩到 10 个
内存泄漏怎么排查?
最直接的办法:每个 malloc 配一个 free,在代码审查时逐对核对。工具方面,Linux 下用 Valgrind(valgrind --leak-check=full ./a.out)能自动检测泄漏位置;macOS 用 Instruments 的 Leaks 模板。常见泄漏场景:函数提前 return 忘了 free、循环里分配但只保存了最后一个指针、结构体成员分配了但释放结构体时忘了先释放成员。
悬空指针和野指针有什么区别?
野指针是未初始化的指针,指向随机地址——声明后没赋值就用了。悬空指针是释放后没置 NULL 的指针,指向已回收的内存——free(p) 后 *p 就是悬空访问。两者都是未定义行为,但悬空指针更危险,因为那段内存可能已被重新分配,改写它会导致别的数据被无声破坏。free(p); p = NULL; 是最简单的防护。
realloc 失败了怎么办?
realloc 失败返回 NULL,但原来的内存块仍然有效。常见错误写法:p = realloc(p, new_size); 如果失败,p 被置 NULL,原来的内存块丢失了——既无法访问也无法释放,内存泄漏。正确做法是先用临时指针接返回值,成功再更新:
cint *tmp = realloc(p, new_size); if (!tmp) { free(p); return NULL; } // 失败也要善后 p = tmp;
实际项目里怎么管理内存?
小项目靠纪律:谁分配谁释放,函数文档写清楚返回的指针要不要调用者 free。大项目用内存池——预先分配一大块,自定义分配器从中切分,统一释放时一次 free 整个池。另外 C11 引入了 _Atomic 和 aligned_alloc,但核心思路没变:malloc/free 配对,free 后置 NULL,每个分配都有明确的释放点。