2

以下代码无法编译:

int main() {
  int a[][] = { { 0, 1 },
                { 2, 3 } };
}

产生的错误信息是

error: declaration of 'a' as multidimensional array must have bounds for all dimensions except the first
int a[][] = { { 0, 1 },
           ^

这是标准规定的吗?如果是这样,那是为什么?我认为在这里推断界限会很容易。

4

1 回答 1

4

这是标准规定的吗?

嗯,是的。

§8.3.4/3 当多个“array of”规范相邻时,创建多维数组类型;只有第一个指定数组边界的常量表达式可以省略。除了允许不完整对象类型的声明外,在某些情况下,在函数参数的声明中可以省略数组绑定(8.3.5)。当声明符后跟初始化器(8.5)时,也可以省略数组绑定。在这种情况下,边界是根据提供的初始元素(例如N)的数量(8.5.1)计算的,标识符的类型D是“数组N T”。此外,如果在指定边界的同一范围内存在实体的先前声明,则省略的数组边界将被视为与先前声明中的相同,并且对于 a 的静态数据成员的定义也是如此班级。

如果是这样,那是为什么?

一方面,不能从不完整的类型(void例如)构造数组。未知界限数组是这些不完整类型之一:

§8.3.4/1 ...数组类型的对象包含一个连续分配的非空N类型子对象集T。除以下说明外,如果省略常量表达式,则标识符的类型D 为“ derived-declarator-type-list array of unknown bound of T”,一个不完整的对象类型。...

§8.3.4/2 数组可以由一种基本类型(除了void)、指针、指向成员的指针、类、枚举类型或另一个数组构成。

此外:

§3.9 已声明但未定义的类、某些上下文 (7.2) 中的枚举类型、大小未知或元素类型不完整的数组,是未完全定义的对象类型45 ...

45) 不完全定义的对象类型的实例的大小和布局是未知的。

我认为在这里推断界限会很容易。

初学者常犯的一个错误是,编译器有神奇的力量。编译器使用它已经拥有的信息,它不会凭空创建信息。如果你要求它创建一个大小未知的对象,它根本就做不到。请参阅以下示例:

只有最里面的维度可以省略。数组中元素的大小是根据给定数组变量的类型推导出来的。因此,元素的类型必须具有已知的大小。

  • char a[] = { ... };具有大小为1(8 位)的元素(例如a[0]),并且大小未知。
  • char a[6] = { ... };元素的大小为1,大小为 6。
  • char a[][6] = { ... };具有大小为6 的元素(例如a[0],它是一个数组),并且大小未知。
  • char a[10][6] = { ... };具有大小为6 的元素。大小为 60。

不允许:

  • char a[10][] = { ... };将有 10个未知大小的元素。
  • char a[][] = { ... };将有未知数量的未知大小的元素。

资源

于 2016-01-24T07:33:54.663 回答