如果这样声明,整数数组 arr 的维度是多少:
int arr[][2]={1,2,3};
不声明最高维度有什么用?
令我惊讶的是,您的声明:
int arr[][2]={1,2,3};
似乎是合法的。您可以在初始化程序中合法地省略内括号。例如,如果您想arr
显式定义 的边界并初始化其所有元素,您可以编写:
int arr[2][2] = { { 1, 2}, { 3, 4 } };
或者,等效地:
int arr[2][2] = { 1, 2, 3, 4 };
您也可以省略尾随元素,它们将被隐式设置为零。对于一维数组,这很简单;这:
int arr[4] = { 1, 2, 3 };
相当于:
int arr[4] = { 1, 2, 3, 0 };
如果你省略一个维度,它可以从初始化器中推断出来:
int arr[] = { 1, 2, 3, 4 }; // 4 elements
由于您定义arr
为 2 元素数组的数组int
,因此:
int arr[][2]={1,2,3};
相当于:
int arr[][2] = { { 1, 2 }, { 3 } };
初始化程序中有两个元素(每个元素都初始化一个 2 元素数组),因此相当于:
int arr[2][2] = { { 1, 2 }, { 3 } };
最后,您省略了最后一个初始化器子元素,因此它隐式为零:
int arr[2][2] = { { 1, 2 }, { 3, 0 } };
通常,省略维度和尾随初始化程序很有用,因为它可以让编译器找出某些事情。如果我写:
char message[] = "hello, world";
我不必计算字符串中的字符(并为终止添加 1 '\0'
)。计算机非常擅长计算事物;让人类做这项工作是愚蠢的。
同样,省略一些初始化程序可以让您只提供您需要的信息。通过 C99 添加的指定初始化程序,您甚至可以初始化结构的指定成员,并让编译器处理其他所有事情:
struct foo obj = { .something = 42 };
至于通过省略内部花括号来展平初始化器,我个人认为这没什么用,除了使用{ 0 }
初始化器来初始化整个数组或结构为零的特殊情况。特别是,对于多维数组,我发现显示数组的整个结构更加清晰。
根据最小括号规则(C11 中的 6.7.9p20),
列表中足够的初始化器被用于考虑子聚合的元素或成员或包含的联合的第一个成员;剩下的任何初始化器都将用于初始化当前子聚合或包含的联合所属的聚合的下一个元素或成员。
所以下面的声明是等价的:
int arr[][2]={1,2,3};
int arr[][2]={{1,2},{3}};
int arr[2][2]={{1,2},{3}};
至于为什么这是有用的:当初始化一个大的多维数组时,读者很可能很清楚每个子聚合有多少项;在这种情况下,不需要在子聚合之间提供括号。