就在我放松思考时,我对数组上下文中的指针有了相当的理解,我再次在下面的程序上脸朝下摔倒了。我已经了解对于数组arr
,arr
和&arr
在大小上都相同,但在类型上不同,但我无法牢牢掌握以下程序的输出。我试图想象它,但只取得了部分成功。如果您能对这件事进行严格而详细的解释,我将不胜感激,以便像我这样的人可以永远摆脱这种困惑。
在下面的程序中,我使用了"2D"数组demo[][2]
。我知道demo[]
将是大小为 2 的array of arrays
,我也知道单独使用的demo
将是 (*)[2]
型。我仍然对以下内容感到茫然:
1(为什么&demo[1]
和demo[1]
一样?demo[1]
不应该是第二个数组的地址吗?那么到底是什么&demo[1]
,为什么它与第二个数组的地址相同?
2(我知道第二printf()
和第四个是相同的,因为demo[1]
只不过是*(demo+1)
。但我用它来说明这一点。它怎么能等于第三个printf()
,即demo+1怎么能等于*(demo+1(? demo[1]
和*(demo+1)
一样是众所周知的,但demo+1
怎么能等于*(demo+1)
呢?"某物">怎么能等于该"某物"的价值?
3(既然它刚刚证明我不是很聪明,我应该停止我的猜谜游戏,并询问您以下类型的结论性答案:
和演示[1]
演示[1]
演示+1
#include<stdio.h>
int main(void)
{
int demo[4][2]= {{13,45},{83,34},{4,8},{234,934}};
printf("%pn",&demo[1]);
printf("%pn",demo[1]); //Should have cast to (void*),but works still
printf("%pn",demo+1);
printf("%pn",*(demo+1));
}
输出:
0023FF28
0023FF28
0023FF28
0023FF28
demo[1]
是数组demo
的第二个成员,本身就是一个数组。 就像任何其他数组一样,当它不是 &
或 sizeof
运算符的主题时,它会计算到指向其第一个元素的指针 - 也就是说,demo[1]
计算与数组中第一个int
的地址相同的事物&demo[1][0]
demo[1]
。
&demo[1]
是数组demo[1]
的地址,并且因为数组的地址和该数组的第一个成员的地址必然是相同的位置,所以&demo[1]
等于&demo[1][0]
,等于裸demo[1]
。 这是关键的见解 - 数组的第一个元素与数组本身位于内存中的同一位置,就像struct
的第一个成员与结构本身位于内存中的同一位置一样。 当您打印 &demo[1]
和 demo[1]
时,您不会打印指向数组和数组的指针;您正在打印指向数组的指针和指向该数组的第一个成员的指针。
demo+1
是demo
第二个成员的地址。 *(demo+1)
是该成员本身(它是数组demo[1]
(,但由于该成员是一个数组,因此它的计算结果是指向其第一个成员的指针。 如上所述,它的第一个成员必须与数组本身并置。 并不是说"某物"等于"某物"的值 - 因为当您在这样的表达式中使用数组时,它不会计算数组本身。
-
&demo[1]
是指向demo[1]
的指针,它是一个 2int
的数组。 所以它的类型是int (*)[2]
. -
demo[1]
是一个 2 个int
的数组。 它的类型是int [2]
. 但是,当在表达式中使用它不是类型&
或sizeof
运算符的主题时,它将计算出指向其第一个成员的指针,该成员是类型为int *
的值。 -
demo+1
是指向demo[1]
的指针,其类型是int (*)[2]
。
考虑数组在内存中的布局:
+-----+-----+-----+-----+-----+-----+-----+-----+ | 13 | 45 | 83 | 34 | 4 | 8 |234 |934 | +-----+-----+-----+-----+-----+-----+-----+-----+ ^ ^ ^ ^ | | | |演示[0] 演示[1] 演示[2] 演示[3]
然后还要记住,自然demo
"指向"数组中的第一个条目。由此可见,demo + 0
当然也应该指向第一个条目,而获取数组中条目地址的另一种方法是使用操作数地址&
,这将&demo[0]
。所以demo
等于demo + 0
等于&demo[0]
。
还要记住,对于您的示例,demo
中的每个条目都是另一个数组,数组和指针几乎可以互换(因为数组衰减为指针(。由此可见,demo[0]
也可以用作指针。
现在将上面的0
索引替换为 1
,你得到的和你观察到的完全相同。
+-------+------+
| | |
| 13 | 45 |
101 | | | 105
+--------------+
| | |
| 83 | 34 |
109 | | | 113
+--------------+
| | |
| 04 | 08 |
117 | | | 121
+--------------+
| | |
| 234 | 934 |
125 | | | 129
+--------------+
注意:假设sizeof(int) = 4
假设 2D 布局(虽然在内存中不是这样,但它们都对齐(
demo[i]
是 2D 阵列的第i
行。 它们本身就是一维数组。 demo[1]
是第 1
行。[我的意思是地址109
的那个]。
&demo[1]
是 demo[1]
的地址,并且与该行的基址相同。就像一维阵列一样。数组名称给出第一个位置的地址。此处 1D 数组名称demo[1]
demo[1]
由于数组名称也给出了数组的基址,因此它与&demo[1]
相同
demo+1
demo
是指针,值101
。 demo
(即 demo[0]
(属于类型 1 行 [劣质描述。我的意思是具有两个元素的行的大小 - (*)[2]
] 所以demo+1
递增它以指向下一行。这是理智的demo[1]
*(demo+1)
demo+1 is the 1<sup>th</sup> row
*(demo+1)
表示该位置的价值。这本身是一个数组,所以它给出了地址。由于数组名称提供了地址