[英]Array size without sizeof operator
I am trying to understand program below, but it's not clear to me. 我想了解下面的程序,但我不清楚。
#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]);
}
Above code output is : 上面的代码输出是:
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
It's not clear to me why ((&a)[1]-a))
on second print statement is returning 7; 我不清楚为什么
((&a)[1]-a))
在第二个印刷语句中返回7; it should be 0x7ffc4888e78c - 0x7ffc4888e770
which is 0x1c
ie 28 total size of array. 它应该是
0x7ffc4888e78c - 0x7ffc4888e770
,即0x1c
即数组的总大小为28。
For reference I also tried printing (&a)[1]
and a values which you can see in code. 作为参考,我还尝试了打印
(&a)[1]
以及您可以在代码中看到的值。 I tried also debugging. 我也尝试过调试。
If you cast (&a)[1]
and a
to long
before the calculation, then you will get your expected result. 如果你投
(&a)[1]
和a
对long
计算之前,那么你会得到你预期的结果。 As haccks commented, you're currently calculating the pointer difference. 正如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));
Explaining the Math 解释数学
What's happening in this case, is &a
is considered to be type int(*)[7]
. 在这种情况下发生的是
&a
被认为是int(*)[7]
类型int(*)[7]
。
Then, you reference (&a)[1]
, which translates to *((&a)+1)
. 然后,您引用
(&a)[1]
,转换为*((&a)+1)
。 In English, this means "give me the point in memory 1 after the beginning of a
." 在英语中,这意味着“给我记忆1点开始后
a
。” As &a
happens to be type int(*)[7]
, that point is at the end of the array. 当
&a
恰好是int(*)[7]
,该点位于数组的末尾。
When you subtract a
, the pointer to the beginning of the array, you are performing pointer arithmetic and take a base the size of an int
(because a
is an int
array). 当你减去
a
指向数组开头的指针时,你正在执行指针运算并取一个int
大小的基数(因为a
是一个int
数组)。 So the expression ((&a)[1]-a)
is counting how many int
are between (&a)[1]
and a
. 所以表达式
((&a)[1]-a)
计算在(&a)[1]
和a
之间有多少int
。
An overview on pointer arithmetic can be found here . 可以在此处找到有关指针算法的概述。
(&a)[1]
is the address of the memory location past the array a
, ie 0x7ffc4888e788
. (&a)[1]
是经过阵列a
的存储器位置的地址,即0x7ffc4888e788
。 (&a)[1]
is of type int *
. (&a)[1]
的类型为int *
。 After conversion, a
will be of type int *
. 转换后,
a
将是int *
类型。 It is equivalent to (&a)[0]
. 它相当于
(&a)[0]
。
Standard says that: 标准说:
C11-§6.5.6/9: C11-§6.5.6/ 9:
When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object;
当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素; the result is the difference of the subscripts of the two array elements.
结果是两个数组元素的下标的差异。
The difference (&a)[1]-a
gives the number of elements in array a
. 差异
(&a)[1]-a
给出了数组a
中元素的数量。 Note that a
in this expression is the address of array element a[0]
, after decay, and this address is equivalent to the address of array a
, though &a
and a[0]
have different type. 注意, 此表达式中的
a
是数组元素a[0]
的地址,在衰减之后,并且该地址等效于数组a
的地址,尽管&a
和a[0]
具有不同的类型。
You can think of this difference as (&a)[1]-(&a)[0]
or &a[7] - &a[0]
. 您可以将此差异视为
(&a)[1]-(&a)[0]
或&a[7] - &a[0]
。
sizeof(a)
gives the memory size allocated for array a
. sizeof(a)
给出为数组a
分配的内存大小。 sizeof(a)/sizeof(a[0])
will give the number of elements of array a
. sizeof(a)/sizeof(a[0])
将给出数组a
的元素数。
So pointers are not integers. 所以指针不是整数。 Sure, you can convert them to integers by casting them to an integer type, or add integers to them to slide them around.
当然,您可以通过将它们转换为整数类型将它们转换为整数,或者向它们添加整数以将它们滑动。 But they are not integers.
但它们不是整数。
Pointers are like mathematical vectors over the integers, if you have done any linear algebra. 如果你做了任何线性代数,指针就像整数的数学向量。
p1-p2
is the distance between p1
and p2
, the integer required to add to p2
to reach p1
. p1-p2
是p1
和p2
之间的距离,是加到p2
到达p1
所需的整数。
When you add an integer to a pointer, you have to pay attention to the type of the pointer. 向指针添加整数时,必须注意指针的类型。 If the pointer is to an object of size 4, each time you add 1 to a pointer its numerical address increases by 4, not 1.
如果指针指向大小为4的对象,则每次向指针添加1时,其数字地址将增加4而不是1。
The same thing is true when you subtract two pointers. 当你减去两个指针时,同样的事情也是如此。
The key part here is that the numerical value of the address in memory matters, but the type matters just as much to understand what happens. 这里的关键部分是内存中地址的数值很重要,但类型对于理解发生的事情同样重要。
The second strange thing going on here is that arrays decay into pointers to their first element at the drop of a hat. 这里发生的第二个奇怪的事情是,数组会在一滴帽子的情况下衰减成指向第一个元素的指针。 They, however, are not pointers to their first element, they just convert into them very easily.
然而,它们并不是指向第一个元素的指针,它们只是很容易转换成它们。
So when we do this: 所以当我们这样做时:
(&a)[1]
we are taking the address of a
. 我们正在采取的地址
a
。 The address of a
is a pointer of type int(*)[7]
. 的地址
a
是类型的指针int(*)[7]
It is a pointer to an array, not a pointer to the first element of the array . 它是指向数组的指针 , 而不是指向数组第一个元素的指针 。 The difference is in the type of the pointer.
不同之处在于指针的类型。 And that 7 is important.
这7很重要。
We then use []
on the pointer . 然后我们在指针上使用
[]
。 If you have a pointer or array p
and a value v
, p[v]
is defined to be *(p+v)
. 如果你有一个指针或数组
p
和一个值v
, p[v]
被定义为*(p+v)
。 This leads to humor if you do v[p]
, but that isn't important. 如果你做
v[p]
,这会导致幽默,但这并不重要。
Let pa
represent (&a)
. 设
pa
表示(&a)
。 Then pa[1]
is going to be *(pa + 1)
. 那么
pa[1]
将是*(pa + 1)
。
Now, pa
is a pointer-to-an-array (not a pointer-to-the-first-element of the array). 现在,
pa
是一个指向数组的指针(不是指向数组的第一个元素)。 So +1 adds the full size of the array (sizeof(int)*7) to the numeric value. 因此,+1将数组的完整大小(sizeof(int)* 7)添加到数值。
So pa+1
is a pointer to one-past-the-end of a
, and is of type pointer-to-array. 所以
pa+1
是一个指向的一个-过去最端a
,并且是类型的指针到阵列。
We then dereference, and get the non-existent array of size 7 right after the end of the array a
. 然后我们取消引用,并在数组
a
结束后立即得到大小为7的不存在的数组。
Then we subtract a
. 然后我们减去
a
。
(&a)[1]-a
This is where pointer decay kicks in. There is no -
operation on arrays, but there is a -
operation on pointers. 这就是指针衰减的地方。数组上没有
-
操作,但指针上有一个-
操作。 So the C language helpfully decays each of these arrays into pointers to their first element. 因此,C语言有助于将每个数组衰减为指向其第一个元素的指针。
The pointer to the first element of a
is &a[0]
. 指向
a
的第一个元素的指针是&a[0]
。
The pointer to the first element of the array of size 7 immediately after the end of a
is ... &a[7]
. 紧接在
a
结尾之后指向大小为7的数组的第一个元素的指针是... &a[7]
。
Both of these pointers are of type int*
. 这两个指针都是
int*
类型。 When you subtract two int*
s, you get their numeric pointer value, divided by sizeof(int)
. 当你减去两个
int*
,你得到它们的数字指针值除以sizeof(int)
。 In this case, this is easy -- 7. 在这种情况下,这很容易 - 7。
This might be easier if we looked at this: 如果我们看一下这可能会更容易:
(&a)[1]-(&a)[0]
or 要么
*(&a+1)-*(&a+0)
&a
is a pointer to the array a
of type "pointer to array of size 7". &a
是指向“指向大小为7的数组的指针”类型的数组a
的指针。 We add 1 to it, getting the pointer to the array afterwards in one case, and zero in the other case. 我们向它添加1,在一个case中获得指向数组的指针,在另一种情况下获得0。
We then go down back to being arrays, and subtract. 然后我们回到数组,然后减去。 Subtraction triggers decay to pointer-to-first-element, so we get a pointer to the element right after the end of a, and a pointer to the first element of a.
减法触发衰减到指向第一个元素的指针,因此我们在a结束后立即得到一个指向该元素的指针,并指向一个指向第一个元素的指针。
&a[7]-&a[0]
which is 是的
&*(a+7)-&*(a+0)
Now &*
does nothing to things that are already pointers (which they are at that point), so: 现在
&*
对已经指针的东西(它们在那一点上)没有任何作用,所以:
(a+7)-(a+0)
The question then becomes, how much do you have to add to a+0
to reach a+7
. 那么问题就变成了,你必须加多少
a+0
才能达到a+7
。 The answer, not surprisingly, is 7
: 毫不奇怪,答案是
7
:
(a+7) = (a+0)+7
and that is what is displayed. 这就是显示的内容。
You operates but int*
pointer. 你操作但
int*
指针。 All arithmetic operations on it using 4 bytes
( sizeof(int)
to be precise) as unit. 所有算术运算都使用
4 bytes
( sizeof(int)
来精确)作为单位。 Difference betwen two pointers expressed into this units. 两个指针之间的差异表示为这个单位。
((&a)[1]-a))
is equals as sizeof(a)/sizeof(a[0])
. ((&a)[1]-a))
等于sizeof(a)/sizeof(a[0])
。 For calc array size into bytes you need to cast pointer to integer value, unsigned int: 要将calc数组大小转换为字节,您需要将指针转换为整数值,unsigned int:
printf("size of array using logic is %d\n",((int)((&a)[1])-(int)a));
If you want to get number of bytes, without using sizeof
operator, then rather than casting to long
data type*, I think that more idiomatic and safe way is to cast both pointers into char *
: 如果你想获得的字节数,不使用
sizeof
操作符,然后而非强制转换为long
数据类型*,我认为更地道,安全的方法是将两个三分球投进去char *
:
printf("Size of array using pointer arithmethic is %td.\n", (char*)(&a)[1] - (char*)a);
Result: 结果:
Size of array using pointer arithmethic is 28.
使用指针arithmethic的数组大小为28。
Note that %td
format specifier is suited for datatype ptrdiff_t
(defined in <stddef.h>
), that is how pointer difference is represented. 请注意,
%td
格式说明符适用于数据类型ptrdiff_t
(在<stddef.h>
定义),即表示指针差异的方式。
*) There are dedicated data types intptr_t
and uintptr_t
for representing object pointers as integers if you really need that. *)有专门的数据类型
intptr_t
和uintptr_t
,如果你真的需要,它们可以将对象指针表示为整数。
First thanks to all and special thanks to Yakk for giving me such great analysis on simple pointer arthamatics.I at last figured out why it is happening so as @Yakk explained in detail that cleared me to much extent but still had some doubt on that,so I started changing code and tryed to verify pointer arthematics. 首先感谢Yakk给予我如此精彩的简单指针式艺术分析。我终于弄明白为什么会发生这样的事情,因为@Yakk详细解释了我在很大程度上清除了我,但仍然对此有所怀疑,所以我开始更改代码并尝试验证指针数学。 One short answer is if &a[0] is used it refers to first element in array address.
一个简短的答案是,如果使用&a [0],它指的是数组地址中的第一个元素。 If a or &a are used they refer to base address of complete array of size 7. Now to go clear ,we used (&a)[0] which point to base address of array of size 7 when incremented to 1 it goes to one-past-the-end of array a.
如果使用a或&a,则它们引用大小为7的完整数组的基址。现在要清楚,我们使用(&a)[0]指向大小为7的数组的基地址,当增加到1时,它变为1 - 阵列的过去结束了。 As explained by --Yakk as below: This might be easier if we looked at this:
正如-Yakk所解释的那样:如果我们看一下这可能会更容易:
(&a)[1]-(&a)[0] (一)[1] - (&一)[0]
or 要么
(&a+1)- (&a+0) (&a + 1) - (&a + 0)
&a is a pointer to the array a of type "pointer to array of size 7". &a是指向“指向大小为7的数组的指针”类型的数组a的指针。 We add 1 to it, getting the pointer to the array afterwards in one case, and zero in the other case.
我们向它添加1,在一个case中获得指向数组的指针,在另一种情况下获得0。
We then go down back to being arrays, and subtract. 然后我们回到数组,然后减去。 Subtraction triggers decay to pointer-to-first-element, so we get a pointer to the element right after the end of a, and a pointer to the first element of a.
减法触发衰减到指向第一个元素的指针,因此我们在a结束后立即得到一个指向该元素的指针,并指向一个指向第一个元素的指针。
&a[7]-&a[0] &一个[7] - 一个[0]
which is 是的
& (a+7)-& (a+0) & (a + 7) - & (a + 0)
Now &* does nothing to things that are already pointers (which they are at that point), so: 现在&*对已经指针的东西(它们在那一点上)没有任何作用,所以:
(a+7)-(a+0) (A + 7) - (A + 0)
The question then becomes, how much do you have to add to a+0 to reach a+7. 那么问题就变成了,你必须加多少+ 0才能达到+7。 The answer, not surprisingly, is 7:
毫不奇怪,答案是7:
(a+7) = (a+0)+7 (a + 7)=(a + 0)+7
and that is what is displayed. 这就是显示的内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.