2D数组索引 - 未定义的行为?

dra*_*sht 4 c arrays multidimensional-array undefined-behavior

我最近进入了一些代码,做了一些有问题的2D数组索引操作.以下面的代码示例为例:

int a[5][5];
a[0][20] = 3;
a[-2][15] = 4;
a[5][-3] = 5;
Run Code Online (Sandbox Code Playgroud)

上面的索引操作是否受到未定义的行为的影响?

Dre*_*wen 6

这是未定义的行为,这就是原因.

多维数组访问可以分解为一系列单维数组访问.换句话说,表达式a[i][j]可以被认为是(a[i])[j].引用C11§6.5.2.1/ 2:

下标操作符的定义[]E1[E2]相同(*((E1)+(E2))).

这意味着以上内容完全相同*(*(a + i) + j).在C11§6.5.6/ 8之后关于添加整数和指针(强调我的):

如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出; 否则,行为未定义.

换句话说,如果a[i]不是有效索引,则行为立即未定义,即使"直观" a[i][j]似乎是入境的.

所以,在第一种情况下,a[0]是有效的,但以下[20]不是,因为类型a[0]int[5].因此,索引20超出范围.

在第二种情况下,a[-1]已经超出界限,因此已经是UB.

但是,在最后一种情况下,表达式a[5]指向一个超过数组最后一个元素的表达式,根据§6.5.6/ 8有效:

...如果表达式P指向数组对象的最后一个元素,则表达式(P)+1指向数组对象的最后一个元素之后的一个...

但是,在同一段后面:

如果结果指向数组对象的最后一个元素之后,则不应将其用作已计算的一元*运算符的操作数.

因此,虽然a[5]是一个有效的指针,但是解引用它会导致未定义的行为,这是由最终[-3]索引引起的(其也是越界,因此是UB).

  • @mafso 实际上,`a[5]-3` 意味着`a + 5` 被取消引用。正如我提到的,`a[5][-3]` 等价于 `*(*(a + 5) - 3)`;表达式 `*(a + 5)` 是 UB。 (2认同)