2012-04-07 15 views
2

Okay, also habe ich meiner Freundin C++ beigebracht, und sie hat ein Programm geschrieben, von dem ich dachte, es würde nicht funktionieren, aber es hat funktioniert. Es greift auf ein weiteres Element im Array zu, das dann vorhanden ist (z. B. Zugriff auf Array [5] für ein Array der Größe 5). Ist das eine Instanz eines Pufferüberlaufs? Meine Gedanken dazu sind, dass es direkt nach dem Array auf den Speicher schreibt/darauf zugreift, ist das korrekt? Grundsätzlich ist meine Frage hier ... warum funktioniert das?Array-Überlauf (warum funktioniert das?)

#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; 
} 

Antwort

16

Es ist undefiniertes Verhalten. UB kommt in vielen Geschmacksrichtungen. Hier sind ein paar:

1) Es wird Ihren Hund treten.

2) Es wird Ihre Festplatte neu formatieren.

3) Es wird ohne Probleme funktionieren.

In Ihrem Fall, mit Ihrem Compiler und auf Ihrer Plattform und an diesem bestimmten Tag, sehen Sie (3). Aber versuchen Sie es woanders, und Sie erhalten (1), (2) oder etwas anderes vollständig (höchstwahrscheinlich eine Zugriffsverletzung).

+5

Es kann auch einen Fehler in der Matrix verursachen. – dreamlax

4

C/C++ führt keine Grenzüberprüfung durch, wenn Arrays verwendet werden.

Da Sie ein Stack-basiertes Array deklarieren. Der Zugriff außerhalb der Grenzen des Arrays wird nur auf einen anderen Teil des bereits zugewiesenen Stack-Speicherplatzes zugreifen.

Wenn Sie also auf etwas zugreifen, das außerhalb der Grenzen liegt, wird kein Segmentierungsfehler ausgelöst, es sei denn, es ist vollständig aus dem Stapelspeicher entfernt.

C/C++ ist gefährlich mit Array-Grenzen nicht vergessen!

+0

Ich bin etwas neugierig auf das Speicherlayout des Stacks mit dieser dynamisch großen Variable. Auf meinem Laptop (i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (Punkt 3)) gdb's "Drucken (char *) & Größe - (char *) & Array [Größe] "sagt sowas wie 84 oder 96 (je nachdem, was ich als Größe eingebe). Ich bin mir nicht sicher, was zwischen ihnen ist. Valgrind erkennt den Fehler nicht einmal. Ich zerlegte die Funktion, aber die Montage war komplizierter als ich mir erhofft hatte. –

0

Zunächst müssen Array Größen so

int arr[size] 

arbeiten nicht konstant sein, wie Größe eine Variable ist, so, entweder die Größe des Arrays bei der Kompilierung beheben oder dynamische Speicherzuweisung verwenden.

d.h. entweder

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

oder

int arr[5]; 

oder

int* arr = new int[5]; 

UND ..

Einen Zeiger auf ein Element, über das Ende des Array funktioniert garantiert in C++. Dies ist wichtig für viele von der STL bereitgestellte Algorithmen. Da ein solcher Zeiger jedoch nicht auf ein Element des Arrays zeigt, kann er nicht zum Lesen und Schreiben verwendet werden. Andererseits ist das Ergebnis der Übernahme der Adresse des Elements vor dem Anfangselement undefiniert und sollte vermieden werden.

dh Sie können die Adresse der Variablen nehmen und dann zurückkommen, aber nicht verwenden! !!

+0

was? Die Übernahme von Elementen außerhalb des Arrays funktioniert nicht garantiert (Segmentierungsfehler). Darüber hinaus ist Größe vom Typ int, die nur sagt int Größe = 5; int arr [5]. Diese Antwort ist ziemlich falsch. – Kevin

+2

Arrays variabler Länge sind ein Merkmal von C, das als Erweiterung in vielen C++ - Compilern implementiert wurde. 'int arr [Größe];' ist gültig C99. – dreamlax

+0

@Kevn, Sie können die Adresse eines Elements direkt hinter dem Ende des Arrays nehmen, aber Sie können diese Adresse nicht dereferenzieren (http://stackoverflow.com/questions/1021021/c-element-beyond-the-end) eines Arrays). Nicht wirklich relevant für diese Frage jedoch. –

0

Hier wissen Sie, dass Array-Index beginnt bei 0 und gehe zu 5

Sie geben Ihre Zähler als 5, die 1 beginnt und gehe zu 5

Sie verwenden Index 1 für Zähler 1, Index 2 für zweiter und so weiter.

Index 0 haben immer noch keinen Eingabewert und enthalten einen ungültigen Wert.

1

Der Stapel ist sehr groß. Unter Windows it's 1 MB.

Da das Programm nicht viel bringt, wäre das Array nahe am Anfang des Stapels zugewiesen worden. Dies bedeutet, dass zwischen dem Ende des Arrays und dem Ende des Stacks fast 1 MB freier Speicherplatz vorhanden wäre.

Was bedeutet das? Wenn Sie über das Ende des Arrays schreiben, überschneiden Sie nur Ihren eigenen Stack-Bereich, nicht andere Programme, so dass das Betriebssystem Sie nicht stoppt und das Programm weiter läuft.

+1

Der Stapel wird kleiner, sodass der leere Teil nicht am Anfang, sondern am Ende des Arrays liegt. Sonst richtig. –

+0

Ja, in VS2013 habe ich einmal ein Array 'int a [65535]' deklariert, und bis für 'a [i]', 'i == 84330', löst das Programm eine Ausnahme aus. –