繁体   English   中英

没有sizeof运算符的数组大小

[英]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]along计算之前,那么你会得到你预期的结果。 正如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的地址,尽管&aa[0]具有不同的类型。

您可以将此差异视为(&a)[1]-(&a)[0]&a[7] - &a[0]

sizeof(a)给出为数组a分配的内存大小。 sizeof(a)/sizeof(a[0])将给出数组a的元素数。

所以指针不是整数。 当然,您可以通过将它们转换为整数类型将它们转换为整数,或者向它们添加整数以将它们滑动。 但它们不是整数。

如果你做了任何线性代数,指针就像整数的数学向量。

p1-p2p1p2之间的距离,是加到p2到达p1所需的整数。

向指针添加整数时,必须注意指针的类型。 如果指针指向大小为4的对象,则每次向指针添加1时,其数字地址将增加4而不是1。

当你减去两个指针时,同样的事情也是如此。

这里的关键部分是内存中地址的数值很重要,但类型对于理解发生的事情同样重要。

这里发生的第二个奇怪的事情是,数组会在一滴帽子的情况下衰减成指向第一个元素的指针。 然而,它们并不是指向第一个元素的指针,它们只是很容​​易转换成它们。

所以当我们这样做时:

(&a)[1]

我们正在采取的地址a 的地址a是类型的指针int(*)[7] 它是指向数组的指针而不是指向数组第一个元素的指针 不同之处在于指针的类型。 这7很重要。

然后我们在指针上使用[] 如果你有一个指针或数组p和一个值vp[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 bytessizeof(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_tuintptr_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.

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