Hallo,
ich bin gerade dabei, ein Programm zu schreiben, dass TicTacToe einmal
komplett durchrechnet, es ist noch nicht ganz fertig, da wollte ich es
mal testen und da kam dann bei der Programmausführung diese
Fehlermeldung:
Speicherzugriffsfehler (Speicherabzug geschrieben)
Googeln hat mir bisher auch nicht viel gebracht.
Falls ihr noch Fragen zum Code habt, stellt sie gerne, ich bin leider
nicht der geborene Code-Kommentator:-)
Schon mal Danke im Voraus,
Ivo
PS: Ich nutze Linux Mint und habe mit dem G++ folgendermaßen kompiliert:
g++ main.cpp -o main.out
PSPS: Bitte diskutiert nicht über den Sinn, bzw. Unsinn des Programms
und dass ich keine Makefiles nutze, etc. (Gut, ich hätte vielleicht noch
die Warnungen aktivieren sollen)
Stack overflow weil berechnen() sich selbst undendlich oft aufruft.
Kann sein dass das der Debugger nicht ordentlich anzeigt, ansonsten
suchst Du "backtrace".
Hilfe zur Selbsthife ist hier angesagt.
Aktiviere erstmal -wall -werror -wpedenatic , und arbeite alle Fehler
weg.
Noch etwas:
Du hast 4 geschachtelte for Schleifen + Rekursion? Mutig das du das
überblickst...
Kompiliere mit "-g" und benutze einen Debugger wie GDB. Der zeigt dir
bessere Informationen an. Im konkreten Fall hast du eine endlose
Rekursion gebaut, das stürzt daher mit einem Stack Overflow ab. Bei der
Entwicklung sollte man grundsätzlich mit "-Wall -Wextra -Werror"
kompilieren um möglichst viele potentielle Fehler zu finden, aber das
hilft im konkreten Fall nicht.
1
#define leer 0
2
#define kreis 1
3
#define kreuz 2
4
5
#define breite 3
6
#define hoehe 3
Das ist C-Stil. In C++ sollte man hier unbedingt richtige Konstanten
benutzen:
1
staticconstexprshortleer=0;
2
staticconstexprshortkreis=1;
3
staticconstexprshortkreis=2;
4
5
staticconstexprshortbreite=3;
6
staticconstexprshorthoehe=3;
Warum überhaupt überall "short"? Für das Feld wäre doch ein "enum"
passender. Für die Größe und die Laufvariablen ein std::size_t. Für
"zuege" müsstest du das erreichbare Maximum vorberechnen und einen
passenden Typ wählen.
Dir ist klar dass zwischenSpeicher ständig überschrieben wird?
Hallo,
danke schonmal für eure Tipps, der C-Style hängt bei mir immer noch
drin, naja...
Dass sich berechnen() immer wieder aufruft, hatte ich übersehen, dachte
die for-Schleifen enden ja irgendwann.
Das mit dem Überschreiben von zwischenSpeicher, darüber muss ich nochmal
nachdenken, ich sage es euch dann, wenn ich es raushabe, ob das so
richtig ist oder nicht.
Die Fehlermeldungen-Flags kennt der Compiler angeblich nicht, er sagt
mir:
g++ TicTacToe.cpp -o main.out -wall -werror -wpedenatic
g++: error: unrecognized command line option ‘-wall’
g++: error: unrecognized command line option ‘-werror’
g++: error: unrecognized command line option ‘-wpedenatic’
Bin ich sehr doof? (So langsam glaube ich nämlich schon ;-))
Danke für eure Geduld,
Ivo
PS: Die Variable zuege war dafür gedacht, zu wissen, wie viele Züge
schon gezogen wurden, also ob er jetzt einen Kreis oder ein Kreuz setzen
muss.
Ich hab mal meine Version der Datei angehängt und wie ich das ganze in
C++ schreiben würde. Bei Fragen, gerne schreiben.
Das Problem mit der Endlosrekursion besteht natürlich immer noch.
Durch meine Anpassungen ändert sich an der Funktion nichts, aber das
manuelle kopieren der Felder fällt weg. Außerdem verwende ich statt der
Magic Numbers ein Enum.
Hallo,
Supergroßes Dankeschön, so viel Mühe hätte ich mir nicht gemacht,
wirklich toll von dir!!! Werde ich mich dann mal nach dem Abendessen
noch mal dransetzen, wirklich vielen Dank!!!
Oh man, abschreiben müsste man können!
Ich habe doch tatsächlich von meinem "Programm-Storyboard" falsch
abgeschrieben, der berechnungs-Funktionsaufruf darf nur passieren, wenn
das Feld ungleich null ist, die endlose Rekursion wäre also behoben,
ich kann es jetzt gerade leider nicht ausprobieren, da ich gerade nur
von meinem Smartphone aus schreiben kann, werde es dann morgen nochmal
probieren und berichten.
Ivo
PS: Was ist denn eure bevorzugte GUI für den GDB?
Ivo Z. schrieb:> PS: Was ist denn eure bevorzugte GUI für den GDB?
Eclipse, das hat gleich noch viele andere praktische Dinge wie
automatisches Erstellen von makefiles, Git-Anbindung, Auto Completion &
Highlighting, funktioniert plattformübergreifend.
==14446==ERROR: AddressSanitizer: stack-overflow on address 0x7ffe7daf0ff8 (pc 0x55ab20b4fbdb bp 0x000000000000 sp 0x7ffe7daf1000 T0)
6
#0 0x55ab20b4fbda in berechnen() /home/daniel/projects/test/test.c:26
7
#1 0x55ab20b4fffa in berechnen() /home/daniel/projects/test/test.c:45
8
#2 0x55ab20b4fffa in berechnen() /home/daniel/projects/test/test.c:45
(geht noch ne weile so weiter)
1
#250 0x55ab20b4fffa in berechnen() /home/daniel/projects/test/test.c:45
2
#251 0x55ab20b4fffa in berechnen() /home/daniel/projects/test/test.c:45
3
4
SUMMARY: AddressSanitizer: stack-overflow /home/daniel/projects/test/test.c:26 in berechnen()
5
==14446==ABORTING
Das ist unglaublich praktisch und funktioniert noch bei vielen ähnlichen
Problemen. Ich lasse meine Makefiles häufig noch Debug versionen und
Tests mit dem address sanitizer und co. bauen. (Bei Tests nutze ich auch
noch "-fprofile-arcs" für die coverage anzeige).
Hallo,
ich habe es jetzt geschafft, als GUI habe ich Nimever benutzt, die
endlose Rekursion ist weg, jetzt muss ich noch ein paar Sachen
hinzufügen, beispielsweise für Berechnungen, die nur bis Zug x gehen
sollen.
Ivo
PS: Großes Dankeschön an alle!!!