"Damenproblem": Programmabsturz bei For-Schleifenaufrufen?
-
So ist der Code erst mal soo, dass man ihn lesen kann.
class Schachbrett{ public: int n; bool** Feld; Schachbrett(int breite) { n = breite; bool** Feld = new bool* [n]; for(int i=0;i<n;i++) Feld[i] = new bool[n]; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { Feld[i][j] = true; } } } void printFeld() { for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { cout << Feld[i][j]; } } } };Tja, wo ist dein Problem?
Mag es viellicht sein, dass eine lokale variablendefinition eine globalere überlagert?Tip:
membervariablen macht man normalerwesie private und gibt ihnen außerdem den präfix m_xxx.
- Genau aus diesem Grund, weil man so interne von lokalen Variablen unterscheiden kann, da es häufig input oder lokale Variablen gibt, die ein Datum enthalten, was dann nach intern übertragen wird.Edit:
Außerdem ist es nicht wirklich schwer zu finden, wenn man in die accessviolation läuft und dann im Debugger feststellt, dass die Variable NULL ist, die dereferenziert werden sollte.
-
Tip:
membervariablen macht man normalerwesie private und gibt ihnen außerdem den präfix m_xxx.Danke für den Tip! Ich bin in der Hinsicht gern bissle schlampiger, als gesund ist.

Außerdem ist es nicht wirklich schwer zu finden, wenn man in die accessviolation läuft und dann im Debugger feststellt, dass die Variable NULL ist, die dereferenziert werden sollte.
Also ich verwende den Editor Dev-C++ unter Windows, und dort brichts einfach ab...
temp.exe hat ein Problem festgestellt und muss beendet werden.Bzw:
AppName: temp.exe AppVer: 0.0.0.0 ModName: temp.exe ModVer: 0.0.0.0 Offset: 00010a09Das sagt mir leider alles nichts.
Und wo dereferenziere ich denn? Ich versteh grad nur Bahnhof...
Tja, wo ist dein Problem?
Mag es viellicht sein, dass eine lokale variablendefinition eine globalere überlagert?Ist das jetzt eine ernste Frage oder rhetorisch gemeint? Ich seh da wirklich keine lokale Variable, die eine globale überlagert...

Ist vielleicht die Deklaration oder Initialisierung des Feldes fehlerhaft?

