动态内存函数的介绍
1 malloc 和free
简单来说,malloc函数就是用来开辟内存空间的
我们去cplusplus上看下函数定义
不难看出,这里参数只有一个,就是你想开辟的字节数,然后返回值为void* 的指针,想用别的指针得自己强转
如果开辟失败就会返回空指针
我们举个简单的例子
这里我给int型指针pa开辟了40个字节的空间,如果返回为空指针就打印错误,并且返回1,然后在开辟的空间里放值,再打印
注意malloc的返回值一定要判断,不然指不定在哪个地方就会出事儿,然后你还发现不了
再举个例子,我们切换到x86环境下,再改一下开辟的空间量
(INT_MAX是一个巨量的数字,有21亿多,在x86下肯定是装不下的)
接着再运行下看看
因为数字太大了,直接导致开辟失败,malloc返回值为NULL,进到if里后打印错误并且立马返回1并结束运行,这样能最大限度地保证空间开辟成功
事实上malloc开辟的空间用完之后是需要我们手动结束的,它不像是局部变量一样存放在栈区里面,能够随着局部的括号一起自动销毁,而是需要我们手动销毁,否则就会造成内存泄漏,比方说我们这里写一个小小的死循环,刻意不销毁开辟的空间
你能够看到内存占用直线上升,连截图都卡的那种,还要把程序关了才能够截图的那种
打个不雅的比方,前面的人占着茅坑不拉屎(开辟内存既不释放,又不使用),后面的人想进来都进不来(截图都难)
接下来看看怎么内存释放
过程很简单
比方说这里开辟40byte给p,p里面放上值
如果我后面就不想用p了,我就在free函数里放p,这样运行到free额时候p就被释放了
你可以看到被释放完之后就变成成了dd…
但此时还有一个问题,p这个变量怎么办??
p的空间没了,p不就变成了野指针了??
很简单,在释放完之后再搭配一个赋值,把p赋值成NULL就行
一般情况下都要这么搭配,要不然很容易出错
还有的小天才,想着把malloc里放个0会怎么样,事实上这样的操作在c语言中是未定义的,具体会怎样执行取决于编译器,所以还是别随便乱传参数给malloc(后面的calloc和realloc也是同理的)
还有小天才试图free掉非动态内存开辟空间的变量,比方说
你能够看到程序结束后返回非0,说明报错了
好了,我们现在讲完malloc了,但你没发现吗,malloc用起来还是稍微有点别扭的,每次开辟完还要手动初始化,如果我们懒得手动初始化,想要更方便一点,怎么办呢,这里咱就讲讲calloc
2 calloc
首先看看函数定义
第一个参数是开辟的内存里面,你想放的元素个数,第二个参数是每个元素所需要的大小(字节)
相同的,如果开辟成功了就返回开辟空间的地址,失败就返回空
他与malloc的区别就是,calloc执行完默认会把空间里头每个字节都初始化成0,就不用再手动初始化了
比方说
你能看到它的空间全都初始化成了0,就会比malloc会要方便一些(除非你的需求就是不进行初始化)
所以总的来说,calloc函数就像是malloc+memset的结合体一样
而动态内存最突出动态的部分,就需要我们来讲讲下面这个函数了
3 realloc
这个函数如何突出动态二字??
有时候我们发现用malloc或者calloc开辟的空间不够用或者是空闲空间太多了,此时我们就可以用realloc这个函数来实现动态内存的分配了,动态地适时调整内存大小,做到要多少拿多少,一点也不浪费
我们先看看定义
第一个参数ptr是要修改的空间的起始地址,第二个参数size是你想修改成的空间大小
返回值是修改过的空间的地址
我们来看看realloc函数的工作原理
这里我们两种情况(橙色代表已经被使用的空间)
情况1:
假设说我们要从40byte扩充为80byte,函数如果发现在原来40byte后面依旧有空间分配给需要增加的40byte,他就会直接分配
情况2:
同样的例子,函数如果发现在原来40byte后面没有空间分配给需要增加的40byte,他就会在内存中找一片有80byte空间的空地,把原来的数据挪过来,老区域的内存释放掉
值得注意的是,咱在申请空间的时候是不能够直接把realloc的返回值赋值回原来的指针的,这样的做法是十分危险的
问题就在于,申请空间的时候是有可能失败的,要是万一失败了,返回值就成了空指针,指针p就会瞬间失忆,变成了野指针,那可就完蛋了,好家伙本来武器还能凑合用用,升级锻造加上限给锻造爆了,瞬间归零了属于是
所以我们还需要一个中间变量ptr来判断一下
当然,如果你这么写,那功能就和melloc函数是相同的了