簡體   English   中英

int (*ptr)[4] 的真正含義是什么,它與 *ptr 有何不同?

[英]What int (*ptr)[4] really means and how is it different than *ptr?

int (*p)[4] , *ptr;
int a[4] = {10,20,30,40};
printf("%p\n%p\n%p",&a,a,&a[0]);
p = &a ;
//p=a;        gives error

//ptr = &a;   gives error
 ptr = a;

Output:

0x7ffd69f14710
0x7ffd69f14710
0x7ffd69f14710

我試圖了解a&a&a[0]返回的內容及其起始變量的 memory 地址。 那么,為什么我在其中一些作業中遇到錯誤?

我的意思是,如果p = &a = 0x7ff...有效,為什么不p = a = 0x7ff..

如果可能的話,任何人都可以通過這個 p 和 ptr 實際指向的框圖讓我理解。 或者他們只是指向相同。 但它們是不同的東西,我肯定知道。

想象一下指針是激光指針,具有不同的 colors(紅色表示指向 int 的指針,綠色表示指向 arrays 的指針,...)和變量是您可以使用正確的激光指針指向的東西,即,您不能使用綠色激光指針指向指向一個 char 變量。

好的,所以你有int a[4]一個數組(4 個整數)。 使用綠色指針指向它: int (*green)[4] = &a; ...您還有一個 int ( a[0] ),您可以用紅色指針指向它: int *red = &a[0]; /* in most contexts 'a' by itself is converted to "address of first element": &a[0] is the same as a */ int *red = &a[0]; /* in most contexts 'a' by itself is converted to "address of first element": &a[0] is the same as a */

現在問你的色盲朋友指針指向哪里:)
就你的朋友而言,他們是平等的,指向同一個“地方”……但你欺騙了你的朋友! 編譯器是色盲的,不喜歡被欺騙

int (*ptr)[4]的真正含義是什么,它與*ptr有何不同?”

首先,我們看一下聲明本身:

int * ptr - ptr的類型是int * - 指向int的指針。

int (*ptr)[4] - ptr的類型為int (*)[4] - 指向四個int數組的指針。

類型不同。


我的意思是,如果p = &a = 0x7ff...有效,為什么不p = a = 0x7ff..

挑剔的旁注:這些表達式不會被編譯,但我知道這只是說明上下文的示例。

在 C 中,數組類型的表達式能夠衰減為指向數組第一個元素的指針。

引用 C18 標准 ISO/IEC 9899:2018:

"除非它是 sizeof 運算符的操作數,或一元 & 運算符,或者是用於初始化數組的字符串字面量,否則類型為 "array of type" 的表達式將轉換為類型為 "pointer to type" 的表達式“它指向數組 object 的初始元素並且不是左值。如果數組 object 具有寄存器存儲 class,則行為未定義。”

資料來源:C18,§6.3.2.1/3

但由於&運算符用於a ,因此a不會衰減為指向 a 的第一個元素a指針。 相反, &應用於數組本身並產生一個指向整個數組的指針(類型int (*)[4] )。

它是一種語法類型差異/不匹配, int *int (*)[4] ,當然兩者都指向 memory 中的相同地址。

編譯器有義務對任何類型不匹配進行診斷,因為它是語法違規。

當然,兩者都具有相同的地址,但是分配時的類型不兼容會有所不同。

p是指向int[4]類型值的指針,即指向 arrays 的指針,每個 4 個整數。 請注意, sizeof(*p)sizeof(int)的 4 倍。

現在,

  • p = a失敗,因為a在分配時衰減為指向 int 的指針,而p指向不同的類型。 閱讀有關衰減的更多信息: 什么是數組到指針衰減?
  • ptr = &a失敗,因為ptr實際上是一個指向 int 的指針; 它與p的類型不同。 在同一行聲明多個變量通常會令人困惑,因為並非所有語法都適用於您聲明的所有內容 更好地將這些定義拆分為單獨的行。

我試圖理解a&a&a[0]是什么。

在 C arrays 衰減到指針。 所有這些指針都引用相同的 memory 位置(數組的第一個元素)。 唯一的區別是類型。

