11

我正在阅读 Kochen 的《Programming in C》一书,我很困惑他在哪里解释了多维数组的初始化

这里

特别是,我不明白下面这句话的含义注意,在这种情况下,需要内部的大括号对来强制正确初始化。没有它们,前两行和第三行的前两个元素将被初始化。我不确定这句话到底是什么意思。

4

5 回答 5

15

这是因为该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}
};
于 2013-08-09T23:51:20.543 回答
8

使用内部大括号,数组看起来像这样:

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。

于 2013-08-09T23:53:52.633 回答
7

由于所有数组在内部都表现为一维数组,因此您必须用括号指定您初始化的确切行。

举个例子:

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
于 2013-08-09T23:55:25.660 回答
3

C 中的多维数组只是一维数组的“语法糖”。当您分配一个 4 x 5 int 数组时,您实际上是在为内存中的一行中的 20 个整数分配空间。这些整数存储为第一行的所有元素,然后是第二行的所有元素,依此类推。

如果没有内大括号,您的初始化程序也是 1D,表示您要初始化这 20 个整数中的前 12 个,即前两行和第三行的前两个元素。

于 2013-08-09T23:55:53.250 回答
2

看看具体的例子会有所帮助。

多维数组是数组的数组。(它不仅仅是长一维数组的语法糖。)

在初始化程序中,省略尾随元素(隐式初始化为零)和内部花括号是合法的。

鉴于:

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]具有未定义的行为。这确实有实际后果;优化编译器可能会假设所有边界都在范围内,如果违反该假设,则会生成行为不端的代码.)

另请参阅此问题

于 2013-08-10T00:11:07.303 回答