没有sizeof运算符的数组大小

时间:2016-06-02 05:03:46

标签: c arrays

我想了解下面的程序,但我不清楚。

    #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,即数组的总大小。

作为参考,我还尝试打印(&a)[1]以及您可以在代码中看到的值。我也尝试过调试。

6 个答案:

答案 0 :(得分: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));

解释数学

在这种情况下发生了什么,&a被视为类型int(*)[7]

然后,您引用(&a)[1],转换为*((&a)+1)。在英语中,这意味着“在a开始后给我记忆1。”由于&a恰好是类型int(*)[7],因此该点位于数组的末尾。

当你减去a(指向数组开头的指针)时,你正在执行指针算术并取一个int大小的基数(因为a是{{} 1}}数组)。因此,int表达式计算((&a)[1]-a)int之间(&a)[1]的数量。{/ p>

可以找到关于指针算术的概述here

答案 1 :(得分:5)

(&a)[1]是数组a之后的内存位置的地址,即0x7ffc4888e788(&a)[1]的类型为int *。转换后,a的类型为int *。它相当于(&a)[0]

标准说:

C11-§6.5.6/ 9:

  

当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素;结果是两个数组元素的下标的差异。

差异(&a)[1]-a给出了数组a中的元素数量。请注意,此表达式中的a 是数组元素a[0]的地址,在衰减之后,此地址等同于数组a的地址,但{ {1}}和&a具有不同的类型。

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

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

答案 2 :(得分:5)

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

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

p1-p2p1p2之间的距离,是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是指向类型为#34的数组a的指针;指向大小为7&#34;的数组的指针。我们向它添加1,在一种情况下获得指向数组的指针,在另一种情况下获得零。

然后我们回到数组,然后减去。减法触发衰减到指向第一个元素的指针,因此我们在a结束后立即获得指向元素的指针,并指向指向第一个元素的指针。

&a[7]-&a[0]

&*(a+7)-&*(a+0)

现在&*对已经指针的东西(它们在那一点上)没有任何作用,所以:

(a+7)-(a+0)

接下来的问题是,您需要向a+0添加多少才能达到a+7。毫不奇怪,答案是7

(a+7) = (a+0)+7

就是显示的内容。

答案 3 :(得分:2)

你操作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));

答案 4 :(得分:2)

如果你想获得字节数而不使用sizeof运算符,那么我认为更加惯用和安全的方法是将两个指针都转换为long数据类型*。 {1}}:

char *

结果:

  

使用指针arithmethic的数组大小为28。

请注意,printf("Size of array using pointer arithmethic is %td.\n", (char*)(&a)[1] - (char*)a); 格式说明符适用于数据类型%td(在ptrdiff_t中定义),即表示指针差异的方式。

*)如果您确实需要,可以使用专用数据类型<stddef.h>intptr_t将对象指针表示为整数。

答案 5 :(得分:0)

首先要感谢Yakk给予我如此精彩的简单指针式艺术分析。我终于弄明白为什么会发生这样的事情,因为@Yakk详细解释了我在很大程度上解除了我但仍有一些疑问在那,所以我开始改变代码并尝试验证指针数学。 一个简短的答案是,如果使用&amp; a [0],它指的是数组地址中的第一个元素。如果使用a或&amp; a,则它们指的是大小为7的完整数组的基址。                  现在要清楚,我们使用(&amp; a)[0]指向大小为7的数组的基地址,当增加到1时,它会转到数组a的一端。正如-Yakk所解释的那样: 如果我们看一下这可能会更容易:

(&安培;一)[1] - (&安培;一)[0]

(&安培; A + 1) - (&安培;一个+ 0)

&amp; a是指向“指向大小为7的数组的指针”类型的数组a的指针。我们向它添加1,在一种情况下获得指向数组的指针,在另一种情况下获得零。

然后我们回到数组,然后减去。减法触发衰减到指向第一个元素的指针,因此我们在a结束后立即获得指向元素的指针,并指向指向第一个元素的指针。

&安培;一个[7] - 安培;一个[0]

&安培; (A + 7) - &安培; (A + 0)

现在&amp; *对已经指针的东西(它们在那一点上)没有任何作用,所以:

(A + 7) - (A + 0)

然后问题变成了,你需要多少加到+ 0来达到+7。毫不奇怪,答案是7:

(a + 7)=(a + 0)+7

就是显示的内容。