我偶尔会使用多维数组,并且很好奇标准所说的(C11和/或C ++ 11)索引的行为,其“维度”小于为数组声明的索引。 / p>
假设:
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];
答案 0 :(得分:5)
m[1]
只是int[2][2]
类型。同样地,m[0][1]
只是int[2]
。是的,索引为子数组就像你想象的那样工作。
答案 1 :(得分:3)
标准是否定义了
a[i]
a
为T [M][N]
的{{1}}的类型?
当然。该标准基本上定义了所有表达式的类型,如果不是,则它将是缺陷报告。但我想你对那种类型更感兴趣......
虽然标准可能没有明确提及您的情况,但规则是明确的,给定a
N
个T
类型a[0]
元素的数组,表达式{{1} }是类型T
的左值表达式。在变量声明int a[2][2]
中,a
的类型是 2个元素的数组,其类型为int
类型的两个元素的数组,应用上述规则意味着a[0]
左值为2个元素的数组,或者您必须在程序中键入它:int (&)[2]
。添加额外的维度不会影响机制。
答案 2 :(得分:2)
我认为C11中的这个例子含蓄地解释了它。
C11 6.5.2.1 Array subscripting
示例考虑由声明
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 Arrays
示例:考虑
int x[3][5];
这里
x
是一个3×5的整数数组。当x
出现在表达式中时,它将转换为指向(三个中的第一个)五元数组整数数组的指针。在表达式x[i]
中,*(x + i)
等同于x
,x
首先转换为指针,如上所述;然后将x + i转换为i
的类型,其中涉及将{{1}}乘以指针所指向的对象的长度,即五个整数对象。结果被添加 和间接应用于产生一个数组(由五个整数组成),而这个数组又转换为指向第一个整数的指针。如果有另一个下标,则同一参数再次适用;这次结果是一个整数。 - 末端示例] - 结束注释]
答案 3 :(得分:1)
要记住的关键点是,在C和C ++中,多维数组只是一个数组数组(因此三维数组是数组数组的数组)。多维数组的所有语法和语义都遵循它(当然还有语言的其他规则)。
所以给定一个对象定义:
int m[2][2][2];
m
是int[2][2][2]
类型的对象(两个数组的数组,每个数组由两个元素组成,每个元素由两个元素组成,每个元素都是两个数组{ {1}} S)。
当您撰写int
时,您已经在评估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
引用类型m[1]
的对象(两个数组的数组,每个数组由两个int[2][2]
元素组成)。
(数组索引操作符int
被定义为在指针上操作,而不是数组。在像[]
这样的常见情况下,指针恰好是结果隐式数组到指针的转换。)
我们重复arr[42]
的过程,给我们一个指向两个m[1][1]
(类型为int
)的数组的指针。
最后,int(*)[2]
获取评估m[1][1][1]
的结果并再次重复该过程,为我们提供左值,引用类型为m[1][1]
的对象。这就是多维数组的工作原理。
只是添加到轻浮,像int
这样的表达式可以直接使用指针和数组。这意味着您可以使用指针和任意大小的分配来构造一些(几乎)像真正的多维数组一样的东西。这使您可以在每行中使用“不规则”数组,其中包含不同数量的元素,甚至是缺少的行和元素。但是,由您来管理每一行的分配和释放,甚至是每个元素。
推荐阅读:comp.lang.c FAQ的第6部分。
附注:有些语言中的多维数组不是数组数组。例如,在Ada中(使用括号而不是方括号进行数组索引),您可以拥有一个数组数组,索引类似foo[index1][index2][index3]
,或者您可以拥有一个二维数组,索引类似于{{1} }。 C不同; C没有对多维数组的直接内置支持,但它为您提供了自己构建它们的工具。