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。 当 x 存储数组第一个元素的地址时,它不应该是 1,4,7,17 吗?
当我尝试打印时
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
那么,这里到底发生了什么?为什么没有将数字正确分配给数组?
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] = {{1,2,3},{4,5,6},{7,8,9},{17,11,12}};
请记住,数组自然衰减到指向其第一个元素的指针。这意味着在您的情况下,x
本身与&x[0]
相同。
由于x
是数组数组,因此&x[0]
的类型是指向数组的指针,在本例中为unsigned int (*)[3]
。取消引用此指针是一个数组(类型为int [3]
),而该数组又可以衰减到指向其第一个元素的指针。
双重取消引用所做的只是取消引用两个指针,从而产生第一个数组的第一个元素,即x[0][0]
.
这恰好是3
而不是1
是因为您使用(1, 2, 3)
初始化元素,该元素使用逗号表达式导致3
。
您可能还想对"内部"数组使用大括号:
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)
。
由于我认为拼写错误(使用括号而不是大括号)此声明
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 = %un", x );
要获得预期的结果,您必须用大括号替换括号。例如
unsigned int x[4][3] = { {1,2,3}, {4,5,6}, {7,8,9}, {17,11,12} };