前言
在了解动态内存管理之前,我们要先了解关于c语言的内存中的栈区、堆区和静态区:
栈区主要存储形式参数(也就是我们调用函数的时候一般会将我们定义的实参传入函数后所形成的参数),以及局部变量(比如说就是我们在main函数中定义的int A=10;等等的变量)。在栈区创立的变量在程序运行完后会自动回收,不需要我们去进行回收操作,而堆区是我们可以在堆区内存充裕时按照自己所需要的字节大小去主动申请空间的地方,我们称之为堆区,也就是我们下面主要要讲到的动态内存管理,相比于栈区更具有可操作性,需要自己去回收。最后一个是静态区,也就是我们所说的全局变量,在main函数外定义的变量,以及静态变量,一般用static来修饰的变量,他们在使用时会在静态区开辟内存。
动态内存管理的优点
1:栈区和堆区内存独立,在开辟空间时候不在栈区开辟空间,而是独立地在堆区进行内存操作,避免了栈区内存过度使用,也提高了内存分配的效率。
2:可操作性强,在堆区进行内存开辟是靠自己去衡量需要开辟的大小以及何时回收,因此在使用动态内存规划时能更贴切写程序时的需要。
动态内存具体使用方法和使用时机
这里主要讲述三个在堆区开辟内存空间的函数和释放内存的函数:
1:malloc函数
从源代码中可以看到,传入的就只是一个无符号的整形数字,就是需要开辟的字节数,前面的函数类型为void*,即返回一个无定形的指针,因此我们在使用的时候只需要创建某个类型指针然后再将其开辟后的地址强制转换成这个类型的指针再赋值就行。当堆区内存不够时,开辟失败的时候会返回NULL,即开辟失败。(ps:运用malloc函数开辟的内存是一段连续的存储空间,因此可以抽象成一个数组去使用)(以下代码还未使用free函数释放空间,后面讲到再使用)
例子:
**
2:calloc函数
**
从以上看到calloc函数返回类型也是void和malloc一样,所以也是需要强制类型转换后赋值的,而后面传入的元素有所差别,即第一个nitems是代表需要开辟的内存个数(这个个数仅仅只是数量,而不是字节数),后面的size则代表的是某种类型的字节数,比如说int类型那么就是size为4个字节,如果是char类型那么size就是1个字节 。*这个calloc函数与malloc大致相似,但唯一有一点不同的便是calloc开辟一段连续空间后会进行初始化赋值为0进去。
用法是与malloc相似的就不赘述了。
**
3 realloc函数
**
我们也可以叫realloc为扩容函数,开辟的空间也是连续的一段内存,从源代码也可以看出是与malloc、calloc类型一致都是void*,因此都需要强制类型转换,不同于前两个函数,这个函数第一传入元素为指针ptr,第二个为大小size。这里要进行解释一下,ptr指针代表的是需要扩容的首地址,size代表的是新的一段内存的总大小,而不是需要开辟的内存大小。例如我原本ptr指针所指的内存为20个字节,而我需要扩容40个字节,那么我的size需要传入的是60个字节而非40个字节。
(ps:当ptr为NULL也就是空指针的时候,realloc的作用可以看作是malloc,因为ptr是空指针的时候就类似于我重新开辟一段空间而非是在原有的空间上扩容)
例子:
注意:
这里realloc函数开辟的内存分为三种情况:
第一种:若堆区内存足够则在原来的地址之上向后开辟内存,即返回的地址是原来传入的地址:
第二种:若想要原来ptr地址上开辟的内存,但是在原来的地址内存之后不够内存开辟,则在另找一段新的地址开辟所需大小的内存并且返回新的地址。(ps:原来的地址所指向的内容不变,只是新开辟的一段内存而地址变了)
第三种:完全就没有足够内存开辟,返回NULL,改变了原来ptr传入的内容。
4 free函数
即在开辟内存使用完后进行释放,若不释放可能就导致内存泄漏,还要将释放后的指针赋值为NULL,不然会成为野指针。。
最后在使用动态内存管理的这四个函数时候需要包含头文件<stdlib.h>
版权归原作者 SPMAX 所有, 如有侵权,请联系我们删除。