二维数组和指针

问题描述 投票:0回答:2

我被告知,编译器会在必要时将数组名称转换为指向数组第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];取而代之。答案仍然是一样的。现在我非常困惑。

c pointers multidimensional-array array-formulas pointer-arithmetic
2个回答
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

0
投票

这行不正确:

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
© www.soinside.com 2019 - 2024. All rights reserved.