一道2016年nice的校招笔试题引发的思考

x33g5p2x  于2021-11-23 转载在 其他  
字(1.0k)|赞(0)|评价(0)|浏览(145)

声明

原题

题目详细解析

运行结果:

题目解析:

结论1:

注意点1:

注意点2:

结论2:

注意点3:

注意点4:

注意点5:

声明

今天的题,并非是完全出自于nice的笔试原题,今天的这道题出自于《C陷阱和缺陷》,只是两道题有异曲同工之妙!

原题

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

问题:这段代码在vs2019上会出现什么现象?这种现象是由什么原因造成的?我们应该如何避免像这样的问题?

题目详细解析

运行结果:

出现了死循环,即在屏幕上不停的打印"hehe"。

题目解析:

(1)i和arr是局部变量,放在栈区上

(2)栈区上的使用习惯:先使用高地址处的空间,再使用低地址处的空间

(3)数组随着下标的增长,地址是由低到高变化的

由这三点可以画出这段程序的内存图来,当然,这还要区分具体的编译器!

结论1:

**arr[12]与变量i占用的是同一块空间,即地址值一样 **

如果arr和i之间的空间合适的话,就有可能使用的arr数组向后越界访问到了i,造成循环变量i的改变,最终死循环。

注意点1:

这个代码是严格依赖环境的,例如vc 6.0 中i和arr是连续的,在gcc编译器中,i和arr之间有一个空间。

注意点2:

虽然此程序越界访问了,但是由于程序进入了死循环,所以不会报错,但是一旦把i<=12改成了i<=11,程序就会在i=11的地方会停止下来,此时已经构成了越界访问,程序自然会报错。如下图所示:

 结论2:

死循环会掩盖程序中的某些错误,比如数组越界访问。

 注意点3:

当把int i = 0;与int arr[10] = {0};交换之后,程序将不会出现死循环,但是程序的越界访问报错是少不了的。

注意点4:

此时也应该注意一下debug与release版本的区别:

很明显,在debug版本下,i的地址值比arr[9]的要大,而在release版本下,i的地址要比arr[9]的地址值要小,在release版本下进行了某些优化,即杜绝了我们上述出现的死循环的情况,在这种情况下,即使数组越界,也不会影响到i的值。

注意点5:

这种优化是无差别的,即无论你的代码是否越界,都会进行这样的优化。

相关文章