malloc/free 内存问题
一、malloc 和 free 函数
1. malloc:动态分配内存
功能:在堆区分配一块指定大小的连续内存空间,返回指向该空间的指针。
原型:void *malloc(size_t size);
参数:size 为需要分配的字节数(通常用 sizeof(类型) 计算)。
返回值:成功时返回指向分配内存的指针;失败时返回 NULL(需检查返回值)。
示例:
#include <stdlib.h> // malloc 和 free 的头文件
int main() {
// 分配可以存储 5 个 int 类型的内存空间
int *arr = (int*)malloc(5 * sizeof(int));
if (arr == NULL) { // 必须检查分配是否成功
// 处理内存分配失败(如输出错误信息)
return 1;
}
// 使用分配的内存
for (int i = 0; i < 5; i++) {
arr[i] = i;
}
// ... 使用完毕后需释放内存
return 0;
}
2. free:释放动态分配的内存
功能:将 malloc(或 calloc、realloc)分配的内存释放,归还给系统。
原型:void free(void *ptr);
参数:ptr 是 malloc 系列函数返回的指针(不能是其他指针,如栈变量地址)。
注意:
释放后,指针 ptr 不会自动变为 NULL,需手动置空(避免野指针)。
不能重复释放同一块内存(会导致程序崩溃)。
不能释放非动态分配的内存(如栈上的局部变量)。
示例:
int *p = (int*)malloc(sizeof(int));
if (p != NULL) {
*p = 10;
free(p); // 释放内存
p = NULL; // 手动置空,避免野指针
}
二、常见动态内存问题
1. 内存泄露(Memory Leak)
定义:动态分配的内存使用完毕后,未通过 free 释放,导致这部分内存无法被系统回收,长期运行会耗尽可用内存。
原因:忘记释放内存、释放路径被跳过(如函数提前返回)。
示例(内存泄露):
c
运行
void func() {
int *p = (int*)malloc(sizeof(int));
// 未调用 free(p),函数结束后 p 被销毁,内存无法释放
}
int main() {
while (1) {
func(); // 每次调用都泄露一块 int 大小的内存
}
return 0;
}
2. 内存溢出(Memory Overflow)
定义:程序需要分配的内存超过了系统能提供的最大内存,导致 malloc 失败(返回 NULL)。
后果:若未检查 malloc 返回值,直接使用 NULL 指针会导致程序崩溃。
示例:
int main() {
// 尝试分配远超系统能力的内存(如 10GB)
int *p = (int*)malloc(1024 * 1024 * 1024 * 10 * sizeof(int));
*p = 10; // 若 p 为 NULL,会导致程序崩溃
return 0;
}
3. 越界访问(Out-of-Bounds Access)
定义:访问动态分配的内存时,超出了分配的范围(如访问 arr[5] 但只分配了 5 个元素的空间)。
后果:修改其他变量的内存、程序崩溃、数据损坏(编译器通常不报错,需手动保证访问合法性)。
示例(越界访问):
c
运行
int *arr = (int*)malloc(5 * sizeof(int)); // 分配 5 个 int(索引 0~4)
arr[5] = 10; // 越界访问(索引 5 超出范围)
free(arr);
4. 野指针(Wild Pointer)
定义:指向无效内存的指针(未初始化、已释放或越界的指针)。
常见场景:
指针未初始化(指向随机内存)。
指针指向的内存已被 free 释放,但指针未置空。
指针越界(指向超出分配范围的内存)。
后果:访问野指针可能导致程序崩溃、数据损坏或不可预知的行为。
示例(野指针):
// 场景 1:未初始化的指针
int *p;
*p = 10; // p 是野指针,操作危险
// 场景 2:释放后未置空的指针
int *q = (int*)malloc(sizeof(int));
free(q);
*q = 20; // q 已释放,成为野指针
三、避免内存问题的原则
配对使用 malloc 和 free:动态分配的内存必须释放,且只释放一次。
释放后及时置空指针:free(p); p = NULL;,避免野指针。
检查 malloc 返回值:确保内存分配成功后再使用。
严格控制访问范围:避免越界(如通过变量记录动态数组长度)。
初始化指针:不确定指向时,先初始化为 NULL。
总结
malloc 和 free 是 C 语言动态管理堆内存的工具,需手动控制生命周期。
内存泄露、溢出、越界访问和野指针是常见风险,需通过规范代码(如检查返回值、及时释放、避免越界)规避。
良好的动态内存使用习惯是编写健壮 C 程序的关键。