C语言中的多维数组初始化

C语言中的多维数组初始化,c,C,我正在读Kochen的《C语言编程》一书,我对他解释多维数组初始化的地方感到困惑 特别是,我不理解下面这句话的意思,请注意,在这种情况下,需要内部大括号对来强制执行正确的初始化。如果没有它们,前两行和第三行的前两个元素将被初始化。我不确定这句话到底是什么意思。这是因为m[4][5]数组有20个元素(4行5列),如果没有使用内括号对显式指定行,则默认的初始化顺序为逐行 这意味着,如果将相同的12个值指定为一个简单的线性列表,而没有内部大括号对,则将值指定给前两行(2*5=10个元素)加上第三行的

我正在读Kochen的《C语言编程》一书,我对他解释多维数组初始化的地方感到困惑


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

这是因为
m[4][5]
数组有20个元素(4行5列),如果没有使用内括号对显式指定行,则默认的初始化顺序为逐行

这意味着,如果将相同的12个值指定为一个简单的线性列表,而没有内部大括号对,则将值指定给前两行(2*5=10个元素)加上第三行的前两列。(未显式初始化的数组的其余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}
};
int M[4][5] =
{
  {10,  5, -3, 0, 0},
  { 9,  0,  0, 0, 0},
  {32, 20,  1, 0, 0},
  { 0,  0,  8, 0, 0}
};
您可以通过使用内括号将12个值分隔为自己喜欢的行来覆盖默认顺序(但对于数组的此定义
M
,每行自然不超过5列)

例如,当您使用内大括号将相同的12个值分隔为4组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, 9, 0},
  { 0, 32, 20, 1, 0},
  { 0,  8,  0, 0, 0},
  { 0,  0,  0, 0, 0}
};
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
10  5 -3  9  0
 0 32 20  1  0
 0  8  0  0  0
 0  0  0  0  0
因此,在每一行中,最后两个值都是零(因为您没有为它们设置值)。 如果没有内部大括号,数组将如下所示:

10  5 -3  0  0
 9  0  0  0  0
32 20  1  0  0
 0  0  8  0  0
10  5 -3  9  0
 0 32 20  1  0
 0  8  0  0  0
 0  0  0  0  0

只有前12个元素将成为给定值,其余元素将为0。

因为所有数组在内部都表现为1d数组,所以必须用括号指定要初始化的行

例如:

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整数数组时,你实际上是在内存中为一行中的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]
具有未定义的行为。这确实会产生实际后果;优化编译器可能会假设所有边界都在范围内,如果违反该假设,则会生成行为错误的代码。)


另请参见。

没有多维数组是数组的数组。鉴于声明
int-arr[3][3];
,引用
arr[0][3]
具有未定义的行为,即使您可能认为它等同于
arr[1][0]
@KeithThompson我指的是数组的底层内存表示形式,这在这里是相关的,并不是说访问数组的行为是等价的。不过,这一点很好。@1''C类型系统与底层表示形式不同。嗯,我想你不能称之为语法糖。C类型系统是不是mpiler需要将2D数组的1D初始值设定项解释为初始化前两行和前两列,就好像2D数组是连续存储在内存中的一样?无论在这种情况下是否完全恰当,短语syntactic sugar都是说明性的。而且,它让我笑了。谢谢。Do