动态内存管理,如何实现内存的高效分配?良心制作,属实不易!

目录

前引

与之相关的4个重要函数

malloc—申请所需内存

对开辟空间有效性的判断

free内存释放

calloc—申请所需内存

malloc与calloc的区别

realloc调整动态空间

realloc调整空间的2种情况

常见的动态内存错误(重点)

动态开辟必须流程

内存大概分配图

几个经典的笔试题

 

前引

静态与动态内存:

1:相较于静态内存,动态内存可以按需分配,取多少用多少,避免空间浪费,比如(静态的创建变量,这种就随便开辟了一块空间,可能用不完):

2:突破栈空间限制,栈空间有限且容易溢出,而动态空间利用堆空间进行存储

3:延长变量生命周期,内部变量在函数返回后任然有效,实现局部变量的全局化使用

后面还给大家整理了常见的错误点,避免了这些坑,动态开辟直接满分!

看到这里,有没有想一睹动态内存真容的冲动!我们一起来了解了解吧!

与之相关的4个重要函数

malloc (申请所需内存)                    calloc (申请所需内存)                                                                                        realloc  (调整内存空间)                  free (释放开辟的内存空间)             

  头文件均是:<stdlib.h>

动态分配的重点是这四个函数,我们来一一讲解,千万认真记笔记!

在前面我们先只了解这4个函数的参数、返回值、作用,后面会整理各种做法的原因!

malloc—申请所需内存

学习库函数,我们需要了解它的参数,以及返回值,可以登入下面的网站,搜素想了解的库函数


https://legacy.cplusplus.com/

我们可以看到,它只需要一个参数:字节大小 

返回值:地址             

 比如:

创建了一个 int 类型的指针 p ,指针指向 malloc 开辟空间的起始位置,空间的大小是16个字节

 注意:

            1:开辟的空间需要注明类型,为了之后指针的移动方式来存储数据

            2:malloc 后面的参数可以写成表达式,但是要保证表达式的结果是多少多少字节

对开辟空间有效性的判断

下面我们来看一个例子:

我们可以看到,虽然确实打印成功了,但是编译器提醒了你,如果开辟失败,那么P就是空指针,也就不符合语法了,所以我们做一下改进这个很重要,如果不加判断,那么可能会发生非法访问 ,因为P是空指针,强制移动P可能指向其余不属于自己的空间

判断的2种方式:(自选一种即可)

第一种,需要头文件:<string.h>以及<errno.h>

 

第二种:

 

最后提醒三遍:动态开辟空间的,都需要做判断,防止非法访问

                         动态开辟空间的,都需要做判断,防止非法访问

                         动态开辟空间的,都需要做判断,防止非法访问 

free内存释放

 我们在前引里面说过了,动态开辟可以延长变量的生命周期,那么我们开辟了一块动态空间,一直开辟,一直开辟下去,是不是有效空间会越来越少,所以我们需要再使用完后及时释放开辟的空间

那么我们如何释放开辟的动态空间?

方式:free(指针)

           指针置空

比如:

注意:先释放后置空,这两步缺一不可! 

calloc—申请所需内存

这个函数的申请空间其实和malloc差不多,至于差距我们后面会细说!先了解这个函数的使用就行了!

它需要2个参数:元素个数   元素类型的大小

怎么样?calloc跟malloc的参数其实意思一样,只是calloc的参数把malloc的参数分解成了2个

比如:

malloccalloc这两个函数都是开辟动态内存,那么区别是什么?

malloc与calloc的区别

malloc:开辟空间后,没有初始化,直接返回空间位置的起始地址

calloc:开辟空间后,进行初始化(默认全部初始化为0),然后返回空间位置的起始地址

我们也可以从内存上面看到它们两个的区别:

realloc调整动态空间

顾名思义 ,realloc就是用来调整的,我们再开辟空间时,因为malloccalloc开辟的空间是连续的,那么我们如果所需要的内存空间过大,后面不够了咋办?这时候就需要realloc来进行调整

2个参数:调整对象   总共需要的空间大小

返回值:地址

注意:返回的地址再用指针接收时,不能用原来的指针,接受后还是需要判断是否开辟成功,再进行指针指向的托付(后面会在易错点里面说,放心!

比如:(经过realloc调整的空间可以继续使用,因此注意下面图中的 i 的取值)

 下面我们来对realloc进行讨论,相信看完,绝对是炉火纯青了!

realloc调整空间的2种情况

第一种情况:

当调整空间足够大时,那么realloc会在原空间后面连续开辟剩余的空间

第二种情况:

当调整空间不足以支撑剩余的所需空间时,会找其它地方重新开辟总大小的连续空间,并把旧看空间的数据拷贝过来,再将旧空间自动释放,同时返回新空间的起始地址,继续使用就行了

 比如:(对比这2幅图,我们用realloc调整后可以继续使用,指针指向的位置还是上一个空间结束的位置)

 注意点:

如果realloc调整的对象为空指针NULL,就相当于随便找位置开辟了一块指定大小的空间,类似malloc函数作用,比如:

常见的动态内存错误(重点)

1:对NULL指针的解引用操作(未判断指针的有效性)

只要开辟了动态空间,就需要判断指针的有效性,如果开辟失败,那么这个指针就是空指针,再访问就是非法访问了

 2:对动态开辟空间的越界访问

我们开辟的是16字节大小的空间,但是使用时却超出了16字节的范围,这就发生了越界访问

3:对非动态开辟内存使用free释放 

我们创建的变量是在栈区的,但是我们却对它进行了内存释放,内存释放释放的是堆区,两者毫不相干 

4:使用free释放开辟的动态内存的一部分(就是指针指向发生了改变)

free释放内存的原则:指针指向必须是开辟动态空间的的起始位置 

下面几种形式就需要特别注意,因为指针发生改变:

这种直接对p指向改变的需要先记录p的起始位置,空间使用完后,让p回到起始位置,再释放空间 

比如:

 5:对同一块动态空间多次释放

那么我们可以怎么改呢?直接先置空,这样就没有问题了,因为释放置空后,这个空间就不属于它了,再释放也就等于释放一个不存在的空间,没有影响,比如:

 

 6:动态内存的忘记释放

我们知道动态内存可以延长变量的生命周期,如果开辟了,不释放,那么它就一直在堆区存在,这样堆区内存越来越少,程序就崩了! 

比如下面这个代码:

内存会一直一直开辟下去,最终会崩溃!我们一定要记得及时释放,用完就释放 !

                   

动态开辟必须流程

使用malloc或者calloc或者realloc开辟动态空间后,都要判断空间有效性,即指针是否是空指针

最后记得进行及时释放 

内存大概分配图

几个经典的笔试题

                                                                       第一题 

 

大家可以先看上面的原题,找找错误,再看解析:

首先,strp没有建立真正联系,因为是传值操作

其次,GetMemory函数接收的参数应该是二级指针,应该是对*p开辟内存,因为*p才是一个指针

最后,没有对*p进行判断,也没有进行空间释放,   下面是改正:

                                                                         第二题 

 错误点很明显:就是GetMemory中有个数组,str需要指向这个数组,但是这个数组是临时变量,函数调用完销毁后,主要是解决这个数组被销毁的问题

改进:(我这里忘记释放内存了!不好意思啊,大家记得加上!)

                                                                          第三题

 

这个问题不大,缺一个指针有效性判断跟空间释放,下面是改进:

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值