我在使用以下代码时遇到问题:
int a[] = {1, 2, 3, 4};
fprintf(stdout,
"a : %lun"
"*a : %dn"
"&a : %ldn"
"**(&a) : %dn",
(unsigned long int)a,
*a,
(unsigned long int)&a,
**(&a)
);
输出:
a : 140726063647232
*a : 1
&a : 140726063647232
**(&a) : 1
我知道&a
是指向 1 D 数组的指针。而&a
的类型是int (*)[4]
。 我对怎么**(&a): 1
感到困惑.
&a
是指向数组的指针。*p
获取指针指向的内容,因此*&a
获取数组,a
。
被视为指针的数组退化为指向其第一个元素的指针,因此*a
1
。
由于*&a
只是a
,**&a
与*a
相同,后者1
。
查看它的另一种方法是通过每个地址或取消引用操作后的结果类型。数组访问的基本规则是数组指针转换。C11 标准 - 6.3.2.1 其他操作数 - 适用于访问任何数组的左值、数组和函数指示符 (p3((受列出的 4 个例外 [C18 标准中的 3 个 - 不再列出_Alignof
](。
关键是要理解数组在访问时被转换为指向第一个元素的指针(受有限例外限制 - 此处无关(。如果采用数组的地址,则地址与第一个元素的地址相同,但指针的类型完全不同。
a - pointer to int
&a - pointer-to-array int[4], proper type: int (*)[4]
当你取消引用a
时,你会得到第一个元素:
*a - int
为什么?*a
是偏移量为0
的完全取消引用操作的缩写,例如*(a + 0)
等效于索引表示法中的a[0]
。
当您取消引用指向数组的指针int[4]
时,您会恢复数组:
*(&a) - int[4] -> converted to pointer to first element.
然后,通过操作,将6.3.2.1(p3(转换为指向第一个元素的指针。再次取消引用,你会得到第一个元素:
**(&a) - int
现在值得学习,因为它会让你以后省去很多困惑。
- 如果你想打印一个
address
,你可以使用printf
或fprintf
函数的%p
转换说明符。 - 另一方面,使用上述相同功能打印
integer data type
,应使用%d
转换说明符。 然后,您可以省略所有向上转换以unsigned long int
数据类型。 - 在您的情况下,
c arrays
衰减到相同数据类型的指针(并非在所有情况下数组都可以decays
指针(。 在您的打印中,您使用了这一事实,例如,当取消引用数组时*a
. C中的这个事实使我们能够扭动下面的陈述:int* a_ptr = a;
和int* ptr = &a[0];
.现在a_ptr
和ptr
是平等的!指向内存中的同一地址。 - 打印
a
就像打印a_ptr
值和打印ptr
值一样。 以打印&a[0]
结束。 - 打印
*a
就像打印 *a_ptr 和打印*ptr
,既然ptr = &a[0];
那么,*ptr
==*&a[0]
==a[0]
所以简单来说,它的a[0]
是1
。 &a
. 现在什么是&a
? 它是指向整数数组的指针! 更准确地说,它是一个指向 4 个整数数组的指针,这是int (*)[4]
所以在打印 a 的地址时,就像打印*(int (*)[4])
的取消引用一样,这是数组简单a
的地址。 请注意,数据类型是不同的!a
和&a
!- 打印
**(&a)
与*(*(int (*)[4]))
相同,与*(a)
相同,与*(a+0)
相同,与*ptr
相同,a[0]
1
。
将代码片段修复为:
int a[] = {1, 2, 3, 4};
fprintf(stdout, /*you can use printf instead of fprintf(srdout,)*/
"a : %pn"
"*a : %dn"
"&a : %pn"
"**(&a) : %dn",
a,
*a,
&a,
**(&a)
);