簡體   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