我在C中编写了一个简短的程序,只是为了看看当你索引数组末尾时会发生什么。
我发现它主要产生随机值(我知道它们实际上并不是随机的)直到一个点(在这种情况下52个索引超过结束),它每次产生0。超过这一点的每个值和程序崩溃。为什么是这样?它是程序结束分配内存空间的吗?
main()
{
int ar[4];
ar[0] = 99;
ar[1] = 45;
printf("array: %d, %d random value: %d", ar[0], ar[1], ar[55]);
}
编辑:我还发现如果我改变这个值总是最终为0(即ar [55] = 1000),那么程序的返回码就会增加。
答案 0 :(得分:8)
...只是为了看看索引超过数组末尾时会发生什么
尝试访问超出范围的内存,调用undefined behavior。任何事情都可能发生,只是一切。
在您的情况下,对于某些原因,可以从进程访问最高索引52的内存地址,因此它允许访问。索引超过52个点到未分配给您的进程地址空间的内存区域,从而引发访问冲突导致段错误。这完全是不确定性行为,并且您无法依赖调用UB的程序的输出。
答案 1 :(得分:3)
访问数组边界之外的数组元素(在0
之前或从其大小开始)是未定义的行为。它可能产生或不产生值,它可能导致程序突然结束,它可能导致您的系统停止,重启或着火...
现代系统试图通过内存保护,用户空间限制等将未定义的行为限制在合理的限制范围内,但即使是用户空间代码错误也会产生可怕的后果:
毫无疑问,应该避免未定义的行为。
关于退出状态,您的程序使用了过时的语法来定义main()
,隐式返回类型,在C99及更高版本中不再支持,但不返回任何内容,这意味着它的返回值可以是任何随机值,包括每次执行的不同值。 C99为main()
函数指定了一个kludge,并在return 0;
的末尾强制使用隐式main()
,但依赖它是不好的风格。
同样,在没有适当原型的情况下调用printf()
是未定义的行为。您应该在函数<stdio.h>
的定义之前添加main()
。
最后,ar[0]
和ar[1]
在main()
初始化,但ar[2]
和ar[3]
不是。请注意,访问未初始化的值也具有未定义的行为。这些值可以是任何内容,您描述为随机值,但在某些系统上,它们可能是陷阱值,只需读取它们就会导致未定义的行为。
一些非常方便的工具可用于在简单和复杂的程序中跟踪此类问题,最值得注意的是valgrind
。如果你对这个主题感到好奇,你一定要看看它。