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

时间:2013-08-01 13:49:32

标签: c++ c multidimensional-array language-lawyer

我偶尔会使用多维数组,并且很好奇标准所说的(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];

4 个答案:

答案 0 :(得分:5)

m[1]只是int[2][2]类型。同样地,m[0][1]只是int[2]。是的,索引为子数组就像你想象的那样工作。

答案 1 :(得分:3)

  

标准是否定义了a[i] aT [M][N]的{​​{1}}的类型?

当然。该标准基本上定义了所有表达式的类型,如果不是,则它将是缺陷报告。但我想你对那种类型更感兴趣......

虽然标准可能没有明确提及您的情况,但规则是明确的,给定a NT类型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)等同于xx首先转换为指针,如上所述;然后将x + i转换为i的类型,其中涉及将{{1}}乘以指针所指向的对象的长度,即五个整数对象。结果被添加   和间接应用于产生一个数组(由五个整数组成),而这个数组又转换为指向第一个整数的指针。如果有另一个下标,则同一参数再次适用;这次结果是一个整数。 - 末端示例] - 结束注释]

答案 3 :(得分:1)

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

所以给定一个对象定义:

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

mint[2][2][2]类型的对象(两个数组的数组,每个数组由两个元素组成,每个元素由两个元素组成,每个元素都是两个数组{ {1}} S)。

当您撰写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这样的表达式可以直接使用指针和数组。这意味着您可以使用指针和任意大小的分配来构造一些(几乎)像真正的多维数组一样的东西。这使您可以在每行中使用“不规则”数组,其中包含不同数量的元素,甚至是缺少的行和元素。但是,由您来管理每一行的分配和释放,甚至是每个元素。

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

附注:有些语言中的多维数组不是数组数组。例如,在Ada中(使用括号而不是方括号进行数组索引),您可以拥有一个数组数组,索引类似foo[index1][index2][index3],或者您可以拥有一个二维数组,索引类似于{{1} }。 C不同; C没有对多维数组的直接内置支持,但它为您提供了自己构建它们的工具。