首先我们来看一个程序:
#include<stdio.h>
int main()
{
int i = 0;
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
for (i = 0; i <= 12; i++)
{
printf("王笙\n");
arr[i] = 0;
}
return 0;
}
这个程序放到编译器中运行的话会造成死循环,那这时我们可能会想,数组的总元素是10,而循环语句中的i要循环到12才结束,那么肯定会出现数组越界报错啊,但为什么会出现死循环而不是数组越界,并且这个语句为什么会形成死循环呢?下面我来给大家解释。
首先我们得先从栈开始讲起(不知道什么是栈的小伙伴可以自己去搜),我们平时创建的局部变量就放在栈中,而栈的使用规则从高地址向低地址使用的。并且单个数组元素在栈中的地址相对大小和下标大小相同,也就是说变量i和数组在栈中的位置关系如下图所示。
高地址 |
i |
arr[9] |
arr[8] |
arr[7] |
6 |
5 |
4 |
3 |
2 |
1 |
低地址 0 |
那么这就明了了,当数组越界后,i一直++,直到i=12时,此时arr[12]与i,他们俩的地址一样,所代表的的内存空间一样,可以说arr[12]就是i了,此时给arr[12]赋值为0,也就是重新给i赋值为0,那么这个循环会重新开始,也就造成了死循环。
什么?你说为什么越界了不报错,而还要++呢。啊~这........咳咳,老师说这个程序因为忙着死循环就顾不上报错,估计他的意思是死循环可能占用了某些功能,或者压榨了空间内存等等,系统一直处于死循环没空报错吧!
这个空间的相对位置,不是我随便举个例子,而是在栈中他的确就是这么存放的(vs2019环境下)。不同的环境可能相对位置有些出入,但大致上就是这么个原理,如果把i改为循环到11,那么系统会出现越界报错,因为下标12的位置是i变量,但他只能循环到11,那么这时就不会出现死循环,就会报错了,当然如果改成循环到14,15,那么肯定会死循环的,因为比12大啊!哈哈!
补充:
vc6.0环境下<=10就死循环了,gcc编译器<=11就死循环了,vs2013环境下<=12 就死循环了。
debug版本的程序如果写成上述代码会出现这种问题,如果是release版本的程序则不会出现,因为系统会进行优化,一般情况下会使i变量的地址小于数组地址这样就不会出现这样的问题了。