C/C++:这是未定义的行为吗?(二维阵列)

C/C++: Is this undefined behavior? (2D arrays)

本文关键字:阵列 二维 C++ 未定义      更新时间:2023-10-16

如果我以下列方式浏览二维数组的元素,这是未定义的行为吗?

int v[5][5], i;
for (i = 0; i < 5*5; ++i) {
     v[i] = i;
}

话又说回来,它甚至会编译吗?(我现在不能尝试,我不在家。如果没有,那么想象一下我以某种方式获得了指向第一个元素的指针并使用它而不是v[i].

从指向第一个元素的指针访问多维数组的元素是不属于第一个数组的元素的未定义行为 (UB)。

给定T array[n]array[i]是所有 i>= n 的直接前往 UB land。即使T U[m].即使它是通过指针。确实对数组有很高的要求(例如 sizeof(int[N]) == N*sizeof(int)),正如其他人所提到的,但没有明确规定例外,因此对此无能为力。

我没有官方参考,因为据我所知,C++标准将细节留给了 C89 标准,我不熟悉 C89 或 C99 标准。相反,我有一个参考 comp.lang.c 常见问题解答:

[

...]根据官方的解释,访问(&array[0][0])[x]的行为不是为x>= NCOLUMNS定义的。

它不会编译。

等价物越多越少

int v[5][5], *vv, i;
vv = &v[0][0];
for (i = 0; i < 5*5; ++i) {
     vv[i] = i;
}

int v[5][5], i;
for (i = 0; i < 5*5; ++i) {
     v[0][i] = i;
}

将编译。 我不确定它们是否是UB(实际上C90,C99和C++之间可能有所不同;混叠是一个棘手的领域)。 我会尝试以一种或另一种方式找到参考资料。

标准中很难找到任何明确指出这是未定义行为的参考。当然,该标准明确指出(C99 6.5.6 §8-9),如果你在数组之外进行指针运算,那就是UB。那么问题是,数组的定义是什么

如果将多维数组视为数组对象的数组,则它是 UB。但是,如果将其视为一个具有多个维度的数组,则代码将完全没问题。

标准附录J中还有一个有趣的未定义行为说明:

数组下标超出范围, 即使一个物体显然是 可使用给定的下标访问 (如左值表达式 a[1][7] 鉴于声明 int a[4][5]) (6.5.6).

暗示访问超出第一维范围的多维数组是未定义的行为。但是,附件不是规范性文本,6.5.6相当夸张。

也许有人可以找到数组对象和多维数组之间区别的明确定义?在那之前,我不相信这是UB。

编辑:忘了提到v[i]肯定不是有效的C语法。根据 6.5.2.1,v[i] 等效于 *(v+i),它是一个数组指针,而不是数组元素。我不确定的是,以v[0][too_large_value]访问它是否是UB。

这里v[i]代表5个元素的整数数组。整数数组由地址位置引用,根据您的"C"编译器可能是 16 位、32 位......

所以v[i] = i可能会在某些编译器中编译....但它绝对不会产生您想要的结果。

尖牙的答案是正确的v[i][j] = i...是最简单易读的解决方案之一。

其他可能是

int *ptr;
ptr = v;

现在,您可以循环访问此 PTR 以分配值

for (i = 0; i < 5*5; i++, ptr++) {
     *ptr = i;
}

这不会编译。

对于该行,您将收到以下错误:

v[i] = i;

错误:将"int"赋值为"int [5]"时的类型不兼容

从类似问题中给出答案:

http://www.velocityreviews.com/forums/t318379-incompatible-types-in-assignment.html

v 是一个 2D 数组。由于您只引用一个维度,因此最终得到的是指向底层数组的 char 指针,因此此语句试图将 char 常量分配给 char 指针。您可以使用双引号将常量更改为 C 样式字符串,也可以显式引用 v[i][0],这是我假设您的意图。