Compiler-, Logik-, oder Verständnissfehler?

Erst Code, dann die Diskusion:

Code:
#include <iostream>
using namespace std;

int main(){
	int x[2]={1,2};

	do{
	x[0] = x[0] * 2;
	x[1] = x[1] * x[0];
	x[2] = x[0]*x[1];
	cout << x[1] << ",";
	}
	while(1);
	
return 0;

}

Hi C++'er:

Ich habe eben mal aus langeweile (warum weiß ich auch nemmer) obigen Code geschrieben.....

Kurz zu dem, wie ich das Programm oben verstehe:
Code:
zu Zeile 5 	int x[2]={1,2};

bei einem Feld der länge 2, habe ich die Feldelement 0 und 1.
Wenn ich nun auf 2 etwas ändern will, zugreifen will ect... dann sollte ich doch eigentlich einen Abstutz bzw. eine Compilerwarnung/Fehlermeldung bekommen.
Unter VIsual Studio 2008 jedoch läuft das Programm.

Weiterhin wenn ich das Programm einfach laufen lasse (egal ob Release oder Debug) bekomme ich lauter 0en raus. Was ja eigentlich falsch sein müsste!
>>> STOP: mein fehler, die ersten Zahlen werden normal berechnet, danach 0er weil ich sicherlich den definitionsbereich der INT Zahlen überschreite.......

ABER:
starte ich nun das Programm wie oben beschrieben im DebugModus (mit F10 "Prodezurschritt") und ändere die Zeile 11 in:
Code:
cout << x[2] << ",";
dann dürfte ich doch nichts ausgegeben bekommen? (oder zumindest ein Fehler).
Jedoch rechnet der fleißig weiter.

Ist der Compiler hier einfach "schlau" und erweitert mein x um eine feldgröße im Arbeitspeicher?
Normalerweise dürfte das ja nicht passieren, oder?
 
ich war den beitrag noch am bearbeiten!!! :)
sorry.... ^^
bin fertig, hoffentlich habe ich mich auch verständlich ausgedrückt! bin mal für paar stunden weg, schaue aber bald wieder rein ;)
interesiert mich nämlich was IHR dazu sagt ;-)
 
