浅析一道有趣的数组题
题目描述
对于一个共有10个整型元素的数组,从首元素开始,从前往后循环遍历,修改元素的值,打印字符串。
#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 world\n");
}
return 0;
}
运行结果
对于这个题目,咋一看给人的直觉就是执行13次循环,打印13次hello world;当然也有可能是这样一种结果:由于数组越界访问,所以将arr[9]的值改为0后,系统报错,没法运行,连调试都过不去。
然而,令人震惊的是,在VS 2013编译环境下,编译器竟然没有报错,运行起来了!运行的结果出乎意料,竟是疯狂打印hello world,死循环!!!
结果分析与讨论
下面由小涛给大家简单分析一波:
-
在C语言中,内存主要可以划分为:栈区,堆区,静态区等部分。
-
对于局部变量和数组,是在内存中的栈区开辟的。
-
栈区的使用特点是:先使用高地址空间,再使用低地址空间。
在这个案例中,由于先创建的是i变量,然后才是创建数组arr,故i的地址要比arr数组高。在VS 2013环境下,其内存开辟空间如下图所示(注意i的地址):
-
对于数组而言,其存储和空间的关系是:随着元素下标的增加,对应元素的地址也是由高到低变化的。
在此10个整型元素的数组arr中,arr[0]的地址最低,arr[9]的地址最低。
为什么运行的结果会是死循环呢?有必要对各数的地址进行探究一番。前面我们得到i的地址是0x010FFCD8,下面通过调试,对其他数据的地址查看如下:
我们惊人的发现:arr[12]位置的地址也是0x010FFCD8,这意味着什么?这不是就是说arr[12]和i放在内存中的同一个地址吗?如果把arr[12]的内容修改就会造成i的值被修改!结合我们得到的运行结果,这不是就能解释了嘛。
当i =12时,执行arr[12] = 0指令后,i也被修改成0了;判断条件i<=12恒成立,于是并没有结束循环,继续i = 0,1,2,3,4,5,6,7,8,9,10,11,12,0,1,2·····于是乎持续输出打印。
- 有一点需要注意,不同编译环境下,i和arr的空间间隔不一定是差3字节,亲测发现gcc编译器就不是这样的分布。
哈哈,破案了~~
狄大人对这波分析很是赞同啊,元芳也表示很佩服!哈哈~~
涨姿势咯,希望小伙伴们都有get到哦!