一.引言
动态开辟内存都是通过申请堆上的一块连续的空间,当使用完之后也都需要手动进行空间的释放。
二.申请和释放空间函数简介
申请空间函数:malloc,realloc,calloc
释放空间函数:free
1)因为释放堆上申请的空间是必须要做的,所以首先来了解一下free函数
free函数原型
void free (void* ptr);
函数功能:释放对申请的的空间的使用权,将这块空间的使用权交还给操作系统;
注意:free只是释放了空间,但没有释放指针,没有将指向这块空间的首地址置为空,这个指针仍然指向这块开辟的空间。所以最好在释放空间之后也释放指针,将指针置为NULL
参数:释放的空间的首地址
没有返回值
特性:
free只能对动态开辟的空间可以进行释放;
如果参数ptr是NULL指针,函数什么也不做;
不能free多次;
注:如果申请的空间不释放,就会造成内存泄漏;
使用示例:
free(p); //释放空间
p=NULL; //释放指针
2)申请空间
!!!!!因为堆上申请的空间不会自动释放,所以在我们使用完申请的空间之后就要手动调用free函数进行空间的释放
-----------------------1.malloc-------------------------
函数原型:
void* malloc (size_t size);
函数的功能:开辟一块大小为size个字节的空间,开辟空间时每个元素的值不能进行初始化,默认为随机值;
函数参数:size(开辟空间的字节大小)
返回值:
成功返回一个开辟好的空间的首地址,但使用时需要进行强制类型转换;
失败返回NULL指针;
使用示例:
//开辟存储100个int型数据的空间
int* arr=(int*)malloc(sizeof(int)*100);
free(arr); //释放空间
arr=NULL; //释放指针
--------------------------------------------------------
----------------------2.realloc---------------------
函数原型:
void* realloc (void* ptr, size_t size);
函数功能:
为一块内存空间重新分配大小为size个字节的空间,同时会将原内存空间的数据移动到新的空间;
开辟空间时新的元素的值不能进行初始化,默认为随机值;
realloc可以让空间变大,也可以让空间变小;
参数:
ptr:要改变大小的内存空间的首地址;
注:如果ptr为NULL,等同于malloc,开辟一块新的空间,
size:重新分配的空间的字节大小;
返回值:
成功返回一个开辟好的空间的首地址,但使用时需要进行强制类型转换;
失败返回NULL指针;
关于返回值是否接收:
最好接收,如果不接收可能会出错
因为申请的空间比较大的话,如果原来的空间后面没有足够大的空间,我们就得为它在堆上申请一块足够大的连续的空间,并将原来的空间的数据拷贝过来,再释放原有的空间,返回新空间的首地址。
正确使用示例:
//新开辟一块空间
int* arr1=(int*)realloc(NULL,sizeof(int)*100);
//将arr1指向的空间大小扩充为200个整型大小
int* arr2=(int*)realloc(arr1,sizeof(int)*200);
//当前arr2和arr1指向同一块空间,因此只需要释放一次空间
free(arr2); //释放空间
p=NULL; //释放指针
没有接收返回值的错误演示:
----------------------------------------------------
----------------------3.calloc-------------------
函数原型:
void* calloc (size_t num, size_t size);
函数功能:开辟num个大小为size个字节的空间,并全部初始化为0
参数:
num:开辟的空间的元素个数
size:开辟的空间的每个元素的块大小,单位是字节
返回值:
成功返回一个开辟好的空间的首地址,但使用时需要进行强制类型转换;
失败返回NULL指针;
使用示例:
int* arr=(int*)calloc(100,sizeof(int));
free(arr); //释放空间
arr=NULL; //释放指针
-------------------------------------------------
三.常见的动态内存错误:
对NULL指针的解引用操作
对动态开辟空间的越界访问
对非动态开辟内存使用free释放
使用free释放一块动态开辟内存的一部分
对同一块动态内存多次释放
动态开辟内存忘记释放(内存泄漏)