一道很离谱的坑题

1.题目的展示

最近看到了一道非常坑的题目,如下

在VS2022、X86、Debug的环境下,编译器不做任何优化的话,下⾯代码执⾏的结果是啥?

#include <stdio.h>
int main()
{
  int i = 0;
  int arr[10] = {0};
  for(i=0; i<=12; i++)
 {
   arr[i] = 0;
   printf("hehe %d\n",i);
 }
  return 0;
}

 看到这段代码,第一反应就是会发生数组越界访问,因此可能认为这段代码会崩溃,事实上,可能在其他环境下确实是这样,但是在上述 VS2022、X86、Debug的环境下,会发生另一个奇特的现象。

可以看到死循环了。

2.猜想

可以看到死循环中i每次变成11后就变回了0,让我们调试一下看看

这是i==11时的情况

当我们结束第11次循环后,进行到图中137行代码时,惊奇的发现arr[i]变得和i的值一样了!

这引发了一个猜想:难道i和arr[11]的地址是一样的?

3.简单解释

要验证这个猜想是否正确,我们先来了解下面的知识。

我们经常会在研究问题时将内存划分为三个部分:栈区,堆区,静态区,栈区用于局部变量创建和函数栈帧创建,堆区用于动态内存分配,静态区存放全局变量和静态变量。这道题只创建了main函数的栈帧(函数再调用前需要在栈区开辟栈帧,main函数自然也不例外)和一些局部变量,自然要研究一下栈区。分析这段代码的执行过程。

栈区在使用时,一般都是先使用高地址,再使用低地址。那么就会先创建i ,在创建arr数组。

调出vs的监视窗口

可以发现确实i的地址比arr[0]大。

接下来代码继续执行,arr[1],arr[2],arr[3].......的值变为0,直到arr[9]变成0,然后就开始访问非法内存了,arr[10]实际上并不存在,若要继续执行arr[i]=0的指令,就会访问arr[9]后的一个地址,将其值变为0,像这样非法访问到arr[11]后,到了arr[12],在这时再执行arr[i]=0的指令,就发生了i和arr[12]都为12的情况。

 

我们通过监视窗口看到i的地址确实与arr数组首元素后第12个地址相同。那么就造成了i永远会小于或等于12,因此死循环。

4.简单回顾与总结

事实上,这道题的情况非常特殊,因为i的地址恰好与arr[0]的地址相差12,而其他很多情况下,i与arr[11]之间会有空隙,这样都无法造成死循环的结果。而这种巧合的出现,是依赖于VS2022、X86、Debug这种特定的环境。可以看到bug的产生是多么无孔不入,但凡换个环境,都不会死循环,而唯有借助调试的力量,才能有解决这种bug的机会。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值