我偶尔会使用多维数组,并且很好奇标准对(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];
我偶尔会使用多维数组,并且很好奇标准对(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[i]
wherea
is的类型T [M][N]
?
当然。该标准基本上定义了所有表达式的类型,如果没有,那就是缺陷报告。但我猜你对那种类型可能更感兴趣......
虽然标准可能没有明确提及您的情况,但规则已经说明并且很简单,给定type 元素的数组a
,表达式是 type 的左值表达式。在变量声明中,类型为2 个元素的数组,类型为 2 个元素的数组,应用上面的规则意味着它是2 个元素的数组的左值,或者你必须在程序中键入它:添加额外维度不会影响机制。N
T
a[0]
T
int a[2][2]
a
int
a[0]
int (&)[2]
我认为 C11 中的这个例子隐含地解释了它。
C11 6.5.2.1 数组下标
示例考虑由声明定义的数组对象
int x[3][5];
这x
是一个 3 × 5 的整数数组;更准确地说,x
是一个由三个元素对象组成的数组,每个对象都是一个由五个整数组成的数组。x[i]
在等价于的表达式中(*((x) + (i)))
,x
首先将其转换为指向五个整数的初始数组的指针。然后i
根据 的类型进行调整x
,这在概念上需要乘以指针指向的对象的大小,即五个对象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++ 中,多维数组只是数组的数组(因此 3 维数组是数组数组的数组)。多维数组的所有语法和语义都遵循于此(当然也遵循该语言的其他规则)。
所以给定一个对象定义:
int m[2][2][2];
m
是一个类型的对象int[2][2][2]
(两个数组的数组,每个数组由两个元素组成,每个元素由两个元素组成,每个元素是两个int
s的数组)。
当您编写时,m[1][1][1]
您已经在评估m
和。m[1]
m[1][1]
该表达式m
是一个左值,引用类型为 的数组对象int[2][2][2]
。
在m[1]
中,数组表达式m
被隐式转换为(“衰减”到)指向数组第一个元素的指针。这个指针的类型是int(*)[2][2]
,一个指向 的二元素数组的二元素数组的指针int
。m[1]
根据定义等价于*(m+1)
; 前进+1
一个m
元素并取消引用结果指针值。som[1]
指的是一个类型的对象int[2][2]
(一个由两个数组组成的数组,每个数组由两个int
元素组成)。
(数组索引运算符[]
被定义为对指针,而不是数组进行操作。在常见的情况下,例如arr[42]
,指针恰好是隐式数组到指针转换的结果。)
我们对 重复这个过程,给我们一个指向两个s (类型为)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 没有对多维数组的直接内置支持,但它为您提供了自己构建它们的工具。