为什么存在动态内存分配
我们常见的内存开辟方式如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
char arr1[20] = { 0 };
return 0;
}
但是这样开辟出来的空间大小是固定的,事先必须根据条件确定数组的大小 如果我们需要的空间大小在程序开始运行以后才能知道的话,就需要使用动态内存开辟了
注意:上述代码是在栈空间上申请以及使用空间,而动态内存管理所使用的函数都是应用于内存的堆区上的
一、动态内存管理
1.概念
2.相关函数
下述函数均包含在stdlib.h头文件中,后文不再赘述
(1)malloc与free
下面是malloc函数的类型与参数 这个函数的主要功能是向内存的堆区上申请一块连续且可用的空间,若开辟成功,函数返回一个指向这块空间的指针
既然函数的返回类型是void*,我们储存这块地址的时候当然也不要忘记将地址进行强制类型转化
如果开辟失败,函数会返回一个空指针; 虽然开辟失败的情况很少见,但以防万一,写代码的时候不要忘了先判断函数的返回值
如果malloc函数的参数为0,这种行为是标准未定义的,具体结果取决于编译器
然后看一下另一个函数free: free的返回类型和参数看起来也相当“纯真”,它是用来释放动态内存开辟的空间的 参数也必须是你用malloc开辟出的那个地址才行,所以使用时要记得把旧地址储存起来
如果参数指向的空间不是动态开辟的,那么free的行为是标准未定义的;而如果参数换成空指针的
将一块地址释放以后,指向这块空间的指针也就变成野指针了,所以千万不要忘记把这个指针置为空指针
(2)calloc
这个函数的功能就是为num个size大小的元素开辟出一块空间,并把空间的每一个字节初始换为0
其他的地方和malloc一模一样,他们两个的区别只是calloc多了一个参数,又加上一个初始化的功能而已
(3)realloc
这个函数用来调整动态开辟内存的大小 其中*memblock是想要调整的内存空间的起始地址,size则是调整后的内存大小
这个函数在调整原内存空间大小的基础上,还会将内存中的数据移动到新的空间,其具体实现过程相当与memmove,不了解这个函数的同学可以看一下我的这一篇博客: 库函数的奇妙冒险:从内存到字符串
实际上,realloc在调整内存大小时也存在两种情况: 如果原有空间后有足够大的空间,要拓展的内存直接追加在原空间的末尾,原来的空间数据不发生变化,返回的也是原来的地址 如果原空间后没有足够大的空间了,则会在堆空间上另外寻找一块大小合适的连续空间,并返回这块空间的起始地址
(4)常见错误
(1.对NULL指针解引用 (2.对动态开辟空间的越界访问 (3.对非动态开辟的内存使用free释放 (4.使用free释放一块动态开辟内存的一部分,即参数使用错误 (5.对同一块动态内存多次释放 (6.动态开辟内存忘记释放(内存泄漏)
二、柔性数组
1.概念
结构中的最后一个元素允许是未知大小的数组,这个元素就是柔性数组成员 代码如下(示例):
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
struct eg
{
int a;
int arr[];
}eg1;
printf("%d\n", sizeof(eg1));
return 0;
}
结构中的柔性数组成员前面至少要包含一个其他成员 sizeof返回的这种结构大小不包括柔性数组的内存 包含柔性数组成员的结构用malloc函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以便于适应柔性数组预期的实际大小
按照上面的规则,我们就可以轻松得出代码运行的结果了: 这几行代码其实也涉及到一些关于使用sizeof计算结构体大小的知识,总而言之还是“内存对齐”惹了不少麻烦,有兴趣的同学可以看一下我的另外一篇博客: 传送门
2.优势
第一个好处是方便内存释放: 在一个与结构体相关的函数中,如果这个结构体里存在一个未知大小的数组,我们既可以使用柔性数组,也可以根据前面的运行情况再进行一次动态内存开辟; 如果使用第二种方法,我们就必须在函数外将开辟的空间释放: 而在实际情况中,我们提供给用户函数,并返回一个指向这个结构体的指针,而这个函数里面还有一块动态开辟的空间,需要连续释放两次,但是用户只知道把返回的地址指向的空间释放一次,所以这种方法既不方便也容易导致内存泄漏 但如果我们使用柔性数组的话,用户只需要对返回地址指向的空间释放一次就可以了
总结
这篇博客的篇幅和我之前的其他博客相比要少得多 原因主要在于我前几篇博客中对推导过程的描写相对详细,一直保持着(量大管饱)的风格,而这篇博客的内容和前几篇相比也有很多重复的地方,所以粘贴了很多我以前作品的链接 创作不易,希望大家多多支持!
|