拥有一个 3x3 2d 数组并访问 array[1][3] 等于 array[2][0]?

mas*_*ato 4 c arrays multidimensional-array

基本上,我在课堂上遇到过这段代码:

#include <stdio.h>

int main() {

    int arr[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };

    printf("%d", arr[0][2]);
    printf("\n%d", arr[1][0]);

    printf("\n%d", arr[0][2 + 1]);
}
Run Code Online (Sandbox Code Playgroud)

我有点困惑,因为最后一个printf语句arr[0][2 + 1]等于arr[0][3],但由于我们的数组维度是 3x3,所以这使得我们的最大索引值仅为 2,从而arr[0][3]超出范围。但是当我运行这个东西时,它显示4,这与第二条语句相同printf,即arr[1][0],为什么会发生这种情况?

我期待类似的错误,它会告诉我它超出了范围,但它继续打印数组的下一个索引值。

dbu*_*ush 8

C 不对数组执行任何类型的边界检查。这就是它变得快速的部分原因。然而,这也意味着,如果您做了一些不应该做的事情,那么您的代码最终会触发未定义的行为

在这种情况下,arr[0][2 + 1]第二个数组元素越界,并且访问越界数组是未定义的行为。在二维(和更大)数组的情况下,每个子数组彼此相连。因此,您最终读取了下一个内存位置中发生的内容,该位置恰好是arr[1][0]

然而,并不能保证您所看到的总会发生。编译器在优化过程中会假设不存在未定义的行为,并根据该假设做出优化决策。

这种情况在 C 标准的 J.2 节中被明确提及为未定义行为的示例:

数组下标超出范围,即使对象显然可以使用给定的下标访问(如a[1][7]给定声明的左值表达式中int a[4][5])(6.5.6)。

  • @Dúthomhas 不,这不安全。如果我对“arr[0][3]”进行写访问,然后对“arr[1][0]”进行读访问,则编译器可以自由地假设“arr[1][0]”仍然有效初始值并可以相应地优化代码。不要编写依赖于未定义行为的代码。 (4认同)
  • ...但是,数组具有非常严格的对齐和别名要求,因此只要您不尝试访问数组之外​​的元素,就可以安全地假设您可以执行诸如环绕索引之类的愚蠢操作。 (2认同)