2013-04-02 116 views
2

我正在學習測試,並且遇到了一些我很難理解的東西。我們正在處理指針和內存分配,我只是在玩弄東西,試圖弄清楚什麼改變了。我有這段代碼:C中的內存分配和指針

int * arr[10]; 
for(i=0; i<5;i++) 
{ 
    int index = i; 
    arr[index] = malloc(sizeof(int*)); 
    int i = 2 * index; 
    *arr[index] = i; 
    printf("arr [%d] = %d\n", index, *arr[index]); /* should be 0, 2, 4, 6, 8 */ 
} 

但是我發現的是,如果不是使用* ARR [指數] =我,我用ARR [指數] = &我我不需要malloc 。我一直認爲這兩件事情本質上是一回事,但必須有一些我不明白的關鍵區別,以保證使用malloc

我真的很困惑,爲什麼我真的需要malloc。我對內存分配相當陌生,但我不明白什麼時候應該使用它(顯然),並且想知道是否有人可以爲我解決這個問題。

+0

我想了解最重要的事情是堆棧(局部變量聲明)與從堆中分配內存分配的東西之間的差別(malloc的。) – Marvo

回答

4

試試這個代碼,而不是:

int * arr[10]; 
for(i=0; i<5;i++) 
{ 
    int index = i; 
    int value = 2*i; 
    arr[index] = malloc(sizeof(int*)); 
    *arr[index] = value; 
} 

for (i=0; i<5; i++) 
{ 
    int index = i; 
    printf("arr [%d] = %d\n", index, *arr[index]); /* should be 0, 2, 4, 6, 8 */ 
} 

如果你讓你的建議進行修改,你現在有不確定的行爲。而此代碼仍然有效。

你會有未定義的行爲,因爲*arr[0]現在指向一個堆棧內存已經留下範圍。


您的malloc實際上應該是malloc(sizeof(int))。您正在爲int分配空間,而不是爲int *分配空間。

+0

你不應該分配'的malloc(的sizeof(int)的) ;'? – 2013-04-02 18:41:17

+0

@Armin:絕對。這是我沒有注意到的代碼中的一個錯誤。 –

0

一個關鍵的區別是,&i將不再存在,一旦i超出範圍(或者,相反,這段內存可以重用於別的東西......可能不會包含您認爲它包含的東西) 。

0

編輯:我說下面你沒有說明如何i被宣佈。實際上,如果在循環中使用i,則重新聲明它,隱藏原始值。無論如何,i將在循環結束時超出範圍,或者可能在例程結束時結束。

您不顯示如何在這裏聲明i。但是,在大多數情況下,它會是一個局部變量或者傳遞給方法的參數。無論哪種情況,該變量的空間都在堆棧中聲明。你可以用&i取這個變量的地址,但是這個變量在方法結束後會消失,代碼將這些值從堆棧中彈出。只要您需要,您可能會感到幸運,並保持該價值。但是現在調用另一種方法的時候,這個價值很可能會被覆蓋和繁榮,你的程序最多會表現得不正確。

如果i是全局聲明的,那麼你可以逃脫這個。

此外,即使在更改i的值後,您仍指向相同的地址。如果在例程結束時打印出數組的所有值,則會看到它們都是相同的值 - 您輸入數組的最後一個值。這是因爲數組中的每個條目指向相同的位置。

+0

它們實際上在循環體內映射了'i'與本地聲明的一個。 –

+0

啊,你說得對。所以他隱藏了循環中的價值。伊克!看看循環之後數組的轉儲真的很有意思,儘管它可能與我之前的每一個化身都在同一個地方。 – Marvo

+0

這就是爲什麼它有助於提高編譯器的警告級別。 =) – Marvo

1

是的,我認爲這很難理解,因爲我被重新定義在中間。我現在將重寫代碼。我寫了我而不是索引和2 *我而不是重新定義的我。

int * arr[10]; 
for(i=0; i<5;i++) 
{ 
    arr[i] = malloc(sizeof(int)); 
    *arr[i] = 2*i; 
    printf("arr [%d] = %d\n", i, *arr[i]); /* should be 0, 2, 4, 6, 8 */ 
} 

在這裏你不需要動態存儲器,你知道將使用數組0-4。當你不知道你需要多少數據時,你需要動態記憶。這段代碼是寫的,所以你的代碼的其餘部分仍然可以工作,但是沒有malloc。

int array[5]; 
int **arr=array; 

以下代碼裝置,該陣列[指數]應指向存儲器ADRESS i被存儲在它不會複製是在I的值,所以當改變i或我被刪除,這會導致這個指針發生故障,並在以後引發問題。你不應該這樣做。

arr[index] = &i 
1

這樣寫的:

*arr[index] = i; 

方式:的i的值複製到記憶位置指向arr[index](這是在你的代碼前面分配)。

arr[index] = &i; 

方式:的i地址複製到arr[index]

在你的代碼i被裏面的for循環自動創建,只存在循環中。一旦你離開循環(範圍),用於存儲i的內存就可以自由成爲新創建的變量的一部分。

由於沙爾斯建議,儘量原來外面看值循環看到一些有趣的結果。