2014-03-03 88 views
0

我很難找到這樣的問題的具體答案,但我會解釋我認爲這應該(不)工作的方式,也許有人可以告訴我我錯在哪裏。C++循環,範圍和堆棧(爲什麼這個工作?)

我在棧中創建一個大小爲10的整數數組。然後我使用for循環將整數0-9加載到該數組中。當for循環結束時,堆棧指針返回到初始化arr1後的位置,但這些值仍然存在於內存中,並且數組仍然指向它們。

然後,我使用另一個for循環來氾濫堆棧,它應該覆蓋在第一個for循環中創建的值,現在當我去訪問arr1中的值時,它們應該指向值爲5000的整數

當我打印數組時,它仍然打印出數字0-9。爲什麼這個工作?我認爲在一個循環中聲明的數據在超出範圍時從堆棧中彈出。謝謝

int main(void) 
{ 
    int arr1[10]; 

    for(int i = 0; i < 10; i++) 
     arr1[i] = i; 

    for(int i = 0; i < 500; i++) 
     int a = 5000; 

    for(int i = 0; i < 10; i++) 
     cout << arr1[i] << endl; 

    system("PAUSE"); 

    return 0; 
} 

回答

2

您似乎誤解了C++中的數據生命週期。在範圍塊中聲明本地數據(無論是在函數,循環還是其他控制結構中)時,它將一直保留在堆棧上,直到該範圍塊結束。

這意味着整個arr1保持分配和堆棧,直到main()完成,無論你做了什麼。它不會被相同函數中的後續局部變量或嵌套在更深範圍塊中的變量覆蓋。

在您的第二個循環中,變量a(理論上)在循環體的每個迭代上被創建並銷燬()。這意味着在循環中你沒有500個a實例 - 你只有一個。 (實際上,編譯器幾乎肯定會優化這個,因爲它沒有做任何有用的工作。)

+0

我的印象是C++中的一個數組只是一個指向內存中某個位置的指針,這個位置的數據順序依次存在。因此,如果這些值是在for循環中創建的,並且該循環超出了範圍,那麼數組指向的值是否會從堆棧中彈出?謝謝 –

+0

@JohnSavage:你的印象不正確。 C++中的數組不是指向內存中存在序列的位置的指針,它是*序列。值不是在'for'循環中創建的,它們是在創建數組時創建的(儘管在這種情況下它們沒有被初始化,這會帶來它自己的危險)。它們在'for'循環中被修改。 –

+0

@JohnSavage你是正確的,在一個數組變量*行爲*像一個指針(並可以很容易地轉換爲一個指針)。但是,對於靜態數組(在你的例子中),當你聲明它時,整個數組實際上被創建*(添加到堆棧)。循環內的代碼只是分配(即改變)數組中的值。 –

2

不,數組不是「指向」的值。 arr1是10個整數,它不是整數的10個指針。這些值存儲在數組中。創建並立即銷燬另一個變量a,即使這樣做了500次,也不會改變存儲在數組arr1中的內容。

你可能來自一種語言,根據定義,變量和/或數組元素是對象的引用。在C++中情況並非如此。

對於什麼是值得的,C++實現通常不會在進入和退出for循環時移動堆棧指針。通常他們只爲每個函數生成一個包含所有函數需要的變量的棧幀,儘管只要他們在正確的時間調用析構函數就可以做他們喜歡的事情。

+0

我很好奇哪種語言會使OP的構造成爲問題。不尋找答案;寧可考慮這種語言是非常深奧的。 –

+0

@CaptainGiraffe:我不認爲有一種語言是一個問題,我認爲提問者已經將Perl/Python /知識與「在C++中可以在堆棧上創建對象」這一事實相結合,然後來到不正確的結論是,arr [i] = i'使得'arr [i]'指向一個比'arr1'更靠上堆棧的對象,因此可以在該分配的範圍退出後覆蓋它。或類似的規定。 –

+0

我的印象是,C++中的一個數組只是一個指向內存中某個位置的指針,在這個位置中,該數據類型的值序列依次存在。因此,如果這些值是在for循環中創建的,並且該循環超出了範圍,那麼數組指向的值是否會從堆棧中彈出?謝謝 –

0

正如你所說的:「在循環中聲明的數據在超出範圍時彈出堆棧。那是真實的。但在你的示例中,數組不是在循環內部聲明的。它在循環之外聲明,並且仍然處於main()的其餘部分的範圍內。

如果你有這樣的事情:

char * arr1[10]; 

for(int i = 0; i < 10; i++) 
{ 
    char * text[16]; 
    sprintf(text, "%d", i); 
    arr1[i] = text; 
} 
for(int j = 0; j < 10; ++j) 
    printf ("%s\n", arr1[i]); 

那麼這會崩潰,因爲文本[]數組的第一個循環內聲明的,他們走出去的範圍在循環結束後,留下的指針超出範圍的變量。我認爲這是你的想法。

0

arr1a處於完全獨立的存儲位置。

printf("%lu %p %p %p", \ 
    sizeof(int), (void *)&arr1[0], \ 
    (void *)&arr1[9], (void *)&a); 

例如,我的機器上,我得到這個輸出:

4 0x7fff5541e640 0x7fff5541e664 0x7fff5541e63c

正如你所看到的,&a爲四,您可以使用此行證明了這一點字節(sizeof(int))來自arr1的第一個元素。

下面的語句:

for(int i = 0; i < 500; i++) 
    int a = 5000; 

不有,你懷疑的效果。它只是一次又一次地將值5000賦值給變量a,或者已經優化並且僅僅做了一次,甚至根本不做,因爲不使用a

+0

或者已經過優化,並且從未這樣做,因爲變量未被使用。 –

+0

@JosephMansfield非常真實。 –