标准是否定义了“a[i]”的类型,其中“a”是“T [M][N]”

Does the standard define the type for `a[i]` where `a` is `T [M][N]`?

本文关键字:其中 定义 标准 是否 类型      更新时间:2023-10-16

我偶尔会使用多维数组,并且很好奇标准(C11和/或C++11(对索引行为的看法,其"维度"比为数组声明的"维度"更少。

鉴于:

int a[2][2][2] = {{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}};

标准是否说明a[1]是什么类型,或者a[0][1],它是否合法,以及它是否应该按预期正确索引子数组?

auto& b = a[1];
std::cout << b[1][1];

m[1] 只是类型 int[2][2] 。同样m[0][1]只是int[2].是的,索引作为子数组的工作方式与您认为的方式相同。

标准是否定义了a T [M][N] a[i]的类型?

答案是肯定的。该标准基本上定义了所有表达式的类型,如果没有,它将是一个缺陷报告。但我想你对那种类型可能更感兴趣......

虽然标准可能没有明确提到您的情况,但规则是陈述的并且很简单,给定一个数组a T类型的N元素,表达式a[0]是类型T的左值表达式。在变量声明int a[2][2]中,a的类型是 2 个元素的数组,类型为 int 的两个元素的数组,应用上述规则意味着 a[0]2 个元素的数组的左值,或者您必须在程序中键入它:int (&)[2] .添加额外的维度不会影响机制。

我认为 C11 中的这个例子隐含地解释了它。

C11 6.5.2.1 数组下标

示例 考虑由声明定义的数组对象 int x[3][5]; 这里x是一个 3 × 5 的整数数组;更准确地说,x 是一个由三个元素对象组成的数组,每个对象都是一个由五个整数组成的数组。在表达式 x[i] 中,它等价于 (*((x) + (i)))x首先被转换为指向五个整数的初始数组的指针。然后根据x的类型调整i,这在概念上需要将i乘以指针指向的对象的大小,即五个int对象的数组。将结果相加并应用间接寻址以生成包含五个整数的数组。当在表达式x[i][j]中使用时,该数组又被转换为指向第一个整数的指针,因此x[i][j]产生一个int

在 C++11 8.3.4 数组中也有类似的情况

示例:考虑

int x[3][5];

这里x是一个 3 × 5 的整数数组。当表达式中出现x时,它将转换为指向(三个整数数组中的第一个(五位数组的指针。在表达式x[i]中,等价于 *(x + i)x首先被转换为指针,如前所述;然后 x + i 转换为 x 的类型,这涉及将i乘以指针指向的对象(即五个整数对象(的长度。结果已添加 以及应用于生成数组(五个整数(的间接寻址,该数组又转换为指向第一个整数的指针。如果有另一个下标,则相同的参数再次适用;这次的结果是一个整数。—尾注 ] —尾注 ]

要记住的关键点是,在 C 和 C++ 中,多维数组只是数组的数组(因此三维数组是数组的数组(。多维数组的所有语法和语义都遵循这一点(当然,也来自语言的其他规则(。

所以给定一个对象定义:

int m[2][2][2];

mint[2][2][2] 类型的对象(由两个数组组成的数组,每个数组由两个元素组成,每个元素由两个元素组成,每个元素都是两个int的数组(。

当你写m[1][1][1]时,你已经在评估mm[1]m[1][1]

表达式 m 是一个左值,引用类型为 int[2][2][2] 的数组对象。

m[1]中,数组表达式m被隐式转换为("衰减"到(数组的第一个元素的指针。这个指针的类型是 int(*)[2][2] 的,一个指向 int 的双元素数组的双元素数组的指针。 根据定义,m[1]等同于*(m+1);+1 m前进一个元素,并取消引用生成的指针值。因此,m[1]指的是类型为 int[2][2] 的对象(由两个数组组成的数组,每个数组由两个int元素组成(。

(数组索引运算符[]定义为对指针进行操作,而不是对数组进行操作。在像arr[42]这样的常见情况下,指针恰好是隐式数组到指针转换的结果。

我们重复这个过程 m[1][1] ,给我们一个指向两个int的数组(类型 int(*)[2] 的指针(。

最后,m[1][1][1]获取评估m[1][1]的结果并再次重复该过程,从而为我们提供一个引用 int 类型的对象的左值。这就是多维数组的工作方式。

只是为了增加轻浮性,像foo[index1][index2][index3]这样的表达式可以直接使用指针和数组。这意味着您可以使用指针和任意大小的分配来构造(几乎(像真正的多维数组一样工作的东西。这使您有可能拥有"参差不齐"的数组,每行中具有不同数量的元素,甚至是缺少的行和元素。但是,您可以管理每行甚至每个元素的分配和取消分配。

推荐阅读:comp.lang.c FAQ 的第 6 节。

旁注:有些语言中的多维数组不是数组的数组。例如,在 Ada 中(使用括号而不是方括号进行数组索引(,您可以拥有一个数组数组,像 arr(i)(j) 一样索引,或者您可以有一个二维数组,像 arr(i, j) 一样索引。C 是不同的;C 没有对多维数组的直接内置支持,但它为您提供了自己构建它们的工具。