2012-04-07 25 views
2

好吧,所以我教我的女朋友一些C++,她寫了一個程序,我認爲不會工作,但它做到了。它訪問數組中的另一個元素,然後存在(例如,訪問數組[5]爲大小爲5的數組)。這是一個緩衝區溢出的實例嗎?我的想法是,它正在寫入/直接訪問數組後,是否正確?這裏基本上我的問題是......爲什麼這個工作?數組溢出(爲什麼這個工作?)

#include <iostream> 

using namespace std; 

int main() 
{ 
int size; 

cout << "Please enter a size for the array." << endl; 
cin >> size; 
cout << endl; 

cout << "There are " << size << " elements in this array." << endl; 
cout << endl; 
cout << endl; 
cout << endl; 

int array[size]; 

for (int counter = 1; counter <= size; counter++) 

{ 
    cout << "Please enter a value for element " << counter << "." << endl; 
    cin >> array[counter]; 

} 

cout << endl; 
cout << endl; 


for (int counter = 1; counter <= size; counter++) 

{ 
    cout << "Element " << counter << " is " << array[counter] << "." << endl; 
    cout << endl; 

} 

cout << "*bing! :)" << endl; 
cout << endl; 


return 0; 
} 

回答

16

這是未定義的行爲。 UB有許多口味。這裏有幾個:

1)它會踢你的狗。

2)它會重新格式化您的硬盤驅動器。

3)它會毫無問題地工作。在你的情況下,使用你的編譯器,在你的平臺上,在這個特定的日子,你會看到(3)。但在其他地方嘗試,你可能會得到(1),(2)或其他完全(最有可能是訪問衝突)。

+5

它也可能導致矩陣中的一個小故障。 – dreamlax 2012-04-07 04:45:04

4

C/C++在使用數組時不會執行邊界檢查。

由於您聲明瞭基於堆棧的數組。訪問數組邊界之外的部分將訪問已經分配的堆棧空間的另一部分。

所以基本上當你訪問超出範圍的東西時,除非它完全超出堆棧內存,否則不會拋出分段錯誤。

對於數組邊界,C/C++很危險!

+0

我對帶有動態大小變量的堆棧的內存佈局有點好奇。在我的筆記本電腦上(i686-apple-darwin10-gcc-4.2.1(GCC)4.2.1(Apple Inc. build 5666)(dot 3))gdb的「print(char *)&size - (char *)&array [size] 「說84或96(取決於我輸入的尺寸)。我不確定他們之間有什麼。 valgrind甚至沒有發現錯誤。我拆開了這個功能,但是組裝比我想要的要複雜得多。 – 2012-04-07 05:14:01

0

首先,數組大小需要是恆定的,以便大小是可變的,所以,無論是在編譯時固定所述陣列的大小或使用動態存儲器分配

int arr[size] 

將不起作用。

即 任

const int size =5; 
    int arr[size]; 

int arr[5]; 

int* arr = new int[5]; 

AND ..

隔空指針將一個元件以外的端部數組保證在C++中工作。這對STL提供的許多算法很重要。但是,由於這樣一個指針實際上並不指向aray的一個元素,所以它可能不會用於讀寫。另一方面,在初始元素之前取元素地址的結果是不確定的,應該避免。

即你可以取那個變量的地址,然後回來但不能使用它! !

+0

是什麼?不能保證陣列之外的元素能夠工作(分段錯誤)。另外Size是int類型,它只是說int size = 5; int arr [5]。這個答案是非常錯誤的。 – Kevin 2012-04-07 04:50:45

+2

變長數組是C的一個特性,它在許多C++編譯器中作爲擴展實現。 'int arr [size];'是有效的C99。 – dreamlax 2012-04-07 04:57:39

+0

@Kevn,你可以把一個元素的地址放在數組的末尾,但是你不能取消這個地址的引用(http://stackoverflow.com/questions/1021021/c-element-beyond-the-end -of-一個陣列)。然而,這個問題並不真正相關。 – 2012-04-07 05:02:42

0

在這裏,你知道數組索引從0和轉到開始5

你輸入你的5計數器,它從1轉到5

您正在使用索引1計數器1,指標2開始couter 2等等。

索引0仍然沒有輸入值並且包含垃圾值。

1

堆棧非常大。在Windows上,it's 1 MB

由於程序沒有太多的工作,數組將被分配到接近堆棧的開始位置。這意味着陣列的末尾和堆棧的末端之間會有幾乎1 MB的空白空間。

那麼這是什麼意思?當你寫過數組的末尾時,你只是在打斷你自己的堆棧空間,而不是其他程序,所以操作系統不會阻止你並且程序繼續運行。

+1

堆棧增長減少,所以空的部分不在數組的開始,而不是結束。否則正確。 – 2014-11-01 18:25:16

+0

是的,在VS2013中,我曾經聲明過一個數組'int a [65535]',直到'a [i]','i == 84330',程序拋出一個異常。 – 2016-05-10 00:39:02