[英]Array size without sizeof operator
我想了解下面的程序,但我不清楚。
#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
即数组的总大小为28。
作为参考,我还尝试了打印(&a)[1]
以及您可以在代码中看到的值。 我也尝试过调试。
如果你投(&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]
类型int(*)[7]
。
然后,您引用(&a)[1]
,转换为*((&a)+1)
。 在英语中,这意味着“给我记忆1点开始后a
。” 当&a
恰好是int(*)[7]
,该点位于数组的末尾。
当你减去a
指向数组开头的指针时,你正在执行指针运算并取一个int
大小的基数(因为a
是一个int
数组)。 所以表达式((&a)[1]-a)
计算在(&a)[1]
和a
之间有多少int
。
可以在此处找到有关指针算法的概述。
(&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]
我们正在采取的地址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
是指向“指向大小为7的数组的指针”类型的数组a
的指针。 我们向它添加1,在一个case中获得指向数组的指针,在另一种情况下获得0。
然后我们回到数组,然后减去。 减法触发衰减到指向第一个元素的指针,因此我们在a结束后立即得到一个指向该元素的指针,并指向一个指向第一个元素的指针。
&a[7]-&a[0]
是的
&*(a+7)-&*(a+0)
现在&*
对已经指针的东西(它们在那一点上)没有任何作用,所以:
(a+7)-(a+0)
那么问题就变成了,你必须加多少a+0
才能达到a+7
。 毫不奇怪,答案是7
:
(a+7) = (a+0)+7
这就是显示的内容。
你操作但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));
如果你想获得的字节数,不使用sizeof
操作符,然后而非强制转换为long
数据类型*,我认为更地道,安全的方法是将两个三分球投进去char *
:
printf("Size of array using pointer arithmethic is %td.\n", (char*)(&a)[1] - (char*)a);
结果:
使用指针arithmethic的数组大小为28。
请注意, %td
格式说明符适用于数据类型ptrdiff_t
(在<stddef.h>
定义),即表示指针差异的方式。
*)有专门的数据类型intptr_t
和uintptr_t
,如果你真的需要,它们可以将对象指针表示为整数。
首先感谢Yakk给予我如此精彩的简单指针式艺术分析。我终于弄明白为什么会发生这样的事情,因为@Yakk详细解释了我在很大程度上清除了我,但仍然对此有所怀疑,所以我开始更改代码并尝试验证指针数学。 一个简短的答案是,如果使用&a [0],它指的是数组地址中的第一个元素。 如果使用a或&a,则它们引用大小为7的完整数组的基址。现在要清楚,我们使用(&a)[0]指向大小为7的数组的基地址,当增加到1时,它变为1 - 阵列的过去结束了。 正如-Yakk所解释的那样:如果我们看一下这可能会更容易:
(一)[1] - (&一)[0]
要么
(&a + 1) - (&a + 0)
&a是指向“指向大小为7的数组的指针”类型的数组a的指针。 我们向它添加1,在一个case中获得指向数组的指针,在另一种情况下获得0。
然后我们回到数组,然后减去。 减法触发衰减到指向第一个元素的指针,因此我们在a结束后立即得到一个指向该元素的指针,并指向一个指向第一个元素的指针。
&一个[7] - 一个[0]
是的
& (a + 7) - & (a + 0)
现在&*对已经指针的东西(它们在那一点上)没有任何作用,所以:
(A + 7) - (A + 0)
那么问题就变成了,你必须加多少+ 0才能达到+7。 毫不奇怪,答案是7:
(a + 7)=(a + 0)+7
这就是显示的内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.