我想了解下面的程序,但我不清楚。
#include<stdio.h>
int main()
{
int a[]={1,2,3,4,5,6,9};
printf("sizeof array is %d\n",sizeof(a));
printf("size of array using logic is %d\n",((&a)[1]-a));
printf("value of (&a)[1] is %p \n",(&a)[1]);
printf("value of a is %p \n",a);
printf("address of a[0] is %p\n",&a[0]);
printf("address of a[1] is %p\n",&a[1]);
printf("address of a[2] is %p\n",&a[2]);
printf("address of a[3] is %p\n",&a[3]);
printf("address of a[4] is %p\n",&a[4]);
printf("address of a[5] is %p\n",&a[5]);
printf("address of a[6] is %p\n",&a[6]);
}
以上代码输出为:
sizeof array is 28
size of array using logic is 7
value of (&a)[1] is 0x7ffc4888e78c
value of a is 0x7ffc4888e770
address of a[0] is 0x7ffc4888e770
address of a[1] is 0x7ffc4888e774
address of a[2] is 0x7ffc4888e778
address of a[3] is 0x7ffc4888e77c
address of a[4] is 0x7ffc4888e780
address of a[5] is 0x7ffc4888e784
address of a[6] is 0x7ffc4888e788
我不清楚为什么第二个印刷语句中的((&a)[1]-a))
返回7;它应该是0x7ffc4888e78c - 0x7ffc4888e770
0x1c
,即数组的总大小。
作为参考,我还尝试打印(&a)[1]
以及您可以在代码中看到的值。我也尝试过调试。
答案 0 :(得分:15)
如果您在计算之前将(&a)[1]
和a
投射到long
,那么您将获得预期的结果。正如haccks评论的那样,你正在计算指针差异。
// These two sizes will be the same
printf("sizeof array is %ld\n",sizeof(a));
printf("size of array using logic is %ld\n",((long)(&a)[1]-(long)a));
解释数学
在这种情况下发生了什么,&a
被视为类型int(*)[7]
。
然后,您引用(&a)[1]
,转换为*((&a)+1)
。在英语中,这意味着“在a
开始后给我记忆1。”由于&a
恰好是类型int(*)[7]
,因此该点位于数组的末尾。
当你减去a
(指向数组开头的指针)时,你正在执行指针算术并取一个int
大小的基数(因为a
是{{} 1}}数组)。因此,int
表达式计算((&a)[1]-a)
和int
之间(&a)[1]
的数量。{/ p>
可以找到关于指针算术的概述here。
答案 1 :(得分:5)
(&a)[1]
是数组a
之后的内存位置的地址,即0x7ffc4888e788
。 (&a)[1]
的类型为int *
。转换后,a
的类型为int *
。它相当于(&a)[0]
。
标准说:
C11-§6.5.6/ 9:
当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素;结果是两个数组元素的下标的差异。
差异(&a)[1]-a
给出了数组a
中的元素数量。请注意,此表达式中的a
是数组元素a[0]
的地址,在衰减之后,此地址等同于数组a
的地址,但{ {1}}和&a
具有不同的类型。
您可以将此差异视为a[0]
或(&a)[1]-(&a)[0]
。
&a[7] - &a[0]
给出为数组sizeof(a)
分配的内存大小。 a
将提供数组sizeof(a)/sizeof(a[0])
的元素数量。
答案 2 :(得分:5)
所以指针不是整数。当然,您可以通过将它们转换为整数类型将它们转换为整数,或者向它们添加整数以将它们滑动。但它们不是整数。
如果你做了任何线性代数,指针就像整数的数学向量。
p1-p2
是p1
和p2
之间的距离,是p2
加到p1
所需的整数。
向指针添加整数时,必须注意指针的类型。如果指针指向大小为4的对象,则每次向指针添加1时,其数字地址都会增加4而不是1。
当你减去两个指针时,同样的事情也是如此。
这里的关键部分是内存中地址的数值很重要,但类型对于理解发生的事情同样重要。
这里发生的第二个奇怪的事情是,数组衰减成为他们第一个元素的指针。然而,它们是不是指向它们的第一个元素的指针,它们只是很容易转换成它们。
所以当我们这样做时:
(&a)[1]
我们正在使用a
的地址。 a
的地址是int(*)[7]
类型的指针。它是数组的指针,不是指向数组第一个元素的指针。不同之处在于指针的类型。这7很重要。
然后我们在指针上使用[]
。如果您有指针或数组p
且值为v
,则p[v]
定义为*(p+v)
。如果你做v[p]
,这会导致幽默,但这并不重要。
让pa
代表(&a)
。然后pa[1]
将成为*(pa + 1)
。
现在,pa
是一个指向数组的指针(不是指向数组的第一个元素)。因此,+1将数组的完整大小(sizeof(int)* 7)添加到数值。
所以pa+1
是一个指向a
的一端的指针,并且是指向数组的指针类型。
然后我们取消引用,并在数组a
结束后立即获取大小为7的不存在的数组。
然后我们减去a
。
(&a)[1]-a
这是指针衰减的地方。数组上没有-
操作,但指针上有-
个操作。因此,C语言有助于将这些数组中的每个数组衰减为指向其第一个元素的指针。
指向a
的第一个元素的指针是&a[0]
。
在a
结束后立即指向大小为7的数组的第一个元素的指针是...... &a[7]
。
这两个指针都是int*
类型。当你减去两个int*
时,你得到它们的数字指针值除以sizeof(int)
。在这种情况下,这很容易 - 7。
如果我们看一下这可能会更容易:
(&a)[1]-(&a)[0]
或
*(&a+1)-*(&a+0)
&a
是指向类型为#34的数组a
的指针;指向大小为7&#34;的数组的指针。我们向它添加1,在一种情况下获得指向数组的指针,在另一种情况下获得零。
然后我们回到数组,然后减去。减法触发衰减到指向第一个元素的指针,因此我们在a结束后立即获得指向元素的指针,并指向指向第一个元素的指针。
&a[7]-&a[0]
是
&*(a+7)-&*(a+0)
现在&*
对已经指针的东西(它们在那一点上)没有任何作用,所以:
(a+7)-(a+0)
接下来的问题是,您需要向a+0
添加多少才能达到a+7
。毫不奇怪,答案是7
:
(a+7) = (a+0)+7
就是显示的内容。
答案 3 :(得分:2)
你操作int*
指针。
使用4 bytes
(精确sizeof(int)
)作为单位对其进行所有算术运算。
两个指针之间的差异表示为这个单位。
((&a)[1]-a))
等于sizeof(a)/sizeof(a[0])
。
要将calc数组大小转换为字节,您需要将指针转换为整数值,unsigned int:
printf("size of array using logic is %d\n",((int)((&a)[1])-(int)a));
答案 4 :(得分:2)
如果你想获得字节数而不使用sizeof
运算符,那么我认为更加惯用和安全的方法是将两个指针都转换为long
数据类型*。 {1}}:
char *
结果:
使用指针arithmethic的数组大小为28。
请注意,printf("Size of array using pointer arithmethic is %td.\n", (char*)(&a)[1] - (char*)a);
格式说明符适用于数据类型%td
(在ptrdiff_t
中定义),即表示指针差异的方式。
*)如果您确实需要,可以使用专用数据类型<stddef.h>
和intptr_t
将对象指针表示为整数。
答案 5 :(得分:0)
首先要感谢Yakk给予我如此精彩的简单指针式艺术分析。我终于弄明白为什么会发生这样的事情,因为@Yakk详细解释了我在很大程度上解除了我但仍有一些疑问在那,所以我开始改变代码并尝试验证指针数学。 一个简短的答案是,如果使用&amp; a [0],它指的是数组地址中的第一个元素。如果使用a或&amp; a,则它们指的是大小为7的完整数组的基址。 现在要清楚,我们使用(&amp; a)[0]指向大小为7的数组的基地址,当增加到1时,它会转到数组a的一端。正如-Yakk所解释的那样: 如果我们看一下这可能会更容易:
(&安培;一)[1] - (&安培;一)[0]
或
(&安培; A + 1) - (&安培;一个+ 0)
&amp; a是指向“指向大小为7的数组的指针”类型的数组a的指针。我们向它添加1,在一种情况下获得指向数组的指针,在另一种情况下获得零。
然后我们回到数组,然后减去。减法触发衰减到指向第一个元素的指针,因此我们在a结束后立即获得指向元素的指针,并指向指向第一个元素的指针。
&安培;一个[7] - 安培;一个[0]
是
&安培; (A + 7) - &安培; (A + 0)
现在&amp; *对已经指针的东西(它们在那一点上)没有任何作用,所以:
(A + 7) - (A + 0)
然后问题变成了,你需要多少加到+ 0来达到+7。毫不奇怪,答案是7:
(a + 7)=(a + 0)+7
就是显示的内容。