一、引入
下面的程序在VS编译器会出现什么问题?运行结果是什么?为什么?
#include <stdio.h> 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("hello\n"); } return 0; }
运行结果:
如下图:代码死循环
二、代码缺陷
上述代码有两个问题:
- 数组访问越界
- 死循环
三、为什么会死循环?
1、i和arr都是局部变量,在内存中局部变量都是存储在栈区的。
2、数组随着下标的增长,地址是由低到高变化的。
3、栈区的内存规定:先使用高地址处的空间,再使用低地址处的空间。
根据上述代码可知,程序会先在栈区中高地址处为变量i
开辟空间,再在栈区中由高到低依次为数组arr
开辟空间
如下图👇
通过调试我们可以在内存中观察到如下变化:
for循环中,i 的内容是从0,一直增加到12,而数组只有10个空间,因此会越界,每次访问arr数组i号位置时,都会将该位置内容设置为0,当访问到arr[12]时,也会将该位置内容设置为0,而位置恰好为i的位置,即arr[12]恰巧将i设置为0,因此造成死循环。
四、补充说明
上述代码在不同的编译器中具有不同的效果,并且与运行环境有关。
- 在VS2013/2019/2022的x86环境中,i和arr间相隔两个整形。即
i<=12
就死循环 - 在gcc中间空相隔一个整形。即
i<=11
就死循环 - 在VC6.0中间没有多余的空间。即
i<=10
就死循环
五、总结
在写代码的时候我们可能会遇到各种各样的问题:语法错误、编译错误、运行错误……
但是我们在制造Bug的同时也要努力成为一名 Bug终结者
。
学会发现问题,解决问题并且避免出现问题是一名合格程序员的基本素养。这就要求我们要掌握一定的调试技巧,养成良好的编程习惯。