2017-06-13 176 views
3

當我使用此代碼時,GCC給了我一個'從不兼容的指針類型初始化'的警告(儘管代碼工作正常,並且執行它應該做的事情,數組的元素)。分配給指針時從不兼容的指針類型警告初始化

#include <stdio.h> 

int main(void) 
{ 
    int arr[5] = {3, 0, 3, 4, 1}; 
    int *p = &arr; 

    printf("%p\n%p\n\n", p); 

    for (int a = 0; a < 5; a++) 
     printf("%d ", *(p++)); 
    printf("\n"); 
} 

然而,當我使用的代碼

int main(void) 
{ 
    int arr[5] = {3, 0, 3, 4, 1}; 
    int *q = arr; 

    printf("%p\n%p\n\n", q); 

    for (int a = 0; a < 5; a++) 
     printf("%d ", *(q++)); 
    printf("\n"); 
} 

這兩個片段之間的唯一區別該位沒有給出警告的是,我分配* P = & ARR和* Q = ARR。

  • &的製作方法究竟有什麼不同?
  • 爲什麼代碼在兩種情況下執行並給出完全相同的輸出?
+1

數組類型與([decays into]([https://stackoverflow.com/questions/1461432/what-is-array-decaying);)不兼容)指向數組項的指針,因此沒有問題在第二種情況下。 – spectras

+0

用'gcc -std = c11 -pedantic-errors'編譯C代碼是一種很好的做法,特別是在學習時。這會阻止你執行無效的代碼C. – Lundin

回答

5
  • &arr給出數組指針,一個特殊的指針類型int(*)[5]其指向在陣列作爲一個整體。
  • arr,當寫入表達式如int *q = arr;時,「decay」成指向第一個元素的指針。完全等同於int *q = &arr[0];

在第一種情況下,嘗試將int(*)[5]分配給int*。這些是不兼容的指針類型,因此是編譯器診斷消息。

事實證明,數組指針和指向第一個元素的int指針很可能在內部具有相同的表示形式和相同的地址。這就是爲什麼第一個例子「工作」的原因,即使它不正確。C.

+0

這是有道理的。謝謝 ! – Nathu

0

輸出是相同的,因爲arr[0]的地址在字面上等同於指向arr[]的指針。任何初始化爲指向arr[0]的指針的值將爲arr[0]的地址;這是一個指針。閱讀指針,尤其是它們與數組的關係。那裏有無數的教程,其中一些可能會以您的兩個案例爲例。

1

這些都是指向數組(開始)(不含警告)的方式,無論是工作:

int *q = arr; 
/* OR */ 
int *q = &arr[0]; 

這一個是介於兩者之間,並會生成一個警告:

int *q = &arr; 
+1

第一個例子都沒有指向數組,它們指向數組的第一項(第二個是直接取其地址,首先是由於數組衰減)。在許多情況下進行淘汰,但可能與問題相關。 – spectras

+0

編輯,謝謝! – SHG

0

TL; DR檢查類型。

  • &arrint (*) [5]型的(指針的5 int小號陣列)。
  • arr類型爲int [5],但不是總是

引用C11,章§6.3.2.1,(重點煤礦

除了當它是sizeof操作者的操作數時,操作者_Alignof或 一元&運營商,或是一個用於初始化數組的字符串文字,表達式具有 類型''數組類型''''被轉換爲類型爲''的表達式指針鍵入「'指向 到數組對象的初始元素並且不是左值。

因此,

int *q = arr; // int[5] decays to int *, == LHS 

int *q = &arr[0]; // RHS == LHS 

是相同的,而,

int *q = &arr; // LHS (int *) != RHS (int (*) [5]) 

是一個不匹配的類型的表達。現在

,它工作,因爲,如在Lundin's answer已經提到的,陣列變量的地址可能是一樣的陣列的第一個元素的地址,所以儘管類型不匹配時,是一樣的,所以這似乎工作。

+0

不,'&arr'給出'int(*)[5]''類型的結果。 – Lundin

+0

@Lundin哎呀,你說得對。我的壞, –

0

當在表達式中用作左值時,數組衰減爲指向其第一個元素的指針。所以int *q = arr;初始化int指針q與數組的第一個元素的地址arr:一切都很好,沒有警告被證明。

&arr是數組的地址。它只能用於正確初始化(或分配)一個指向數組或相同大小的指針,或指向未定義大小數組的指針。你用它來初始化一個指向int的指針(這是一個不同的和不兼容的類型),編譯器會提醒你。因爲使用從指向不同類型的指針初始化的指針是根據標準的「未定義行爲」。

但是在常見的實現中,指向任何類型的指針都具有相同的表示形式,即該對象的第一個字節的地址。因此,即使標準不允許,指令int *p = arr;也會以p的值相同,因爲int *p = arr;的值正確。這就解釋了爲什麼你的程序仍能提供預期的價值。

BTW,未定義行爲並不禁止預期的結果,只是不同的編譯器可能會給出不同的結果,崩潰,沒有錯誤過早結束,踢你的狗,等等。(即使沒有編譯器可以打我的狗到現在;-) )

相關問題