我被告知,编译器会在必要时将数组名称转换为指向数组第1个元素的指针。所以我用这个规则来解决很多问题,直到我看到这个都没关系。
int main()
{
int a[2][3] = {{1,2,3}, {5,6,7}}, (*p)[3];
p = a[0];
for(int i = 0; i < 3; i++)
printf("%d", (*p)[i]);
}
输出是带有代码块的123
。
我试图解决它:
(*p)[i])
应该与*((*p)+i)
相同....(1)
正如规则所说,“数组名称被转换为指向数组第一个元素的指针”。我将第二条指令p=a[0]
转换为p=&a[0][0]
(因为a[0]
是一个子数组名称,其第一个元素是a[0][0]
)。所以(*p)
可以写成(*(&a[0][0]))
。这与a[0][0]
相同。所以eqn(1)变成了
*(a[0][0]+i).
而这就是我被困的地方。 a[0][0]+i
是一个元素,而不是一个地址。所以将*
运算符应用于它是无效的。但我也用原始代码用p=a[0];
替换语句p=&a[0][0];
,答案仍然相同。我也用p=&a[0];
取而代之。答案仍然是一样的。现在我非常困惑。
2D阵列是1D阵列的阵列
在1d数组中,
a[0] => *(a) -> first element of array
a[1] => *(a + 1) -> second element of array
在2d数组中,
a => the adress of first array
a[0] => *(a) -> the first array
a[0][0] => *(*(a)) -> the first element of first array
a[0][1] => *(*(a) + 1) -> second element of first array
a[1][1] => *(*(a + 1) + 1) -> second element of second array
这行不正确:
p = a[0];
p
的类型指向3 int
的数组。 a[0]
的类型是指向int
的指针。你的编译器应该给你一个警告。如果没有,则启用任何必要的开关来打开大多数或所有编译器警告。当编译器发出警告时,请不要忽略它 - 确保您了解编译器在继续之前发出警告的原因。最好启用一个将警告转换为错误的编译器功能。
正确的陈述是p = a;
或p = &a[0];
。但是让我们来看看你的计划中发生了什么。在表达式a[0]
中:
a[0]
相当于*(a+0)
(技术上(*((a)+(0)))
,但在这种情况下我们不需要额外的括号)。a
是一个数组,因此它被转换为指向其第一个元素的指针。所以a
被转换为指向a[0]
的指针。所以表达式现在是*(&a[0] + 0)
。0
添加到&a[0]
不会改变它,因此结果是&a[0]
,表达式现在是*&a[0]
。*
应用于指针会产生指向的东西,因此表达式变为a[0]
。a[0]
是3 int
的阵列。由于它是一个数组,因此它被转换为指向其第一个元素的指针。所以结果是有效的&a[0][0]
。观察&a[0][0]
是指向int
的指针,如上所述。所以现在我们看到p = a[0];
在右侧有一个指向int
的指针,但在左侧有一个指向3个int
数组的指针。这违反了C标准中的约束,编译器必须为其发出诊断消息。
在警告之后,你的编译器可能做的是转换指针,导致p
被设置为指向a[0]
。
我将第二条指令
p=a[0]
转换为p=&a[0][0]
(因为a[0]
是一个子数组名称,其第一个元素是a[0][0]
)。所以(*p)
可以写成(*(&a[0][0]))
。
这是个错误。虽然您执行了作业p = a[0]
,但这并未将&a[0][0]
分配给p
,而p
的行为并不像&a[0][0]
那样。赋值将&a[0][0]
转换为p
的类型。 p
仍然是它被声明的类型,指向3 int
阵列的指针。实际上,p
最终得到了&a[0]
的价值。
现在我们可以评估(*p)[i]
:
p
是&a[0]
,所以表达式变成(*&a[0])[i])
。*&a[0]
是a[0]
,所以表达式变成a[0][i]
。i
元素0的元素a
。