当前位置: 首页 > 知识库问答 >
问题:

通过指向其第一个元素的指针访问多维数组的中间是UB吗?

禹昆
2023-03-14

考虑以下代码

int data[2][2];
int* p(&data[0][0]);
p[3] = 0;

或等同地:

int data[2][2];
int (&row0)[2] = data[0];
int* p = &row0[0];
p[3] = 0;

p是指向数组行0中具有2个元素的第一个元素的指针,因此p[3]访问数组的末尾,根据7.6.6 [expr.add],这是UB:

  • 将具有整数类型的表达式 J 添加到指针类型的表达式 P 中或从中减去该表达式 J 时,结果的类型为 P。
    • 如果 P 的计算结果为空指针值,J 的计算结果为 0,则结果为空指针值。
    • 否则,如果 P 指向具有 n 个元素的数组对象 x 的元素 x[i],则表达式 P J 和 J P(其中 J 具有值 j)指向(可能是假设的)元素 x[i j],如果 0 ≤ i jn,表达式 P - J 指向(可能是假设的)元素 x[i−j],如果 0 ≤ i − jn
    • 否则,行为是未定义的。

    我在标准中没有看到对多维数组进行特殊处理的内容,因此我只能得出结论,上面的内容实际上是UB。

    我说的对吗?

    data声明为std::array的情况如何


共有1个答案

管和志
2023-03-14

是的,你说得对,没有什么可补充的。C型系统中没有多维数组,只有数组(任意数组的数组)。

访问数组大小以外的元素是未定义的行为。

 类似资料:
  • 它建议使用以下机制访问2D数组ARR[5][5]的第I第行的第J第元素: 根据我对指针的粗略了解,我知道数组的名称产生第0行的第0元素的地址,数组的任何整数增量都将产生下一行的基地址。我想在这个节骨眼之前一切都很好。 添加间接运算符是否会导致它产生该行的第I个元素,而不是第I个行的基元素的地址? 下面不应该是访问第I第行的第J第元素的代码吗? 在前面提到的情况下,增加arr i次将导致代码片段指向

  • 我正在学习如何在C中使用并写了以下示例: 问:是否保证在所有情况下指向一个结构的指针都是指向它的第一个元素的完全相同的指针? 在这种特殊的情况下,它能像我预期的那样工作,但我不确定它是否能得到保证。编译器可以在开始时插入一些填充吗? 我唯一能找到的关于结构类型布局的是N1570的类型: 结构类型描述了一组按顺序分配的非空成员对象(在某些情况下,还包括一个不完整的数组),每个对象都有一个可选的指定名

  • 主要内容:指针数组和二维数组指针的区别二维数组在概念上是二维的,有行和列,但在内存中所有的数组元素都是连续排列的,它们之间没有“缝隙”。以下面的二维数组 a 为例: int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} }; 从概念上理解,a 的分布像一个矩阵: 但在内存中,a 的分布是一维线性的,整个数组占用一块连续的内存: C语言中的二维数组是按行排列的,也就是先存放

  • 7. 指向数组的指针与多维数组 指针可以指向复合类型,上一节讲了指向指针的指针,这一节学习指向数组的指针。以下定义一个指向数组的指针,该数组有10个int元素: int (*a)[10]; 和上一节指针数组的定义int *a[10];相比,仅仅多了一个()括号。如何记住和区分这两种定义呢?我们可以认为[]比*有更高的优先级,如果a先和*结合则表示a是一个指针,如果a先和[]结合则表示a是一个数组。

  • 如果一个数组中的所有元素保存的都是 指针,那么我们就称它为 指针数组。指针数组的定义形式一般为: dataType *arrayName[length]; 的优先级高于 ,该定义形式应该理解为: dataType *(arrayName[length]); 括号里面说明 是一个数组,包含了 个元素,括号外面说明每个元素的类型为 。 除了每个元素的数据类型不同,指针数组和普通数组在其他方面都是一样的

  • 主要内容:关于数组指针的谜题数组(Array)是一系列具有相同类型的数据的集合,每一份数据叫做一个数组元素(Element)。数组中的所有元素在内存中是连续排列的,整个数组占用的是一块内存。以 为例,该数组在内存中的分布如下图所示: 定义数组时,要给出数组名和数组长度,数组名可以认为是一个 指针,它指向数组的第 0 个元素。 在C语言中,我们将第 0 个元素的地址称为数组的首地址。以上面的数组为例,下图是 arr 的指向: