我正在阅读 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个值分成自己喜欢的行数来覆盖默认顺序(但是按照数组 M
的定义,每行不能超过5列)。
例如,当您使用内部括号将相同的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
所以每一行的最后两个值都是零(因为您没有为它们设置值)。 如果没有内部括号,该数组将如下所示:
10 5 -3 9 0
0 32 20 1 0
0 8 0 0 0
0 0 0 0 0
只有前12个元素将成为给定的值,其余的将变为0。
由于所有数组在内部都表现为1维数组,因此您必须使用方括号指定要初始化的确切行。
例如:
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
int arr[3][3];
,引用 arr[0][3]
具有未定义的行为,即使您可能期望它等同于 arr[1][0]
。 - Keith Thompson能否提供具体示例会更有帮助。
多维数组是由数组组成的数组(它不仅仅是一个长的一维数组的语法糖)。
在初始化器中,可以省略尾随元素(它们会被隐式地初始化为零)和内部花括号。
例如:
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个元素(或更普遍地说,所有元素)提供初始值,则内部花括号并不是必需的;无论哪种方式,元素的顺序都是相同的。
个人认为最好包含所有内部大括号,因为它们反映了您正在初始化的实际结构。
(那么一维数组和二维数组之间有什么区别,除了语法糖?给定arr的上述声明,如果它与一维数组相同,则arr [0] [2]将与arr [1] [0]相同,第二个索引溢出到第二行。实际上,这可能是可行的,但是arr [0] [2]具有未定义的行为。这确实有实际后果;优化编译器可以假设所有边界都在范围内,并生成在违反该假设时会出现问题的代码。)
请参见此问题。