标准是否定义了“a[i]”的类型,其中“a”是“T [M][N]”
Does the standard define the type for `a[i]` where `a` is `T [M][N]`?
我偶尔会使用多维数组,并且很好奇标准(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];
m
是 int[2][2][2]
类型的对象(由两个数组组成的数组,每个数组由两个元素组成,每个元素由两个元素组成,每个元素都是两个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
类型的对象的左值。这就是多维数组的工作方式。
只是为了增加轻浮性,像foo[index1][index2][index3]
这样的表达式可以直接使用指针和数组。这意味着您可以使用指针和任意大小的分配来构造(几乎(像真正的多维数组一样工作的东西。这使您有可能拥有"参差不齐"的数组,每行中具有不同数量的元素,甚至是缺少的行和元素。但是,您可以管理每行甚至每个元素的分配和取消分配。
推荐阅读:comp.lang.c FAQ 的第 6 节。
旁注:有些语言中的多维数组不是数组的数组。例如,在 Ada 中(使用括号而不是方括号进行数组索引(,您可以拥有一个数组数组,像 arr(i)(j)
一样索引,或者您可以有一个二维数组,像 arr(i, j)
一样索引。C 是不同的;C 没有对多维数组的直接内置支持,但它为您提供了自己构建它们的工具。
- 如何定义自定义生成配置类型,其中通常是.exe的目标改为 DLL
- 如何测试 size_t -1 是否未定义,其中 size_t 为 0?
- 在C++中,创建'n'数量的对象的推荐方法是什么,其中n是用户定义的。我该怎么做?
- 编译一个自定义的tf操作,其中输入是5d张量
- C++ 从未在其中定义的函数访问类
- 拥有 std::map 的最佳方式,我可以在其中定义如果没有键时返回的内容
- c++ 编写一个 cosole 应用程序,您可以从中调用其中定义的函数
- 其中定义函数的静态局部变量对象
- 当在其中定义全局变量时,如何在.cpp中包含 C 样式的 .h
- c++类并在其中定义函数
- 其中定义了Qt的PointerToMemberFunction
- 其中定义了SYSTEM_INFORMATION_CLASS
- 其中定义了wxThreadEvent
- 其中定义了ConfigDSN
- 其中定义了_CPPLIB_VER,在visual studio中可修改吗
- 其中定义了open(char *filename, int access, int permission)
- 其中定义了int()为0
- 在其中定义仅用作私有成员变量的结构
- 查找在其中定义特定函数的库
- 其中定义了stry和其他C库函数(与声明相反)