In C++ eine Warnung? Die C++ ler sind doch gerade darauf stolz, dass sie soviel "Freiheit" mit ihrer Sprache haben ;).
Da der Compiler anscheinden keine Arraygrenzen prüft und es sich sonst um gültige Anweisungen handelt, gibt es keinerlei Probleme. Du greifst natürlich auf "nicht reservierten" Speicher zu und niemand garantiert Dir, dass der in x[2] gespeicherte Wert nicht durch irgendwas anders überschrieben wird (denn fürs Array wurden ja nur 2 Ints reserviert).Versuche noch eine zusätzliche lokale Variable mit einem Wert anzulegen (einmal vor, einmal nach der Arraydefinition) und die Werte auszugeben und mit etwas Glück (wenn die Optimierungen nicht zu stark sind und nicht zuviele Zusatzbytes zu den Arrays wegen der Speicherausrichtugn hinzuaddiert werden) wirst Du sehen, was gemeint ist. Rein technisch gesehen ist Zugriff auf x[2] nichts anderes als Zugriff auf den Speicher an: Adresse von X + 2*INT_Size.
Warum kein Fehler kommt: kommt darauf an, wieviele Bytes wirklich reserviert werden und wo das Array hinkommt (lokaler Speicher, globaler Speicher, Heap). Dadurch überschreibt man zum Beispiel nicht unbedingt nur kritische Sachen. Die Ausgabe klappt, da man jede Speicheradresse lesen kann, solange der Speicher als lesbar markiert ist (d.h das Betriebsystem den Zugriff zulässt). Es kommt wirklich auf die Umsetzung des Compilers an - versuche mal paar hundert Werte mehr "unerlaubt" zu beschreiben.
z.B macht g++ das hier daraus:
Code:
00401446    .  55                         PUSH EBP
00401447    .  89E5                       MOV EBP,ESP
00401449    .  51                         PUSH ECX                                                                 ;  a.004734B4
0040144A    .  83EC 24                    SUB ESP,24
0040144D    .  E8 FE5A0000                CALL a.00406F50
00401452    .  C745 F4 01000000           MOV DWORD PTR SS:[EBP-C],1
00401459    .  C745 F8 02000000           MOV DWORD PTR SS:[EBP-8],2
00401460    >  8B45 F4                    MOV EAX,DWORD PTR SS:[EBP-C]
00401463    .  01C0                       ADD EAX,EAX                                                              ;  a.004734B4
00401465    .  8945 F4                    MOV DWORD PTR SS:[EBP-C],EAX                                             ;  a.004734B4
00401468    .  8B55 F8                    MOV EDX,DWORD PTR SS:[EBP-8]
0040146B    .  8B45 F4                    MOV EAX,DWORD PTR SS:[EBP-C]
0040146E    .  0FAFC2                     IMUL EAX,EDX
00401471    .  8945 F8                    MOV DWORD PTR SS:[EBP-8],EAX                                             ;  a.004734B4
00401474    .  8B55 F4                    MOV EDX,DWORD PTR SS:[EBP-C]
00401477    .  8B45 F8                    MOV EAX,DWORD PTR SS:[EBP-8]
0040147A    .  0FAFC2                     IMUL EAX,EDX
0040147D    .  8945 FC                    MOV DWORD PTR SS:[EBP-4],EAX                                             ;  a.004734B4
00401480    .  8B45 F8                    MOV EAX,DWORD PTR SS:[EBP-8]
00401483    .  894424 04                  MOV DWORD PTR SS:[ESP+4],EAX                                             ;  a.004734B4
00401487    .  C70424 B4344700            MOV DWORD PTR SS:[ESP],a.004734B4
0040148E    .  E8 6DA50300                CALL a.0043BA00
00401493    .  C74424 04 00804700         MOV DWORD PTR SS:[ESP+4],a.00478000
0040149B    .  890424                     MOV DWORD PTR SS:[ESP],EAX                                               ;  a.004734B4
0040149E    .  E8 C5A70600                CALL a.0046BC68
004014A3    .^ EB BB                      JMP SHORT a.00401460
es gibt kein return mehr und für das Array werden 0x24 Bytes reserviert, was eigentlich doch etwas zuviel des Guten ist - da kann man also noch 7 weitere Einträge beschreiben, ohne dass etwas zu befürchten wäre ;)
 
dein Computer ist nicht so schlau und sichert sich mehr Arbeitsspeicher, sondern er greift einfach hart auf den darauffolgenden Speicher zu...
(edit: wie CDW, der mir zuvor kam, schon geschrieben hat :) )

Sowas kann mal ziemlich in die Hose gehen von wegen Überschreiben anderer Variablen...

Beispiel:
Code:
#include <iostream>

using namespace std;


int main()

