【问题标题】:indexing past the end of C arrays [duplicate]索引超过C数组的末尾[重复]
【发布时间】:2017-06-17 19:58:33
【问题描述】:

我用 C 编写了一个简短的程序,只是为了看看当索引超出数组末尾时会发生什么。

我发现它主要产生随机值(我知道它们实际上不是随机的),直到它每次产生 0 的点(在这种情况下超过末尾的 52 个索引)。超过此点的每个值都会导致程序崩溃。为什么是这样?程序分配的内存空间结束了吗?

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),那么程序的返回码就会上升。

【问题讨论】:

  • 这是未定义的行为!!! C 语言标准没有规定程序在此操作之后的行为(例如,与 Java IndexOutOfBound 异常相反)。
  • 它从堆栈中掉了出来,崩溃了。如果您尝试读取现有地址崩溃。如果它掉出来,堆就会崩溃。如果试图写出bonaryes,会损坏内存处理程序

标签: c arrays undefined-behavior


【解决方案1】:

...只是想看看当索引超出数组末尾时会发生什么

试图访问超出限制的内存,调用undefined behavior。任何事情都可能发生,任何事情都可能发生。

在您的情况下,出于某些的原因,最多可以从进程访问索引 52 的内存地址,因此它允许访问。超过 52 的索引指向未分配给您的进程地址空间的内存区域,因此会引发访问冲突,从而导致段错误。这完全不是确定性行为,而且您无法依赖调用 UB 的程序的输出。

【讨论】:

【解决方案2】:

访问数组边界以外的数组元素(在0 之前或从其大小开始)是未定义的行为。它可能会或可能不会产生值,可能会导致程序突然结束,可能会导致您的系统停止、重新启动或着火......

现代系统试图通过内存保护、用户空间限制等将未定义的行为限制在合理的范围内,但即使是用户空间代码错误也会产生可怕的后果:

  • 起搏器与其计时值混淆可能会导致过早死亡;
  • 银行软件溢出数组边界可能会覆盖账户余额信息,将不计其数的美元记入某个随机账户。
  • 您的自动驾驶汽车的行为可能比醉酒司机更糟糕...
  • 想想核电站控制软件、飞机仪器、军事材料......

毫无疑问应该避免未定义的行为

关于退出状态,你的程序使用了一个过时的语法来定义main(),隐式返回类型,在C99及更高版本中不再支持,但不返回任何东西,这意味着它的返回值可以是任何随机值,包括每次执行的不同值。 C99 为 main() 函数指定了一个 kludge,并在 main() 的末尾强制一个隐式的 return 0;,但依赖它是不好的风格。

同样,在没有适当原型的情况下调用 printf() 是未定义的行为。您应该在函数main() 的定义之前包含<stdio.h>

最后,ar[0]ar[1]main() 中初始化,但 ar[2]ar[3] 不是。请注意,访问未初始化的值也有未定义的行为。这些值可以是任何东西,您将其描述为随机值,但在某些系统上,它们可能是陷阱值,仅通过读取它们就会导致未定义的行为。

可以使用一些非常方便的工具来跟踪简单和复杂程序中的此类问题,最著名的是valgrind。如果您对这个主题感到好奇,您一定要看看它。

【讨论】:

    猜你喜欢
    • 2020-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-17
    • 2023-03-23
    • 1970-01-01
    • 2010-10-28
    • 2020-01-06
    相关资源
    最近更新 更多