索引超过C数组的末尾

时间:2017-02-01 06:48:03

标签: c arrays undefined-behavior

我在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),那么程序的返回码就会增加。

2 个答案:

答案 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。如果你对这个主题感到好奇,你一定要看看它。