我正在阅读 Kochen 的《Programming in C》一书,我很困惑他在哪里解释了多维数组的初始化
特别是,我不明白下面这句话的含义注意,在这种情况下,需要内部的大括号对来强制正确初始化。没有它们,前两行和第三行的前两个元素将被初始化。我不确定这句话到底是什么意思。
我正在阅读 Kochen 的《Programming in C》一书,我很困惑他在哪里解释了多维数组的初始化
特别是,我不明白下面这句话的含义注意,在这种情况下,需要内部的大括号对来强制正确初始化。没有它们,前两行和第三行的前两个元素将被初始化。我不确定这句话到底是什么意思。
这是因为该M[4][5]
数组有 20 个元素(4 行,5 列),并且如果未使用内部大括号对显式指定行,则初始化的默认顺序是逐行。
这意味着如果您分配与简单线性列表相同的 12 个值,而没有内部的大括号对,那么值将分配给前两行(2*5 = 10 个元素)加上第三行的前 2 列排。(您未显式初始化的剩余 8 个数组元素将自动设置为 0。)
C 编译器知道每行只有 5 列,并且每次达到 5 列边距时会自动将数字列表包装到下一行。因此,
int M[4][5] = {10, 5, -3, 9, 0, 0, 32, 20, 1, 0, 0, 8};
被理解为
int M[4][5] =
{
{10, 5, -3, 9, 0},
{ 0, 32, 20, 1, 0},
{ 0, 8, 0, 0, 0},
{ 0, 0, 0, 0, 0}
};
您可以通过使用内大括号将 12 个值分隔成您自己喜欢的行来覆盖默认顺序(但对于这个数组的定义,每行自然不超过 5 列M
)。
例如,当您使用内大括号将相同的 12 个值分成四组 3 时,就像书中的页面显示的那样,那么这些内大括号被解释为初始化多维数组的单独行。结果将初始化数组的四行,但仅初始化这四行的前 3 列,将其余列设置为零(每行末尾有两个空白零值)。
也就是说,C编译器知道数组M
每行有5列,所以它会将缺失的列添加到每一行,这样每行就有5列,所以数组总共有20个值:
int M[4][5] =
{
{10, 5, -3},
{ 9, 0, 0},
{32, 20, 1},
{ 0, 0, 8}
};
被理解为
int M[4][5] =
{
{10, 5, -3, 0, 0},
{ 9, 0, 0, 0, 0},
{32, 20, 1, 0, 0},
{ 0, 0, 8, 0, 0}
};
使用内部大括号,数组看起来像这样:
10 5 -3 0 0
9 0 0 0 0
32 20 1 0 0
0 0 8 0 0
因此,在每一行中,最后 2 个值为零(因为您没有为它们设置值。如果没有内括号,数组将如下所示:
10 5 -3 9 0
0 32 20 1 0
0 8 0 0 0
0 0 0 0 0
只有前 12 个元素会成为给定值,其余元素将为 0。
由于所有数组在内部都表现为一维数组,因此您必须用括号指定您初始化的确切行。
举个例子:
int a[4][5] = {
{ 1, 2, 3 }, // those are the elements of the first row.
// only the first 3 elements are initialized
{ 1, 2, 3, 4} // those are the elements of the 2nd row.
// only the first 4 element are initialized
};
// everything else will be equal to 0
尽管
int a[4][5] = { 1, 2, 3, 1, 2, 3, 4}; // this will initialize first 5 elements
// of the first row and then continue
// with the 2nd one making the first 2
// elements to be 3 and 4 respectivly
// everything else will be equal to 0
C 中的多维数组只是一维数组的“语法糖”。当您分配一个 4 x 5 int 数组时,您实际上是在为内存中的一行中的 20 个整数分配空间。这些整数存储为第一行的所有元素,然后是第二行的所有元素,依此类推。
如果没有内大括号,您的初始化程序也是 1D,表示您要初始化这 20 个整数中的前 12 个,即前两行和第三行的前两个元素。
看看具体的例子会有所帮助。
多维数组是数组的数组。(它不仅仅是长一维数组的语法糖。)
在初始化程序中,省略尾随元素(隐式初始化为零)和内部花括号是合法的。
鉴于:
int arr[2][2];
完整的初始化可能如下所示:
int arr[2][2] = { { 10, 20 }, { 30, 40 } };
您可以(但恕我直言不应该)省略内括号:
int arr[2][2] = { 10, 20, 30, 40 };
并且编译器会将初始化程序的元素映射到arr
.
如果省略尾随元素:
int arr[2][2] = { { 10, 20 } };
然后第二行被隐式初始化为{ 0, 0 }
.
或者你可以写:
int arr[2][2] = { { 10 }, { 20 } };
这会将值 10 和 20 分配给每行的第一个元素,而不是第一行。
同样,如果没有看到示例,很难准确地说出作者在说什么,但是内括号告诉编译器开始新行,即使第一行不完整。
如果您为所有 4 个元素(或更一般地说是所有X * Y
元素)提供初始化程序,则内大括号不是绝对必要的;无论哪种方式,元素的顺序都是相同的。
就个人而言,我发现包含所有内部大括号更清楚,因为它们反映了您正在初始化的实际结构。
(那么除了语法糖之外,一维数组和二维数组有什么区别?鉴于上面的声明arr
,如果它与一维数组相同,那么arr[0][2]
将与 相同arr[1][0]
,第二个索引溢出到第二行。它在实践中可能以这种方式工作,但实际上arr[0][2]
具有未定义的行为。这确实有实际后果;优化编译器可能会假设所有边界都在范围内,如果违反该假设,则会生成行为不端的代码.)
另请参阅此问题。