动态内存4

动态内存里还有一个很重要的问题就是free会经常崩溃。

有时候会出现一种程序不free还正常运行,一free就崩溃,但如果将free完的程序放在dev里面就又好了,一放到vs2022里面就又崩溃了的情况。

那么崩溃的原因又有哪些,下面是一些比较常见的内存错误。从上往下的造成崩溃的概率依次减小。

1.数组越界。(找不到尾信息)往往不经意间就会有数组越界。比如你的下标有i+1,然后你把i+1的值赋值给i,控制i<=n(len),这里你的i+1就越界了。

2.崩溃往往容易在realloc函数中出现。因为realloc括号里的第二个参数是你要申请的新的总共内存字节大小,不是用总共的减去旧的所算的新增加的字节大小。例如,我们原本有40个字节,但发现不够用,现在需要80个字节,那么realloc后面就应该写80,而不是80-40出来的40.

也就是动态内存的这几个函数十分的简单粗暴,你只需要告诉它你一共需要多少内存,不需要算来算去。

3.指针移动。(找不到头信息

4.重复释放同一内存。就像同一套房不能卖给两家人。

1.例如下面代码

这里将 i<n 写成了 i<=n ,就使得多出了一个 i+1 造成数组越界了。我们可以看到下面错误原因

发现了应用程序的内存多写在了堆内存的结尾部的后面,一般报这个错就是说越界了。

但如果我们不free,就不会发现,程序就还是正常运行如下

还有一种越界是malloc后面括号里忘写了sizeof,只写了n,那就是才申请了n个字节,但你会以为你申请了n个格子,但实际上你只申请了n/sizeof个格子,就会远远越界。

3.例如下列代码

这个不free也没有问题出现,一free就出现问题。因为i=0,指针一开始指向数组的开头,前面将p当做数组来用没有问题是因为数组p是不动的,而现在的指针p是移动的,每一次赋值后都加加,当p一直走数组操作完了后,这个指针就指到了这个数组的尾巴上面去了,现在你再去free的时候,这个p的指针就不再是原来的指针了。

那么就有两个问题,指针为什么不能移动;数组越界后free为什么会崩溃。        这个根本原因会在内存池里面讲。

我们可以发现free这个函数很强大,无论p这个数组里面有多少字节,你也没有告诉free数组p里面有多少字节,有多少长度,但是它都能给你free掉。我们以前说数组传参一定要传首地址和数组长度,那么问题就是我们并没有告诉free数组长度。那free是怎么做到的呢,这就是动态内存跟我们普通的数组有的一个区别。这个p在动态分配的时候就把它的内存大小标记了一下。也可以说是我拿个小本子,把我自己的内存大小登记一下,然后我就不需要你再传参告诉我这个p有多大了。这样当你一free的时候,例如在1000的位置上我记得偏移四个字节后看到标记,即看小本子是记的是多大,然后我就知道free多少字节了。标记就是类似下图两边的标记。

而这时如果你的指针移动了,那么我还想回到我刚刚的指针位置看一下标记大小,那这个数据就肯定不对了。因为你的指针移动走了,我去哪找我的小本子标记。假如说你的指针走到了一个别的地方,但我们大家本来约定好每次指针偏移四个字节就能知道标记了,但要是在新移动的现在的位置再往后偏移四个字节后,那标记的数据肯定是找不见了,那找不到free多少长度了就只能死了崩溃了。

还有一个尾巴,尾巴也是一样,例如刚才的越界就会把尾巴踩掉,越界了就会把后面的数据篡改掉了,但尾巴在释放的时候也是要用的,具体的作用在内存池里面分析。因为内存合并的时候就需要用到尾巴,所以free的时候尾巴不能被踩掉,一踩掉就不能合并了,程序就会崩溃了。

所以移动指针会崩溃就是因为找不到头信息了。内存大小就收藏在这个头信息里面,里面其他的东西我们先不管。

4.下图就是重复释放两次内存

有时不经意间就会出现重复释放,例如刚好两个指针指向同一段内存的时候,你本来以为p是p,q是q,你将两个指针都一释放后这段内存就被重复释放两次了。        这个后面在C++里面有个叫赋值符号要重载的,就是有的类要重载赋值,如果不重载的话就可能会出现浅拷贝,出现浅拷贝后在销毁的时候就会统一的内存销毁两次。

举例你有一个p申请了动态内存,然后你把这个p的值复制给了q,你用p里面的数据或者用q里面的数据你以为它们是分开单独的,其实它们指向的是同一个内存,用完后你分别释放p和q就重复释放了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值