简体   繁体   English

没有sizeof运算符的数组大小

[英]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]along计算之前,那么你会得到你预期的结果。 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的地址,尽管&aa[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-p2p1p2之间的距离,是加到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和一个值vp[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 bytessizeof(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_tuintptr_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM