C语言(6.动态内存管理)
1. 动态内存函数
动态内存:在堆上动态的开辟内存空间
动态内存函数都在头文件<stdlib.h>
中声明
1.1 malloc
向堆内存申请一块连续可用的空间,并返回指向这块空间的指针
void* malloc(size_t size);
- 返回值:指向分配空间的指针,如果申请失败,返回NULL
- 参数:size - size_t类型(unsigned int),需要申请空间的字节数
使用:
int* arr = (int*)malloc(20 * sizeof(int)); //申请连续的20个int大小的空间
1.2 free
释放动态开辟的内存
void free(void* ptr);
- 返回值:无
- 参数:ptr - 指针,被释放的空间的首地址
注意:
- 如果参数ptr不是动态开辟的,free函数的行为是未定义的
- 如果ptr为NULL,则free什么也不做
使用:
free(arr); //释放arr指向的空间
1.3 calloc
向堆内存为num个大小为size的元素申请一块连续可用的空间,将空间初始化为0,并返回指向这块空间的指针
void* calloc(size_t num, size_t size);
- 返回值:指向分配空间的指针,如果申请失败,返回NULL
- 参数:
- num - 申请的数据类型的个数
- size - 每个数据类型的大小
注意:
- calloc与malloc的使用区别仅仅是参数列表不同,功能上的区别仅仅是calloc会将空间初始化为0
使用:
int* arr = (int*)calloc(20, sizeof(int)); //申请20个int大小的空间,并初始化为0
1.4 realloc
对之前申请的内存空间,进行大小上的调整
void* realloc(void* ptr, size_t size);
- 返回值:指向调整之后的空间的指针,调整失败返回NULL
- 参数:
- ptr - 被调整空间的首地址
- size - 调整后的内存字节大小
注意:
- 原空间后面有足够的空间进行调整时,直接在原空间上追加空间,原空间的数据和调整后空间的地址不变
- 原空间后面的空间不足以调整到指定大小,在堆上另找一个大小合适的连续空间,并将原空间内容复制过去,新空间的地址发生改变。
- 如果参数是NULL,则开辟一块新空间,
realloc(NULL, 40)
的效果等于malloc(40)
- 使用relloc函数时,不要将返回值直接赋给指向空间的原指针,否则申请失败时返回NULL,导致原指针指向的内存失去指引导致内存泄漏
int* ptr = (int*)realloc(arr, 40 * sizeof(int)); //将arr重新分配40个int的大小,地址赋给ptr
if (ptr == NULL)
{
//错误信息处理
}
arr = ptr;
2. 常见问题和解决方案
2.1 常见错误问题
-
内存分配未成功,却使用它
- 解决:使用函数申请内存后,必须检查是否为NULL
-
内存未初始化,却使用它
- 解决:内存申请到手之后,必须赋初始值
-
忘记释放,造成内存泄漏
- 解决:动态内存的申请和释放必须配对,防止内存泄漏
-
内存已经释放,却仍在使用
- 解决:释放内存后,立即将指针置为NULL,防止产生野指针
//正确写法
int* ptr = (int*)malloc(20 * sizeof(int));
//检查是申请成功
if (NULL == ptr)
{
//错误处理
、、、
}
//ptr初始化
//内存使用
free(ptr); //释放内存
ptr = NULL; //将ptr置为NULL
- realloc重新分配内存失败,原空间内存泄漏
- realloc重新分配失败时,会返回NULL,导致直接赋值的原空间指针变成NULL,原空间失去指引
- 解决:realloc时,先创建一个指针接收返回值,对返回值判断后再决定赋值给原空间的指针
//错误写法
ptr = (int*)realloc(ptr, 40 * sizeof(int)); //错误,失败时ptr=NULL,原空间内存泄漏
//正确写法
int* temp = (int*)realloc(ptr, 40 * sizeof(int));
if (temp == NULL)
{
//错误处理
}
ptr = temp; //申请成功后,再将新地址赋值给ptr
内存泄漏:空间失去指针的指向,程序无法访问,一直存在在内存中。在程序运行结束时操作系统会回收该空间
- 频繁向操作系统申请空间,造成内存碎片化和程序效率低
- 解决:使用内存池(此处不做介绍)
2.2 常见报错原因
realloc
报错:大概率是申请的堆内存越界访问了,realloc
在重新分配内存时会先检查原来内存是否错误,如果出错就会报错free
报错:大概率是申请的堆内存越界访问了,malloc
申请的空间越界使用后,会在释放时报错,但NULL被free时不会报错