我想了解下面的程序,但我不清楚.
#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]);
}
Run Code Online (Sandbox Code Playgroud)
上面的代码输出是:
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
Run Code Online (Sandbox Code Playgroud)
我不清楚为什么((&a)[1]-a))在第二次印刷声明中返回7; 它应该0x7ffc4888e78c - 0x7ffc4888e770是0x1c28个阵列的总大小.
作为参考,我还尝试了打印(&a)[1]和您可以在代码中看到的值.我也尝试过调试.
Car*_*ter 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));
Run Code Online (Sandbox Code Playgroud)
解释数学
在这种情况下发生的事情&a被认为是类型int(*)[7].
然后,您参考(&a)[1],转换为*((&a)+1).在英语中,这意味着"在开始之后给我记忆1.a" 正如&a恰好是类型int(*)[7],即点位于阵列的端部.
当你减去a指向数组开头的指针时,你正在执行指针运算并取一个大小为a的基数int(因为它a是一个int数组).所以表达式((&a)[1]-a)计算的int是(&a)[1]和之间的数量a.
可以在此处找到有关指针算法的概述.
(&a)[1]是数组之后的内存位置的地址a,即0x7ffc4888e788.(&a)[1]是类型的int *.转换后,a将是类型int *.它相当于(&a)[0].
标准说:
C11-§6.5.6/ 9:
当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素; 结果是两个数组元素的下标的差异.
差异(&a)[1]-a给出了数组中元素的数量a.请注意,a 在这个表达式是数组元素的地址a[0],衰变后,而这个地址等同于数组的地址a,虽然&a并a[0]具有不同的类型.
您可以将这种差异视为(&a)[1]-(&a)[0]或&a[7] - &a[0].
sizeof(a)给出为数组分配的内存大小a.sizeof(a)/sizeof(a[0])将给出数组元素的数量a.
所以指针不是整数.当然,您可以通过将它们转换为整数类型将它们转换为整数,或者向它们添加整数以将它们滑动.但它们不是整数.
如果你做了任何线性代数,指针就像整数的数学向量.
p1-p2之间的距离为p1和p2,添加到所需要的整数p2达到p1.
向指针添加整数时,必须注意指针的类型.如果指针指向大小为4的对象,则每次向指针添加1时,其数字地址将增加4而不是1.
当你减去两个指针时,同样的事情也是如此.
这里的关键部分是内存中地址的数值很重要,但类型对于理解发生的事情同样重要.
这里发生的第二个奇怪的事情是,数组会在一滴帽子的情况下衰减成指向第一个元素的指针.然而,它们并不是指向第一个元素的指针,它们只是很容易转换成它们.
所以当我们这样做时:
(&a)[1]
Run Code Online (Sandbox Code Playgroud)
我们正在采取的地址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指针,并且是指向数组的指针类型.
然后我们取消引用,并在数组结束后立即得到大小为7的不存在的数组a.
然后我们减去a.
(&a)[1]-a
Run Code Online (Sandbox Code Playgroud)
这就是指针衰减的地方.-数组上没有操作,但-指针上有一个操作.因此,C语言有助于将每个数组衰减为指向其第一个元素的指针.
指向第一个元素的指针a是&a[0].
结束后立即将指针尺寸7的阵列的第一个元素a是... &a[7].
这两个指针都是类型的int*.当你减去两个int*s时,你得到它们的数字指针值,除以sizeof(int).在这种情况下,这很容易 - 7.
如果我们看一下这可能会更容易:
(&a)[1]-(&a)[0]
Run Code Online (Sandbox Code Playgroud)
要么
*(&a+1)-*(&a+0)
Run Code Online (Sandbox Code Playgroud)
&a是指向a"指向大小为7 的数组的指针"类型的数组的指针.我们向它添加1,在一个case中获得指向数组的指针,在另一种情况下获得0.
然后我们回到数组,然后减去.减法触发衰减到指向第一个元素的指针,因此我们在a结束后立即得到一个指向该元素的指针,并指向一个指向第一个元素的指针.
&a[7]-&a[0]
Run Code Online (Sandbox Code Playgroud)
是的
&*(a+7)-&*(a+0)
Run Code Online (Sandbox Code Playgroud)
现在&*对已经指针的东西(它们在那一点上)没有任何作用,所以:
(a+7)-(a+0)
Run Code Online (Sandbox Code Playgroud)
那么问题就变成了,您需要添加多少a+0才能达到目标a+7.毫不奇怪,答案是7:
(a+7) = (a+0)+7
Run Code Online (Sandbox Code Playgroud)
这就是显示的内容.