Ich bin schwer verwirrt...
-
class Schachbrett{ public: int n; bool** Feld; Schachbrett(int breite) { n = breite; bool** Feld = new bool* [n]; // <--------------- HIER for(int i=0;i<n;i++) Feld[i] = new bool[n]; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { Feld[i][j] = true; } } } void printFeld() { for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { cout << Feld[i][j]; } } } };Edit:
So würde ich das schreiben:class Schachbrett{ public: Schachbrett(int breite) { m_width = breite; m_feld = new bool [m_width * m_width]; for(int i=0; i<m_width * m_width; ++i) { m_feld[i] = true; } } void printFeld() { for(int i=0; i < m_width*m_width; ++i ) { if( i%m_width == 0) cout << endl; cout << m_feld[i] << " "; } } int getFieldWidth() { return m_width; } bool& operator() (int x, int y) { assert( x<m_width ); assert( y<m_width ); return m_feld[ x +m_width* y]; } private: int m_width; bool* m_feld; };Zugriff auf feldelemente bekommst du dann über:
Schachbrett b(6); b.printFeld(); b(4,5) = false; bool upperleft = b(0,0);Ich kann nicht glauben, dass (obwohl veraltet und kaum noch zu gebrauchen) dev c++ keinen debugger hat.
-
Vielen Dank für die Geduld!

Also deine Variante kann ich nachvollziehen. Da das aber eine Programmieraufgabe aus der Uni ist, und wir von der Aufgabenstellung her gezwungen sind, (mehrdimensionale) dynamische Felder zu verwenden, die nachher auch wieder gelöscht werden sollen, kann ich das leider nicht so machen.
Ich versteh leider immernoch nicht, wieso
bool** m_Feld = new bool* [m_groesse]; for(int i=0;i<m_groesse;i++) m_Feld[i] = new bool[m_groesse];keine korrekte Definition von einem mehrdimensionalen dynamischen Feld ist.
Mir ist im übrigen aufgefallen, dass das Programm ohne den aufruf von b.printFeld() problemslos kompiliert und ausgeführt wird...
Ein Beispiel aus einem Programm, das reibungslos funktioniert hat:
double** A = new double* [n]; for(int i=0;i<n;i++) A[i] = new double [n]; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { A[i][j]=0; } }Liegt es dann nicht vielleicht doch an der printFeld()-Methode?

Btw, kannst du mir einen guten C++-Editor für Windows empfehlen? Bin selbst nicht grad glücklich mit dem Dev-C++...
-
Haste "m_Feld" schon wieder zweimal definiert?
-
hurz schrieb:
Vielen Dank für die Geduld!

Also deine Variante kann ich nachvollziehen. Da das aber eine Programmieraufgabe aus der Uni ist, und wir von der Aufgabenstellung her gezwungen sind, (mehrdimensionale) dynamische Felder zu verwenden, die nachher auch wieder gelöscht werden sollen, kann ich das leider nicht so machen.
Übrigens ein gutes stichwort:
Du (ich auch in meinem Beispiel) hast vergessen einen destructor zu definieren, der die arrays delete[]ed .Ich versteh leider immernoch nicht, wieso
bool** m_Feld = new bool* [m_groesse]; for(int i=0;i<m_groesse;i++) m_Feld[i] = new bool[m_groesse];keine korrekte Definition von einem mehrdimensionalen dynamischen Feld ist.
Ich habe nicht gesagt, dass sie falsch sei.
Du deklarierst aber eine lokale variable, die genauso heißt wie die membervariable.
Die lokale Variable hat eine stärkere Bindung als die Membervariable.
Dh du weist einer lokalen variable den speicher deines tollen multidim arrays zu.
Die variable liegt aber auf dem Stack und wird am ende der Funktion gelöscht (die is ja lokal).
Also ist die membervariable deiner Klasse unberührt geblieben (undefinierter inhalt, da nirgens initialisiert).
Außerdem hast du speicher alloziert, von dem die einzige Referenz entfernt wurde -> das heißt der kann nicht mehr gelöscht werden -> memory leak.in der printFeld methode wird nun auf die membervariable Feld (uninitialisiert) zugegriffen -> zeigt irgendwo hin im speicher -> Zugriffsverletzung.
Mir ist im übrigen aufgefallen, dass das Programm ohne den aufruf von b.printFeld() problemslos kompiliert und ausgeführt wird...
Ein Beispiel aus einem Programm, das reibungslos funktioniert hat:
double** A = new double* [n]; for(int i=0;i<n;i++) A[i] = new double [n]; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { A[i][j]=0; } }Liegt es dann nicht vielleicht doch an der printFeld()-Methode?

an der liegt es auch nicht. Hier wirkt sich nur dein Fehler aus dem Konsttruktor aus.
Btw, kannst du mir einen guten C++-Editor für Windows empfehlen? Bin selbst nicht grad glücklich mit dem Dev-C++...
Visual Studio 2008 Express c++
Code::BlocksSind die beliebtesten IDEs unter Windows. Beide Kostenlos und mit aktueller Standardbibliothek.
class Schachbrett{ public: Schachbrett(int breite) { m_width = breite; m_feld = new bool* [m_width]; for(int i=0;i<m_width;i++) { m_feld[i] = new bool[m_width]; for(int j=0;j<m_width;j++) { m_feld[i][j] = true; } } } ~Schachbrett() { for(int j=0;j<m_width;j++) { delete[] m_feld[j]; } delete[] m_feld; } void printFeld() { for(int i=0;i<m_width;i++) { for(int j=0;j<m_width;j++) { cout << m_feld[i][j]; } cout << endl; } } int getFieldWidth() { return m_width; } bool& operator() (int x, int y) { return m_feld[x][y]; } private: int m_width; bool** m_feld; };
-
Auch wenn dir das vielleicht momentan unangebracht erscheint, solltest du immer im Hinterkopf behalten, dass die C++-Standardbibliothek bereits fertige komfortable Klassen zur dynamischen Speicherverwaltung bereitstellt.

