2017-06-03 77 views
3

我想知道爲什麼我不得不使用malloc來動態創建內存,而我已經有了指針可以自由操縱內存。 所以我創造了這個代碼,但是這個代碼腐敗,稱‘被破壞「爲什麼我不能使用指針而不是malloc

有人能解釋爲什麼這代碼失敗,那周圍的變量棧’?

#include <stdio.h> 

int main(void) 
{ 
    int a = 1; 
    int * arr1 = &a; 
    *(arr1 + 1) = 2; 
    printf("%d %d\n", *arr1, *(arr1+1)); 
} 
+0

這是未定義的行爲。 – BLUEPIXY

+0

雖然技術上*未定義的行爲*,但最可能的是您正在寫入不屬於您的堆棧內存。這可能表現爲另一個本地變量或函數參數獲取更改的值。或者你因爲函數的返回地址被破壞 - 或者更糟 - 當函數返回時在指令指針的其他位置結束而崩潰。 – selbie

+0

你需要更多的基本概念研究。你的頭銜反映了根本的誤解。使用'malloc'進行堆分配預留存儲空間供程序使用。您的程序可以使用指針算術來讀取和寫入已經保留的存儲中的值。得到一本好書。 – Gene

回答

4

只是因爲你可以對某些任意地址執行指針算術並不意味着你應該。 C給你很大的靈活性去做你想做的事,但這也意味着它相信你做正確的事情,你不是。

你試圖做的是寫入一個內存地址sizeof(int)字節超過地址a。該內存地址不是a的一部分,寫入它將調用undefined behavior

至於你的具體情況發生了什麼,局部變量通常存儲在大多數託管實現的堆棧中。所以如果你寫過一個變量的邊界,你很可能會覆蓋相鄰變量或函數的返回地址。鑑於你的程序崩潰了,你可能正在做後者。

這裏的覆蓋另一個變量的說明:

#include <stdio.h> 

int main(void) 
{ 
    int before = 0; 
    int a = 1; 
    int after = 0; 
    int * arr1 = &a; 
    *(arr1 + 1) = 2; 
    printf("%d %d\n", *arr1, *(arr1+1)); 
    printf("before=%d, after=%d\n", before, after); 
} 

在這個例子中,我把你的例子,之前和之後a加入一個變量。當我運行它,我得到以下的輸出:

1 2 
before=2, after=0 

你可以看到,before現在設置爲2,即使它沒有明確設置。這意味着它出現在a之後的堆棧中。所以通過編寫一個過去的a,你最終會寫入before

重申,這是未定義的行爲。編譯器可以按任意順序排列堆棧上的變量。例如,如果您要添加額外的printf調用或使用不同的優化設置進行編譯,您可能會得到不同的結果。我用-O1重新編譯了上面的代碼,並運行它導致了核心轉儲。

因此,如果需要特定數量的內存,並且沒有明確預留空間,則需要撥打malloc以獲取所需的內存。然後你可以自由地讀取和寫入該塊。

5

你不知道在&a + 1上可能存儲的實現是什麼。這可能是維持操作環境完整性所需的關鍵信息。儘管不知道它可能用於什麼,但您可以修改它。所以什麼都可能發生。

不要寫入不屬於你的內存!

0

您使用int * arr1 = &a;來請求指向a的指針。系統分配arr1。所以該方法可以安全地請求一個指針。

而對於您的另一種情況,請使用*(arr1 + 1) = 2來請求指針(arr1 + 1)指向一個整數值。您可能不知道(arr1 + 1)是否被其他程序或其他用途部署。這不是一個安全的內存地址。所以這就是程序被破壞的原因。

0

您已將變量a的地址指定爲指針arr1。 ARR1由4所聲明整數指針ARR1 + 1級的增量地址(的sizeof(int)的),即,如果ARR1是0x00000003 ARR1 + 1是0x00000007

*(arr1 + 1) = 2; 

變得無效其超出分配用於,寫入無效存儲器內存使你的程序崩潰

相關問題