通过调试解释C语言程序死循环问题

注:此代码非常依赖编译器,环境不一样,效果也可能不一样,虽然效果可能不同,但底层原理不变,思路才是重中之重!这里本人使用的是vs2019编译器。

1. 正文

这里有这样一段代码:

int main()
{
    
    
    int i = 0;
    int arr[] = {
    
     1,2,3,4,5,6,7,8,9,10 };
    for (i = 0; i <= 12; i++)
    {
    
    
        arr[i] = 0;
        printf("666\n");
    }
    return 0;
}

1.1 代码运行结果

此时代码运行的结果是什么呢?
通过执行代码我们发现,程序会死循环的打印666。
程序死循环
但是为什么程序不是报错,而是死循环呢?接下来我们通过调试来观察代码执行的过程来分析死循环的原因。

1.2 调试过程

开始调试,打开监视窗口,监视i和arr值的变化。
调试1
调试2

我们发现当i<=9时,代码运行一切正常,屏幕上打印出10组666,但当我们继续调试,当i=10的时候就会发生越界
越界之后会发生什么现象?我们继续添加arr[10]和arr[11]来监视。
调试3
调试4
此时我们会发现arr[10]和arr[11]依然被修改了,而且printf函数也执行了,屏幕上此时打印出12组666。

1.3 发现死循环原因

那我们继续添加arr[12]来监视,代码继续调试,会发生什么?
调试5
这时候,arr[12]被修改了,但与此同时,i也被修改为0。
我们已经找到了死循环的原因,那就是改变arr[12]为0的同时,i也会被改变为0,导致i永远永远不会超过12,代码死循环。

1.4 为什么i会改变?

到这里也许大家都会有一个疑问,那就是为什么i会被同时改变呢?我们不妨大胆猜测,是不是因为i和arr[12]的地址相同导致的?
我们在监视窗口添加&i和&arr[12]就会发现他们两个的地址确实相同!
调试6
再次说明:不是所有编译器的结果都是如此。

1.5 底层原理

大家可能会有疑问,“为什么arr[12]和i的地址会一样?”
我来为大家浅浅的讲解一下计算机的内存分配和局部变量的存储大家就会明白了。
计算机的内存会划分为三个区域,分别为:栈区、堆区、静态区。
其中栈区是用来存放局部变量和函数形参的。
由于i和arr都是局部变量,所以会被存储在栈区中。
栈区的使用习惯是:先使用高地址处的空间,再使用低地址处的空间。
数组随下标的增长,地址是由低到高变化的。
下面我画个图来帮大家理解。
图解1
从图中不难看出,这里i和arr相差两个整型空间,所以,当我们越界访问arr的时候,arr[12]正好和i的地址一样,所以此时修改arr[12]也会同时修改i,这也就是为什么代码会死循环。

2. 总结

此代码是先创建i再创建arr,又因为i和arr都是局部变量,所以会被存储到栈区中。
栈区的使用习惯是:先使用高地址的空间,再使用低地址的空间,而且数组随着下标的增长,地址的变化是由低到高的,所以i存储的地址就会比arr的地址”高“。
如果在内存分配时,i和arr中间恰好空两个整型空间(编译器不同,结果不同,vc6.0编译器中,i和arr中间没有空间,而gcc编译器中,i和arr中间空一个整型空间),那么在循环的过程中,当数组向后越界访问时,就有可能出现改变arr[12]时,同时改变i这种现象,从而导致程序死循环。

猜你喜欢

转载自blog.csdn.net/qq_43188955/article/details/129759554
今日推荐