2016-12-14 132 views
0

我是新來的c + +和嘗試使用函數打印數組的練習。我創建了兩個數組arrarr2,如下所示。如何內存分配發生在c + +

int main(){ 

int arr[5] = {11, 12, 13, 14, 15}; 

int i =1; 
int* arr2 = &i; 
*arr2 =1; 
*(arr2+1) =2; 
*(arr2+2) =3; 
*(arr2+3) =4; 
*(arr2+4) =5; 

printArray(arr2,5);  
printArray(arr,5); 
} 

我想使用下面的函數打印這兩個數組。

void printArray(int arr[],int size){ 
    for(int i=0; i<size; i++){  
     cout<<*(arr+i)<<" "; 
    } 
    cout<<endl; 
} 

運行該程序後的結果是,

1 2 3 4 5 
2 3 4 5 15 

但該預期的結果,

1 2 3 4 5 
11 12 13 14 15 

有人能解釋發生在這裏,如果是內存問題分配高度讚賞,如果你可以解釋一個適當的圖。

+5

你有*未定義的行爲*。 'arr2'不是指向一個5'int'的塊,而是一個'int'。所以,'*(arr2 + 1)= 2; *(arr2 + 2)= 3; *(arr2 + 3)= 4; *(arr2 + 4)= 5;'邊界外的所有訪問。在'printArray()'函數中打印'arr2'時,同樣的問題仍然存在。 –

+2

這是未定義的行爲 – CoryKramer

+2

正如已經指出的那樣,這是UB,顯然你的編譯器決定在'arr'之前分配'i',這樣'(arr2 + 1)==&arr [0]' - 但是這是** NO **方式正確或保證(不同的編譯器或只是改變優化級別可能已經導致完全不同的效果) – UnholySheep

回答

3

您聲明在棧上聲明的變量:

int arr[5] = { 11, 12, 13, 14, 15 }; // 5xsizeof (int) bytes 
int i = 1; // sizeof (int) bytes on the stack 
int *arr2 = &i; // sizeof (void*) bytes on the stack 

現在arr2是指向int的指針。在另一個上下文中,它可能是一個指向動態分配數組的指針,但這裏並不是:它指向堆棧上的i的位置。當你這樣做:

*(arr2 + 1) = 2; 

您在棧,並從你的結果,它看起來像它的arr[0]地址,這是有點邏輯一致((即&i後馬上來了一個)上分配2到另一個地址但很好,因爲它是未定義的行爲,任何事情都可能發生)。

因爲你是在棧上分配的地址,你沒有得到段錯誤,但你做腐敗堆棧然而,這比獲得一個段錯誤更糟糕:

  • 段錯誤是清楚的信號告訴你你正在嘗試非法的內存訪問。你知道它發生的地方,你可以修復它。
  • 堆棧損壞會悄無聲息地發生,可能會被忽視,直到它崩潰程序,這可能發生在任何地方。這是「非法」內存訪問的結果,因爲該堆棧已經爲您的程序保留,所以未被檢測到。當然,調試它非常困難,因爲崩潰可能發生在與錯誤代碼完全無關的地方。
+0

「比獲得segfault差得多」我建議segfault是UB獲得的*最好*症狀之一,因爲它大聲地告訴你事情是錯誤的,從哪裏開始尋找 – Caleth

+0

@Caleth這正是爲什麼我說一個沉默的堆棧腐敗比segfault更糟糕。也許你的意思是改寫它看起來像段錯誤是一件積極的事情? – Rerito

+0

是的。無聲的堆棧損壞 - >忽略/未察覺 - >生產中的錯誤。 Segfault - >標識 - >固定 – Caleth

2

arr2不是數組。它是指向int i。你正在從不屬於你的記憶中讀取。

相反,使用:

int* arr2 = new int[how_long_array_you_want] 

不要忘記刪除arr2

+3

請不要向新的C++程序員推薦原始指針,C風格的數組和'new' /'delete'。 –

-2

wow no sigsegv? 只是factores的組合,可能(在機器內部)我在數組之前聲明的變量。 所以你不能這樣做。 變量「i」只爲整數分配一個槽。但是你需要5.當你做*(arr2 + 1)時,你會寫一個ungulty,鄰居隨機變量。在這種情況下可能是arr []。幸運的是,也是一個整數,否則你會得到一個SIGSEGV錯誤 因此,代碼將是

int i[5]; 
int *arr2=i; 

所以它的工作原理

+0

*「幸運的是一個整數」* - 不......因爲你指向一個地址的指針並不意味着一些基礎數據類型必須存在。它也不*工作*,它是未定義的行爲,恰好在OP機器和編譯器上產生了這種確切的效果 – UnholySheep

+0

Segfault與嘗試訪問的基礎類型無關。在這裏它不會出現段錯誤,因爲每個'arr2 + i'都指向棧上的內存。 – Rerito

+0

*「幸運的是,指針落入堆內」*除非指針指向的地址位於堆棧中。 – UnholySheep