2015-11-07 63 views
-1

我想測試我能不能改變常量指針,它指向下一個數組的第一個元素測試時我得到了一些奇怪的輸出,我不明白:指向數組第一個元素的常量指針的指針是如何工作的?

//Constant pointer to pointer to constant value 
void test(int const * * const a) { 
    //printf("%d", **a); //Program crashes (2) 
    (*a)++; 
} 

int main() 
{ 
    int a[5] = { 1,2,3,4,5 }; 
    test(&a); 
    printf("%d", *a); //Prints 5 as output (1) 

    return 0; 
} 

我預計編譯當我嘗試編譯(* a)++時出現錯誤,但是我可以運行代碼,但是當我嘗試打印元素時,我得到一個奇怪的值(1)。

然後我想打印出數組第一個元素的值(2)。當我嘗試這個時,程序崩潰。

回答

2

通過做&a你正在指向一個數組(int (*)[])。

然後,當這個指針數組傳遞到test功能,它的轉換成指針的指針(int **);

然後(*a)++;是UB。

1.那麼爲什麼是5?

對於像GCC這樣的C的現代實現,指向數組的指針與數組的開頭具有相同的數值,當數組衰減到指針時,地址值也是如此:它們都是陣列。

所以,在testint **a指向的數組的開始,(*a)++ deferences指針如int *和由1個int元件,其通常作爲添加sizeof(int)到指針的數值實現遞增指針。

然後,1+sizeof(int)給你5

2.爲什麼在第二種情況下崩潰?

假設使用的是一個32位的x86機器,或一些機器,其指針類型的大小與int類型相同,則*a等於1。然後在內存地址1進一步解引用指針通常會給你一個段錯誤。

+0

謝謝你,那是一個很棒的解釋! – Agnaroc

+0

我發現它很有啓發性,當'a'是一個數組時,我發現'printf(「%p \ n」,a);''和'printf(「%p \ n」,&a);''會打印相同的地址! – Prayag

+0

'&a ''具有類型'int(*)[5]',而不是你所說的。另外,由於這不是數組類型,因此它不會衰減(更不用說衰減到'int **')。 –

2

程序在printf上崩潰,因爲test假定當它取消引用時a生成的對象是一個指針。如果它是一個且包含有效地址,則第二個解引用將產生一個int對象。唉,a包含數組的地址,它的數字地址是它的第一個元素的地址。這裏的4或8個字節被認爲是一個地址(因爲test認爲*a是一個指針),然後代碼嘗試訪問地址爲1的存儲器,以便打印該地址處假定的int值。該地址是無效的,所以程序崩潰。

現在我們已經確定程序認爲數組開頭處的數據是一個指向int的指針,我們知道(*a)++會做什麼:它將值遞增sizeof(int),以便「指針」指向下一個int 「元件」。我猜你的機器上的int是4字節長,因爲1 + 4 = 5,這是打印的。

1

這段代碼在C中是非法的,你應該得到一個編譯器診斷。 (如果沒有,請調高警戒級別)。運行任何可執行程序的結果都是沒有意義的。

該代碼是非法的,因爲int (*)[5]未隱式轉換爲int const **

恆定指針指向的數組的第一個元素用C

沒有這樣的事情。你誤解了數組是什麼。數組是一系列連續的元素。 int a[5]就像int a;,只是有5整數而不是1

int a;int a[1];導致相同的存儲器佈局。唯一的區別是用於訪問該內存的語法。

相關問題