昨天晚上,我正在给之前获奖的同学发奖品,正在进行中的时候,看到黄兄推送了一篇文章,里面讲到数组越界会导致无限循环。
关于抽奖看这篇文章《Linux进程管理数据结构》,以后也会不定期抽奖,今年多赚点钱,过年的时候,希望给大家抽一个大奖,喜欢的读者使劲给转发点赞,关注,未来是你们的,大奖也是你们的,感谢支持,不喜欢的请轻拍。过年抽奖我还是很期待的,每年公司的年会抽奖的时候,我总是能小中一把,有一年我还中了个一等奖,不知道大家对一等奖什么概念,中一等奖的概率非常低,集人品运气于一身的,我当时酝酿了全宇宙的力量,不说了,发功的时候真的非常累。
![51d10db4cbaf7625d7c53fbe148c0514.png](https://i-blog.csdnimg.cn/blog_migrate/d178c3c2f8e951aacbbb6dbfb623d33e.jpeg)
就是这个截图,我看了下,感觉有点意思,赶紧就自己敲下代码看看是怎么回事,可惜的是,我怎么也没看到出现无限循环啊。
代码如下:
#include "stdio.h"
int main()
{
int a[10] , i;
for(i = 1;i<= 10;i++){
a[i] = 0;
printf("%d %dn",i,a[i]);
}
return 0;
}
我先是在 dev c++ 上面试了下,结果如下
![66437b79c02ece08603ba102ef57da84.png](https://i-blog.csdnimg.cn/blog_migrate/fef9205f6af1da844d74e6017543234d.jpeg)
我这时候想,黄兄是不是忽悠我了,我要去成都叫他请我吃饭,然后我就给他评论
评论如下
![2861d2411a20832b93105ac75878f4eb.png](https://i-blog.csdnimg.cn/blog_migrate/bfaa0b996777151d099c4b1f80c2522d.jpeg)
竟然还有人给我的评论点赞了,啊啊啊啊啊啊~
不死心,赶紧又到Linux 下用 gcc编译 结果如下
![dc9e8936e0c60a5ffeba42ccea9ef20b.png](https://i-blog.csdnimg.cn/blog_migrate/b3df61866f337235294974c5d72a03a4.jpeg)
还是没有无线循环,我要死了,要是在群里面讨论这个,我要是说不出来会不会丢脸一个晚上。
赶紧用大招,看看i的地址和a[i] 的地址
![0fb008d75f46d007bfeda89503a7c12c.png](https://i-blog.csdnimg.cn/blog_migrate/98ac41c3bc964c6e551e6ed5ef0874ac.jpeg)
看这个图,i等于 10的时候, &a[10] 的地址和 i的地址还是独立的,虽然 a[10]已经超过了 数组的范围,但是并没有对i造成任何影响。
然后,我脑子一响,突然顿悟发现这个代码的问题所在了,这个数组越界没有越过去,要是越过去了,侵犯了i的领土「内存地址」了肯定就死循环了。
代码修改一下
#include "stdio.h"
int main()
{
int a[10] , i;
for(i = 1;i<= 12;i++){
a[i] = 0;
printf("%d %dn",i,a[i]);
}
return 0;
}
![045099b8550b097071dc97f3bafdd7e9.png](https://i-blog.csdnimg.cn/blog_migrate/c5f1699c2138289b9f317e58e489d783.jpeg)
看看内存分布
![3adfb99dc2205b21926a191d3a9bb0c7.png](https://i-blog.csdnimg.cn/blog_migrate/0957b0cadfcd26cd723f665dc43bb573.jpeg)
上图中 i = 10的时候,&a[10] 还没有越界到 &i「i的地址」,等下一次循环 i = 11的时候,那 &a[11] 就等于 &i 了,a[11] = 0,其实也就是 i= 0,死循环也就是这样来了。
从这个例子我们可以明白一点,为什么数组不能越界操作了没?如果真的是项目里面的代码,要是编译器也不给出提示,那么你即将构造一个非常难排查的bug出来。
如果对上面的地址还是不感冒,可以看看这个图片
![4266ebbee0dde7ba462314db1aa24929.png](https://i-blog.csdnimg.cn/blog_migrate/953dd171c7f5a78c90d605c46b830ef2.jpeg)
a我们定义的是10的大小,但是我们使用 a[10],这个是越界操作,越界操作编译器不会提示编译出错,但是这样操作就可能侵犯到i的地址,实际上把i给赋值了,所以会导致i=0,一直跳不出for循环。
我们正常一个数组遍历会这样写
#include "stdio.h"
int main()
{
int i;
int a[10];
for(i = 0;i < sizeof(a)/sizeof(a[0]);i++){
a[i] = 0;
printf("%d %d %p %pn",i,a[i],&i,&a[i]);
}
return 0;
}
编译器就好像法律,约束着人们的行为,但是有些法律没有涉及到的,就很容易被打擦边球。
最后用这个代码看看内存的增长「一个读者奉献的」
#include <stdio.h>
int main(void)
{
#pragma pack (4)
int j;
int a[10];
int i;
#pragma pack()
printf("a=%p &a[10]=%p &i=%p &a[-1]=%p &a[-2]=%p &j=%prn",a, &a[10],&i,&a[-1],&a[-2],&j);
return 0;
}
![1e3ea221c18f94a094f638f7862cac6e.png](https://i-blog.csdnimg.cn/blog_migrate/2b98ff112167d9017773ebf7f0cbd3e6.jpeg)