Falls du einmal keine Lust mehr auf
newunddeletehast, schlag mal zur STL (Standard Template Library) nach. In diesem Forum findest du bei den Artikel eine gute Einführung.
-
furz schrieb:
Haste "m_Feld" schon wieder zweimal definiert?
Ja, sorry, tut mir leid...

vlad schrieb:
Ich habe nicht gesagt, dass sie falsch sei.
Du deklarierst aber eine lokale variable, die genauso heißt wie die membervariable.Jetzt hab ich meinen Fehler erkannt. Im Nachhinein sag ich da nur: aufm Schlauch gestanden... ^^ (Ich war der richtigen Lösung aber doch sehr nah; hätte ich das "bool**" weggelassen...
)Visual Studio 2008 Express c++
Code::BlocksSind die beliebtesten IDEs unter Windows. Beide Kostenlos und mit aktueller Standardbibliothek.
Vielen Dank!

Falls du einmal keine Lust mehr auf new und delete hast, schlag mal zur STL (Standard Template Library) nach. In diesem Forum findest du bei den Artikel eine gute Einführung.
Danke für den Tip! Ich fürchte, ich kann und werde das nur zum privaten Interesse ausnutzen. Uni ist halt Uni, Vorgaben sind Vorgaben...

Vielen Dank für eure Hilfe und Geduld! :xmas1:
-
Tip:
membervariablen macht man normalerwesie private und gibt ihnen außerdem den präfix m_xxx.private ja. Präfix nein. Wozu gibt es namensräume.
-
ich denke, das wird dir jeder c++ entwickler bestätigen, dass es üblich ist, privaten member den Präfix m_ zu geben.
Das ist auch insofern sinnvoll, dass man, wenn man code ließt auf den ersten blick sieht, ob es sich um eine lokale Variable, membervariable oder, im falle, dass man g_ und s_ oder i_ , o_ ind io_ für globale, statische, funktionsinput, -output und -in/output benutzt, auch um jene handelt.
-
vlad_tepesch schrieb:
ich denke, das wird dir jeder c++ entwickler bestätigen, dass es üblich ist, privaten member den Präfix m_ zu geben.
Das ist auch insofern sinnvoll, dass man, wenn man code ließt auf den ersten blick sieht, ob es sich um eine lokale Variable, membervariable oder, im falle, dass man g_ und s_ oder i_ , o_ ind io_ für globale, statische, funktionsinput, -output und -in/output benutzt, auch um jene handelt.Mal davon abgesehen, dass ich das m/m_/... für Membervariablen auch verabscheue gabs die Diskussion ja nun echt schon ein zwei mal ^^ Vll sollte man ja in Zukunft wieder versuchen nicht ganz so sehr vom Thema abzuschweifen
-
Kein_präfix schrieb:
Wozu gibt es namensräume.
Das Argument gegen Präfixe bei Membervariablen.

-
ganz egal, wie man das sieht - trotzdem ist es üblich.
Die Regelung findet sich sicherlich auch in den Programmierrichtlinen der meisten Unternehmen.
-
vlad_tepesch schrieb:
ganz egal, wie man das sieht - trotzdem ist es üblich.
Die Regelung findet sich sicherlich auch in den Programmierrichtlinen der meisten Unternehmen.
Meiner Meinung nach ist das "üblich" völlger Quatsch. Die Richtlinien sind eher weit gestreut und jeder macht es irgendwie anders. Sieht man sehr gut daran, welche Vorlieben in diesem Forum herrschen

Ich würde es jedenfalls ganz sicher nicht einfach als Standard annehmen, das wäre von mir aus gesehen, ein völlig falsches Bild. Ich wäre aber natürlich glücklich darüber, wenn mein m_ so üblich wäre

Grüssli