动态内存管理

1.指针

2.结构体

3.动态内存开辟

这3个决定你学数据结构的水平,这3个你学不好的话到时候用c++来实现数据结构体会很teng的

目前我们知道的向内存申请空间的方法

1.一种是申请变量的空间

2.一种是申请数组的空间

我们这个申请有什么不好的呢,就在于你申请了这个空间之后,这个空间是无法改变的,

空间一旦开辟好久不能调整他的大小了

知道为什么会有动态内存管理存在吗

原因

1.空间开辟的大小是固定的

2.数组在申明的时候必须指定数组大小的长度,它所需要的内存在编译时分配,不仅仅是上面的情况,有时候我们在程序编译的时候,如果空间不够了,然后我们的数组的大小是指定的,那这样就需要我们的动态开辟了

动态内存管理核心的东西就是下面这4个函数

1.malloc

2.calloc

3.realloc

4.free

malloc

开辟内存块的函数

开辟一块size字节的空间,返回这个空间的起始位置

要怎么用

当我们要开辟多少个字节时,就往malloc里面写多少个字节,比如我们要开辟40个·字节的空间,就直接写40,开辟好了空间之后,就要返回这个空间的起始地址,哎呀但是为什么返回的地址是无符号的呢,因为你开辟这个空间,你可能想好了这个空间以后是用来干什么的,但是这个函数是不知道你想干什么的,所以他返回的无符号,并且如果你想用来开辟char和int都可以

但是我们要想一想,我们申请内存空间的时候会不会申请失败

会失败,你想想你用户入如果要4个字节,但你只开辟了3个字节,那么不就失败了吗,失败了就会返回一个空指针

现在我们要开辟40个字节的空间来存放整形

那么我们就用一个整形指针来接收,并且把他开辟的空间,强制转换为整形

这样以后我们给p加1的话就会跳过一个整形

在我们C语言中

INT MAX里面有整形最大开辟的空间

21亿多的空间

这时候就开辟失败了

我们数组和变量是在栈区开辟的空间

我们的动态内存的函数开辟空间是在堆区的

栈区里面的空间如果你申请的不够大是不能再申请的

堆区的不够大就可以再申请一点点

有学习过的小伙伴肯定知道,我们用了malloc申请,那么不就要释放吗,不然的话是不是内存泄漏了

这里我是没有写free,但是这也代表了不了我没有回收,当我的程序退出的时候,我们的系统会自动帮我们回收内存空间

内存泄漏:你向我申请空间,我把空间分给你,你用完了你不再用但你没有还,你不用不还,我就拿不到那本书,那么就内存泄漏

比如你我借你一本书,你看完了但你就是拿着不还,这本书我看不上,你不还,那么就是内存泄漏了

变长数组

变长数组这个名字不好,因为他不能把这个数组的长度变长,他的作用就是当你在指定他大小的时候可以用便来你

vs编译器是是支持的,c99编译器上才支持

这里我们还是写一下释放,free,但是我们还给系统的时候这个指针存的还是我们的地址,所以我们要手动给他个空指针,如果我们不给他个空指针,那么P如果有招一日拿起来,去访问我们这个空间,那么这个p就是野指针了,所以为了防止野指针,我们给他个空指针,让他永远都不要找到我们

这样的写法是不行,因为你p都被你赋值成空指针了,你连p的空间你都找不到,你还释放个毛啊

先释放再清除

如果你非要写bug无节制的开辟空间,那么电脑就会一直给你分配空间,然后最后结果就会死机

但是现在的电脑太智能,是不会给你无节制的开辟空间的,以前的电脑就会,直接卡到死机了

malloc和free注意事项

malloc

这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针

如果开辟成功,则返回开辟的内存空间的指针

如果开辟失败,则返回空指针,因此malloc的值一定要做检查

返回的类型是void *所以malloc不知道要开辟的空间的类型,具体在使用的时候由使用者来决定

如果size的参数是0 malloc行为的标准是未定义的,取决于编译器

free

是用与释放动态开辟的内存空间的

如果ptr指向的空间不是动态内存开辟的,那free的行为是未定义的

就是有人这样写,真是无语了

free必须释放动态内存开辟的空间,像我们这个p是栈区上的空间,不能想当然的去释放别人的空间

如果free释放的是空指针,那么就什么都不干

接下来我们来calloc

num是多少个元素

size就是每个元素的大小

假设我们要开辟40个字节

我们就可以换着说开辟10个元素,大小为4字节的空间

注意我们的calloc在开辟好空间之后,会把开辟的空间初始化为0,而我们之前学的malloc就不行

里面都是随机值

相当于这样

动态动态,现在必须要动动了

realloc

有时候我们申请的空间太小了,不够用,有时候我们申请的空间太大了,浪费了,为了合理的使用的内存,所以我们出现了这个函数

ptr就是我们要修改的空间的起始地址

size就是你希望把他调整为多大的空间

比如这样

realloc的工作原理

第一中情况,假设我们在内存中开辟了40个字节,然后我们的内存空间其他地方有些内存已经被用掉了

后面有别人要用的空间,而我们追加的字节数40可能会把别人的空间给覆盖了

第二种情况,就是比别人的情况好一点,后面没有别人用的空间,我们就可以直接追加

第一种情况怎么办,他是不会把别人的空间覆盖掉的,所以他自己会开辟一块新的空间

他会开辟一个新的空间放80个字节,然后把旧的数据拷贝过来,拷过来之后,再返回一个新的地址回去,旧的空间不用你手动释放,realloc会自动帮你释放的

千万不要用p去接收,因为如果你扩容失败了,那么就会变成野指针,因为你原先旧的地址已经是被释放了,

要拿一个新的指针去接收,如果这个指针没接收到野指针那么就可以被接收,说明扩容成功了

发现我们扩容后的地址还是一样的说明是第一种情况

注意如果你频繁的使用realloc会导致内存的碎片化,这里一块内存,哪里一块内存,内存利用率下降,然后还会导致效率下降,当你开辟新的空间,旧的就要释放影响效率

每次我们使用realloc申请空间,都是向堆区申请的,我们的堆区是调佣操作系统的接口去申请空间的,每一次申请空间都要打断我们操作系统的执行然后去申请空间的,所以你频繁去申请,效率就会低,碎片多

这里写了个空指针就跟malloc是一样的了

见的动态内存错误

1.动态内存的野指针

前面如果p开辟没成功,收到了个空指针,如果你没判断是否是空指针,那么就会变成野指针

2,动态开辟内存的越界访问

3.对非动态内存的开辟内存使用free函数

是指向栈区的空间,是不能释放的

4.使用free释放一块动态内存开辟内存的一部分

找到最后一块地址,释放但是不行,释放必须全部释放

5.对同一块空间多次释放

不能多写,如果你想要多写的话,第二次就给p赋值一个空指针

这样才可以多写,当我们free里面放空指针时相当于什么都没干

6.动态内存开辟忘记释放

当这个值等于5,这个内存就释放不了,这个程序就找不到这个内存了

p是一个指针,str传过去,p这个指针开辟一块放NULL,接下里malloc开辟100个字节的空间的起始地址赋值给p,

然后p返回主函数的时候销毁了,这个临时变量销毁了,然后开辟100个字节的起始地址就找不到了,存在了内存泄漏,str就是空指针了,拷贝函数会报错,打印都打印不了

修改‘’

临时创建的变量,返回地址,当他的变量销毁,他就是个野指针

指针不初始化就会造成随机访问,如果把一个值放到这个指针变量里面就是野指针

  • 18
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值