引言
为什么会有个动态内存管理?
在之前的学习中,我们已经学会了常见的变量和数组的创建方式,并且知道数组是一块一直大小连续的内存空间。如下:
int num = 0; // 在内存中开辟了4个字节用以存放int类型的变量num
char arr[10] = "hello"; // 在内存中开辟了10个字节用于存放字符数组arr
可以观察到,这两种在内存中开辟空间的方式存在一些不足:
a.开辟的空间大小始终不变,直至销毁或者释放
b.在声明数组的时候,必须指定数组的长度,用以在编译时进行内存的分配
但是有些时候我们并不需要直接指定数组所占的内存空间。若初始值设置过大,会造成内存浪费;若初始值过小,则可能会导致内存溢出,或是程序无法正常编译。
这种时候,就需要使用动态内存管理了~~~
常见的动态内存函数
提要:
本文所提及的动态内存管理相关函数均声明在头文件stdlib.h中,使用时需要调用此头文件
1.malloc
使用MSDN搜索malloc
malloc是动态内存开辟函数,可以通过传递的参数开辟大小为size字节的内存空间;
返回的是指向这块内存空间的地址。
这里有几个需要注意的地方:
(1)开辟成功:当内存中可以找到连续size个字节的空间时,开辟成功,返回指向这块空间的地址;
(2)开辟失败:当内存中找不到连续size个字节的连续空间时,开辟失败,返回NULL。
(3)返回值的类型时void*,void*类型的指针无法直接进行使用,需要在使用时对malloc的返回值强制转换为所需要的指针类型
(4)若在使用malloc时参数传递为0,malloc中并没有规定应该如何,这时返回值取决于编译器。
很重要的一点是:
一定要对malloc的返回值进行检查,若返回了NULL则应当立即提醒并退出程序;若不为空(即开辟成功)再进行使用
2.free
动态开辟的内存与我们直接定义的变量在内存中存储的区域是不同的,是需要我们主动进行释放的。
free函数就是用以释放动态开辟的内存。MSDN中如下:
在使用free时区分不同的情况:
a.若传递的参数所指向的空间不是动态开辟的,则free行为是没有定义的
b.若传递的参数为NULL,则free将不执行任何操作
c.所有动态分配的内存在使用结束后都应进行释放并置NULL,防止出现内存泄露
3.calloc
使用MSDN查看如下:
calloc的使用需要传递两个参数,num为所需要开辟的数量,size为所需要开辟的单个元素所占用的字节数。即开辟num个大小为size的空间。
calloc和malloc是有相同之处的:
a.若开辟成功,返回的均是指向该块内存空间的地址
b.若开辟失败,返回均为NULL
c.一定要对返回值进行检查,确认正确后在进行使用
d.使用完毕后使用free释放并且置空,防止野指针出现。
但是calloc和malloc是由不同之处的。
使用VS来调试并查看内存可得:
calloc会将开辟的空间中每个字节初始化为0;malloc开辟的空间则是内存中的默认值
若我们需要直接对申请的空间进行初始化,可以很方便的使用calloc来完成。
4.realloc
有时候申请的内存空间会过大或者过小,为了合理使用内存,需要对申请的空间大小进行调整,这时就可以用到realloc了。
MSDN中关于realloc如下:
realloc用来对动态开辟的内存进行大小的调整。
使用realloc需要传递两个参数:memblock为所需要调整的内存地址,size为调整之后的大小。
realloc的返回值是调整之后的内存的起始位置。
这个返回值分三种情况:
a.返回原地址
原申请的空间之后有足够所需空间(假设要将原空间调大,则所需空间为新调整大小-原空间大小),这时返回的仍是原空间地址,但指向的空间已经变大。如图:
b.返回新地址
当原空间之后没有足够的新增空间时,将会在内存中查找足够大的空间,并将原内存空间中的内容拷贝至新的内存空间中,free原空间的地址,并返回新空间的地址。如图:
c.返回NULL
当原空间后的空间不足,以及在内存中无法找出满足调整后空间大小的连续内存时,将会返回NULL。
故在使用realloc时需要注意:
最好使用临时变量来接收realloc返回的地址,并检查是否为NULL,不为NULL时再将临时地址赋给原地址。如下:
#include <stdlib.h>
#include <stdio.h>
int main()
{
// 原开辟空间
int *ptr = (int*)malloc(40);
// 判断
if(ptr == NULL)
{
// 若为空提示并退出
}
// 使用
// 调整
int* tmp = (int*)realloc(ptr, 80);
// 判断
if(tmp != NULL)
{
// 当不为空时再将临时地址传递给原地址
ptr = tmp;
}
// 释放 置空
free(ptr);
ptr = NULL;
return 0;
}
还需要注意如下:
a.当传入realloc的size为0时,效果相当于free();
b.传入的指针必须是通过malloc/calloc或者realloc分配过的
c.若传入的指针为空,则相当于malloc