{
	int z1=9;
	int z2=8;
	int zahlen[3]={2,3,4};
	int z3=7;
	int z4=6;
	
	int array_elemente=sizeof(zahlen)/sizeof(int);
	
	cout << "Variablen und Speicher-Adressen ausgeben : " << endl;
	cout << "===========================================" << endl << endl;
	cout << "die normalen Variablen:" << endl;
	cout << "z1 (" << &z1 << ") = " << z1 << endl;
	cout << "z2 (" << &z2 << ") = " << z2 << endl;
	cout << "z3 (" << &z3 << ") = " << z3 << endl;
	cout << "z4 (" << &z4 << ") = " << z4 << endl;
	
	cout << endl << "das Array - ueber seine Grenzen hinweg:" << endl;
	for(int i=-10;i<10;i++)
	{
		if(i<0 || i>(array_elemente-1))
		{
			cout << "ATTENTION : ";
		}
		else
		{
			cout << "OKAY      : ";
		}
		cout << " zahlen[" << i << "] (" << &zahlen[i] << ") " << zahlen[i] << endl;
	}

	cout << endl << endl << endl << "nun schreiben wir Werte in das Array (ueber die grenzen hinweg)" << endl << "angefangen mit 100 und dann in jedes Feld eine Zahl höher" << endl << endl;

	int neuer_wert=100;
	
	for(int i=-10;i<10;i++)
	{
		zahlen[i]=neuer_wert++;
		cout << zahlen[i] << "\t";
	}
	cout << endl << "done." << endl << endl;

	
	
	cout << "nun geben wir die Variablen und Speicher-Adressen erneut aus : " << endl << endl;
	cout << "die normalen Variablen:" << endl;
	cout << "z1 (" << &z1 << ") = " << z1 << endl;
	cout << "z2 (" << &z2 << ") = " << z2 << endl;
	cout << "z3 (" << &z3 << ") = " << z3 << endl;
	cout << "z4 (" << &z4 << ") = " << z4 << endl;
	
	cout << endl << "das Array - ueber seine Grenzen hinweg:" << endl;
	for(int i=-10;i<10;i++)
	{
		if(i<0 || i>(array_elemente-1))
		{
			cout << "ATTENTION : ";
		}
		else
		{
			cout << "OKAY      : ";
		}
		cout << " zahlen[" << i << "] (" << &zahlen[i] << ") " << zahlen[i] << endl;
	}
	
	
	return 0;
}

und mit etwas Glück sind deine normalen Integer-Variablen (z1 bis z4) am Ende mit neuen Werten überschrieben, obwohl ich doch nur das Array mit neuen Werten versehen habe :-)



Wenn du wirklich dynamische Arrays brauchst, dann verwende die Klasse vector aus der STL (standard template library)

http://www.cppreference.com/cppvector/index.html
http://www.fredosaurus.com/notes-cpp/stl-containers/vector/header-vector.html
http://www.sgi.com/tech/stl/Vector.html

http://www.google.com/search?hl=de&...de:unofficial&q=vector+stl+c++&btnG=Suche&lr=

(kann dir auch ma paar Code-Schnipsel geben, falls Interesse vorhanden... war jetzt nur zu faul... ;) )
 
ausgezeichnete und verständliche erkläruingen!
naja bis auf den asm code, den kann ich noch nicht lesen / auswerten ;-)

Wenn du wirklich dynamische Arrays brauchst, dann verwende die Klasse vector aus der STL (standard template library)

ja, die sind mir schon bekannt, habe die doch auch für mein bintree benutzt -> fürs levelorder und vlt. auch für andere dinge, ich weiß das nicht mehr genau ^^

wie gesagt, ich habs nur zufällig programmiert und wollte so etwas gar nicht erst machen ;)
aber gut zu wissen....!


auch in diesem fall (siehe code unten) überschreibt er das array, jedoch nach dem return 0 sagt mir das program:
[quoteRun-Time Check Failure #2 - Stack around the variable 'x' was corrupted.[/quote]
-> ich glaube das ist ähnlich wie das was CDW gemacht hat, oder?
aber belassen wir es mal dabei ^^
Code:
#include <iostream>
using namespace std;

int main(){
	long double x[2]={1,2};

	for(int i=0;i<=3;i++){
	x[0] = x[0] * 2;
	x[1] = x[1] + x[0];
	x[2] = x[0] * x[1];
	cout << x[1] << "\n";
	}
return 0;
}
natürlich kann auch i<=x dort stehen (x beliebiger, ganzzahliger wert ^^), die grenze hab ich noch nicht getestet!
 
Hallo,
empfehlenswert wären ein paar Tutorials über die interne Funktionsweise des Computers, bischen Assemblerprogrammierung evt., dann wird das alles viel klarer.

Bin zwar nicht 100% vertraut wie C++ das alles nun in Assembler umsetzt, aber wie bereits gesagt, überschreibst du dort nicht initialisierten Speicher der evt. an anderer Stelle benutzt wird.
Wenn dieser nun deine Rücksprungadresse enthält, wird diese überschrieben und nachdem deine Schleife beendet wird, wird dieser Sprung ausgeführt und du landest irgendwo im Nirvana und enthälst diese Meldung.
 
Zurück
Oben