[英]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]
和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]
類型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
的地址,盡管&a
和a[0]
具有不同的類型。
您可以將此差異視為(&a)[1]-(&a)[0]
或&a[7] - &a[0]
。
sizeof(a)
給出為數組a
分配的內存大小。 sizeof(a)/sizeof(a[0])
將給出數組a
的元素數。
所以指針不是整數。 當然,您可以通過將它們轉換為整數類型將它們轉換為整數,或者向它們添加整數以將它們滑動。 但它們不是整數。
如果你做了任何線性代數,指針就像整數的數學向量。
p1-p2
是p1
和p2
之間的距離,是加到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
是指向“指向大小為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 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));
如果你想獲得的字節數,不使用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_t
和uintptr_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.