前言
我们一般是如何向内存申请空间的呢?
int a = 10;//创建一个变量 int arr[10];//创建一个数组
这种向内存申请空间的方法,申请到空间后就不能再随意改变空间大小。
然而,在实际应用中,我们需要向内存中申请动态(大小可变)的内存空间,因此本文向大家介绍有关于动态内存空间的知识。
一、如何申请动态内存空间
介绍四个函数:
- malloc
- calloc
- realloc
- free
1.malloc函数
开辟动态内存空间
Void* malloc(size_t size)//size指所要开辟的空间大小,单位是bite。
1.开辟空间时时返回的值
1.成功:返回指向开辟好的空间的首地址的指针(类型时void*,因为malloc不知道申请空间后存放的数据类型,所以具体在使用时由使用者自己决定:将返回值的类型强制转换为所需要的指针类型即可)
2.失败:返回空指针(NULL)
【因为可能会申请空间失败,所以就要检查一下,避免对空指针解引用】
if (p == NULL) { Printf(“%s”, sterror(errno));//errno是一个存错误码的变量,sterror是可以将错误码转为错误信息的函数。 Return 1;//异常返回 } Return 0;//正常返回
2.特殊情况(size = 0)
当size = 0时,即申请空间为0时,malloc的行为是未定义的,具体取决于编译器。
2.free函数
一般与malloc、ralloc、realloc等开辟空间的函数配套使用;
例如:malloc开辟空间,free在使用完空间后将开辟的动态空间释放掉
注意
1、free(p)之后,p指向的空间被释放,但p所存的地址没有被改变,有成为野指针的风险,所以在释放空间之后要将p = NULL;
2、void free(void* ptr)
①如果ptr指向的空间不是动态开辟的空间,则free的行为标准未定义
②ptr = NULL,则free什么事情也不做
3.calloc函数
开辟一块动态内存空间
与malloc不同的是,
1.与malloc不同点
1.calloc开辟的空间在返回前,所开辟的空间会被初始化为全0;而malloc所开辟的空间的内容是随机值。
2.calloc开辟的空间大小为num*size;malloc开辟的空间大小为size。(单位都为bite)
2.特殊情况(size = 0)
当size = 0时,即申请空间为0时,malloc的行为是未定义的,具体取决于编译器。
4.realloc函数
在malloc和ralloc开辟的动态内存空间上进一步使空间变大变小(实现动态)。
realloc (p,size)//p是指向原空间首地址的指针,size是调整后动态内存空间的大小。
1.调整空间大小时可能出现的情况
1.原空间后方连续空间的大小足够调整空间到所需要的空间大小,此时直接在原空间后方开辟新的空间,返回原空间的首地址;
2.原空间后方连续空间的大小不足以调整空间到所需要的空间大小,此时在内存中重新找一块新的空间(大小足够到所需要的空间的大小),将原空间中的数据拷贝放到新空间,释放原空间,返回的是新空间的首地址。
2.注意
realloc开辟空间可能会失败,所以直接用指向原地址的指针去接收realloc的返回值,有可能会导致原空间地址也丢失。
为了防止这种情况的出现,就需要一个中间变量先接收realloc的返回值,再对返回值进行判断,如果返回值不为NULL的话,再用指向原地址的指针接收返回值。
3.当传给realloc的指针为空时,realloc的功能
当p = NULL时,即没有原空间的时候,此时realloc的作用和malloc的作用一样,都是开辟一个动态内存空间然后返回指向该空间首地址的指针。
二、常见错误的动态内存
1.常见错误
1.对NULL的解引用操作
2.越界访问(野指针的问题)
3.对非动态内存开辟的空间进行解引用(系统程序会运行崩溃)
4.free一部分动态内存开辟的空间(free的必须是所开辟的动态内存空间的首地址)
5.对同一块动态内存开辟的空间多次free
2.解决方法
1.自己注意不要多次释放;
2.释放完指针p指向的动态内存空间后将p = NULL。
3.忘记free动态内存空间(会产生内存泄露的问题)
常见的可能产生忘记free的两种情况:
①程序在运行途中就停止(return),没有执行到free这一步程序;
②专门用一个函数来开辟动态内存空间,在主函数使用完这块空间之后忘记释放。
当然,还有其他的可能,这里就不一一列举了
三、柔性数组
C99中,结构体的成员变量的最后一个元素位置大小的数组就称为柔性数组成员
1.定义
typedef struct sl_type { int i; int arr[];//柔性数组成员 }type_a;//将结构体名重定义为type_a
2.特点
1.柔性数组之前必须至少有一个成员变量;
2.sizeof返回的结构体大小不包括柔性数组的大小;
3.包含柔性数组的结构体在用malloc开辟内存空间的时候,申请的内存空间要大于结构体的大小,以满足柔性数组的使用需求
3.用法举例
malloc(sizeof(struct s)+40); 其中40就是给柔性数组申请的内存空间。
彩蛋
内存的开辟和使用情况(例图)
总结
本文主要介绍了动态内存管理的相关知识,主要介绍了四个开辟动态内存的函数以及柔性数组,希望本篇文章对各位小伙伴的学习有所帮助。
当然本文的内容是作者这个初学者对于这些概念的浅薄理解,如果内容中有任何错误或者你觉得不清楚的点,可以在评论区交流(也可以私信作者)。
如果大家喜欢这篇文章,希望可以支持支持作者。作者也在不断学习,之后也会继续上传自己的学习笔记。