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

时间:2014-08-05 13:04:31

标签: c arrays multidimensional-array undefined-behavior

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

int a[5][5];
a[0][20] = 3;
a[-2][15] = 4;
a[5][-3] = 5;

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

3 个答案:

答案 0 :(得分: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)。

答案 1 :(得分:-1)

是的,这是未定义的行为。

答案 2 :(得分:-1)

带负索引的数组索引是未定义的行为。抱歉,a[-3]与大多数架构/编译器中的*(&a - 3)相同,并且在没有警告的情况下被接受,但C语言允许您向指针添加负整数,但不使用负值作为数组索引。诅咒甚至在运行时都没有检查过。

此外,在指针前面定义数组时,还有一些问题需要解决。您可以不指定第一个子索引,而不是更多,例如:

int a[][3][2]; /* array of unspecified size, definition is alias of int (*a)[3][2]; */

(实际上,上面是指针定义,而不是数组,只需打印sizeof a

int a [4] [3] [2]; / * 24个整数数组,大小为24 * sizeof(int)* /

当你这样做时,评估偏移的方法对于数组而言不同于指针,所以要小心。如果是数组,int a[I][J][K];

&a[i][j][k] 

位于

&a + i*(sizeof(int)*J*K) + j*(sizeof(int)*K) + k*(sizeof(int))

但是当你宣布

int ***a; 

然后a[i][j][k]与:

相同

*(*(*(&a+i)+j)+k),意味着您必须取消引用指针a,然后将(sizeof(int **))*i添加到其值,然后再次取消引用,然后将(sizeof (int *))*j添加到该值,然后取消引用它,并将(sizeof(int))*k添加到该值以获取数据的确切地址。

BR