a&a[0]具有數組元素的類型(在本例中為int

&a是指向元素數組類型的指針(在本例中為 4 個整數數組)。

這是不同類型的問題,類型是編譯器中存在但編譯后的二進制文件中不存在的概念。 這就是為什么即使這兩種指針類型實際上指向同一個地址也會出現編譯器錯誤的原因。

你可以想到int (*p)[4]=&arr; 作為指向整個數組的指針,而int* ptr=arr; 指向數組中第一個元素的指針

通常在表達式中使用時,數組名稱“衰減”為指向第一個元素的指針。 這就是我們寫int* ptr=arr;時發生的情況。 - 100% 等同於編寫int* ptr = &arr[0]; .

正式地,“陣列衰減”規則在 C17 6.3.2.1/3 中定義:

除非它是sizeof運算符的操作數,或一元&運算符,或者是用於初始化數組的字符串字面量,否則類型為 ''array of type'' 的表達式將轉換為類型為 ''pointer 的表達式鍵入指向數組 object 的初始元素且不是左值的''。

正如我們所見, &運算符是規則中的一個特殊例外。 這意味着在&arr的情況下, arr部分不會衰減。 所以我們應該得到一個指向數組類型的指針,而不僅僅是第一個元素。 這就是int (*p)[4]適合的地方。

但當然,“指向整個數組的指針”會同時指向第一項的地址,因為那是數組開始的地址。 如果我們printf("%p\n", p) ,無論我們傳遞數組指針還是指向第一個元素的指針,我們都會得到相同的地址。

數組指針的存在是為了保持語言類型系統的一致性。 當我們開始使用多維 arrays 時,我們有時也會遇到它們。 例如,如果我們定義一個int arr[2][3]數組,它實際上是一個包含 2 個項的數組,其中每個項都是一個int[3]數組。 那么當我們為這個二維數組輸入arr時會發生什么? 像往常一樣,數組衰減為指向第一項的指針。 而第一項是一個數組,所以為了讓數組衰減的規則保持一致,它必須給出一個指向這樣一個由 3 個整數組成的數組的指針。 這種指針的類型是int(*)[3]

通過這些討論,這兩個答案都得到了明確。 我想總結他們:

1. int *ptr 和 int *ptr[4] 有什么區別;

:兩個指針變量的大小相同,因為它們都只保存地址。 ptr 持有 integer 的地址只是概念上的區別。 好吧,當然你可以用它來指向數組的起始位置。 但這說明編譯器是:它可以容納任何 integer。 當您嘗試在代碼中執行“ptr++”時,它只會將 memory 地址向前移動 1 個單位(根據為該系統保留的 integer 的任何字節)。 但是,int *ptr[4] 表示,ptr 是一個指針,它指向整個數組,只存儲起始位置。 好吧,當然 ptr 在這兩種情況下都存儲相同的地址。 但是當你在這種情況下嘗試執行“ptr++”時,它會向前移動 4 個單位,因為編譯器將其解釋為數組的指針,而不是 integer 的指針。

2. 為什么 ptr=&a 有效,而 ptr =&a[0] 或 ptr=a 不起作用,即使這些值都相同?

答案: ptr=a 和 ptr=&a 在概念上都是正確的。 但是,編譯器遵循嚴格的規則。 如果您想說 ptr 包含 integer 的地址,那么它應該以 ptr = a OR ptr=&a[0] 的方式分配(表示分配的空間是整數)。 而如果 ptr 被聲明為數組的地址,則 ptr = &a[0] pr ptr = a 被編譯器解釋為這個 ptr 獲得了 integer 的地址,這是不正確的,因為這里的 ptr 表示一個大批。 在這種情況下,它不應包含 integer 的地址。 因此, p=&a 在語法上看起來對編譯器非常正確。 因此,這是它接受的唯一選項。

:)

以下是基本規則:

對於任何1類型T ,您可以具有以下任何一種:

T *p;        // p is a pointer to T
T *a[N];     // a is an array of pointer to T
T (*a)[N];   // a is a pointer to an array of T
T *f();      // f is a function returning pointer to T
T (*f)();    // f is a pointer to a function returning T

后綴[]()運算符的優先級高於一元* ,因此*p[i]之類的表達式被解析為*(p[i]) 如果要索引p指向的內容,則需要將*運算符與p(*p)[i]顯式分組。 此優先規則適用於表達式和聲明。

除非它是sizeof_Alignof或一元&運算符的操作數,或者是用於在聲明中初始化字符數組的字符串文字,否則將轉換類型為“ T的 N 元素數組”的表達式(“decay ") 到類型為“pointer to T ”的表達式,表達式的值將是數組第一個元素的地址。 所以鑒於聲明

int a[4] = {10, 20, 30, 40};

以下所有情況均屬實:

Expression        Type            Decays to             Equivalent value
----------        ----            ---------             ----------------
         a        int [4]         int *                 &a[0]
        &a        int (*)[4]      n/a                   &a[0]
        *a        int             n/a                    a[0]

表達式a類型為“4 元素int數組”( int [4] )。 a不是sizeof_Alignof或一元&運算符的操作數,因此表達式“衰減”以鍵入“指向int的指針”,表達式的值是第一個元素的地址。 這個表達式的結果完全等同於&a[0]

表達式&a類型為“指向 4 元素int數組的指針”( int (*)[4] )。 在這種情況下, a一元&運算符的操作數,因此不適用衰減規則。

所有表達式a&a&a[0]產生相同的a的第一個元素的地址),但表達式的類型不同(這可能會影響值的表示方式)。 a&a[0]的類型是int * ,但&a的類型是int (*)[4]

類型對於指針算術之類的事情很重要。 假設以下聲明:

int a[4] = {0, 1, 2, 3};
int *p = a;
int (*ap)[4] = &a;

pap最初都指向同一個地址。 但是,表達式p + 1將產生下一個int object 的地址,無論p指向什么 (IOW, &a[1] ),而ap + 1將產生下a int 4 元素數組的地址.

這正是數組下標的工作方式——表達式a[i]被評估為*(a + i) 給定起始地址a ,偏移i個對象(不是字節)並取消引用結果。

這就是為什么您在某些作業中遇到錯誤的原因 - int *int (*)[4]類型不兼容 一方面,它們不必以相同的方式表示(盡管在您可能使用的任何系統上它們都將是),並且在使用指針算術時它們的行為不同。

指向不同類型的指針本身就是不同的類型,通常不能互換。


  1. 好吧,幾乎所有 - 函數都不能返回數組或 function 類型,並且您不能擁有 function 類型的數組,因此對於T T (*a)[N] T不能是 ZC1C425268E68385D1AB5074F7 類型,而對於T (*f)()不能是 function 或數組類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM