int main(void) {
unsigned int x[4][3] = {(1,2,3),(4,5,6),(7,8,9),(17,11,12)};
printf("%d, %u, %u, %u \n",**x, **(x+1), **(x+2), **(x+3));
return 0;
}
上述代码的输出为3,12,0,0。 不应该是1,4,7,17,因为x存储了数组第一个元素的地址吗?
当我试图打印时
printf("%u, %u \n", x, &x[0][0] );
它显示相同的地址2108666688,2108666688
但是当我尝试使用
打印数组时for(int i = 0; i<4; ++i)
{
for(int j = 0; j<3 ; ++j)
{
printf("%d ",x[i][j]);
}
printf("\n");
}
我看到输出为
3 6 9
12 0 0
0 0 0
0 0 0
那么,到底发生了什么?为什么没有将数字正确分配给数组?
答案 0 :(得分:6)
unsigned int x[4][3] = {(1,2,3),(4,5,6),(7,8,9),(17,11,12)};
在功能上等同于:
unsigned int x[4][3] = {3, 6, 9, 12};
因为comma operator在这里工作!逗号运算符计算其所有操作数并生成其最后一个操作数的结果。
所以你看到的输出是预期的。你可能意味着:
unsigned int x[4][3] = {{1,2,3},{4,5,6},{7,8,9},{17,11,12}};
答案 1 :(得分:1)
请记住,数组会自然地衰减到指向第一个元素的指针。这意味着,在您的情况下,x
本身与&x[0]
相同。
因为x
是数组数组,&x[0]
的类型是指向数组的指针,在本例中为unsigned int (*)[3]
。取消引用此指针是一个数组(类型为int [3]
),而后者又可以衰减为指向其第一个元素的指针。
双解引用的作用是简单地取消引用两个指针,从而产生第一个数组的第一个元素,即x[0][0]
。
这恰好是3
而不是1
是因为您使用(1, 2, 3)
初始化元素,而3
正在使用逗号表达式,这导致{{ 1}}。
您可能想要做的是使用大括号作为“内部”数组:
unsigned int x[4][3] = {{1,2,3},{4,5,6},{7,8,9},{17,11,12}};
现在**x
将导致1
。
要记住的另一件事是,对于任何数组或指针 x
和索引i
,表达式x[i]
等于*(x + i)
。
答案 2 :(得分:1)
由于我认为是一个错字(使用括号而不是括号)这个声明
unsigned int x[4][3] = {(1,2,3),(4,5,6),(7,8,9),(17,11,12)};
相当于
unsigned int x[4][3] = { 3, 6, 9, 12 };
数组的所有其他元素都是零初始化的。
结果,数组看起来像是以下面的方式显式初始化
unsigned int x[4][3] = { { 3, 6, 9 }, { 12, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } };
例如,这个表达式
(1,2,3)
是一个逗号运算符的表达式,它产生最后一个操作数的值。
来自C标准(6.5.17逗号操作员)
2逗号运算符的左操作数被计算为void 表达;它的评估与之间存在一个序列点 正确的操作数。 然后评估右操作数;该 结果有类型和值。
考虑例如
unsigned int x = ( 1, 2, 3 );
printf( "x = %u\n", x );
要获得预期结果,您必须用括号替换括号。例如
unsigned int x[4][3] = { {1,2,3}, {4,5,6}, {7,8,9}, {17,11,12} };