C / C ++:这是未定义的行为吗? (2D数组)

时间:2011-05-16 09:00:37

标签: c++ c arrays undefined-behavior

如果我按照以下方式浏览2D数组的元素,是不确定的行为?

int v[5][5], i;

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

然后,它甚至编译? (我现在不能尝试,我不在家。)如果没有,那么想象我以某种方式获得了指向第一个元素并使用taht而不是v[i]的指针。

5 个答案:

答案 0 :(得分:7)

从指向第一个元素的指针访问多维数组的元素是UB,表示不属于第一个数组的元素。

给定T array[n]array[i]是所有i> = n的UB-land直行。即使TU[m]。即使是通过指针。确实存在对数组的强烈要求(例如sizeof(int[N]) == N*sizeof(int)),正如其他人所提到的那样,但没有明确的例外情况,因此无法对此做任何事情。

我没有正式的参考资料,因为据我所知,C ++标准将详细信息留给了C89标准,而且我不熟悉C89或C99标准。相反,我引用了comp.lang.c FAQ

  

[...]根据官方解释,访问(&amp; array [0] [0])[x]的行为未定义为x&gt; = NCOLUMNS。

答案 1 :(得分:4)

它不会编译。

更少的等价物

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 ++之间可能有所不同;混叠是一个棘手的领域)。我会尝试以某种方式找到参考文献。

答案 2 :(得分:2)

这里v[i]代表5个元素的整数数组。 一个整数数组由一个地址位置引用,这取决于你的'c'编译器可能是16位,32位......

所以v[i] = i可以在一些编译器中编译....但它肯定不会产生你正在寻找的结果。

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

其他可能是

int *ptr;
ptr = v;

现在你可以迭代这个ptr来分配值

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

答案 3 :(得分:1)

很难在标准中找到任何引用明确指出这是未定义的行为。当然,标准明确指出(C996.5.6§8-9),如果你在数组之外做指针算术,那就是UB。那么问题是,数组的定义是什么?

如果多维数组被视为数组对象的数组,那么它就是UB。但如果它被视为具有多个维度的一个数组,则代码将完全正常。

标准附件J中另一个未定义的行为有一个有趣的注释:

  

数组下标超出范围,   即使一个物体显然也是如此   可以使用给定的下标访问   (如左值表达式a [1] [7]   在[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。

答案 4 :(得分:0)

这不会编译。

您将收到该行的以下错误:

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],这是我假设您的意图。