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)
:
Verschoben durch User
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 | static constexpr short leer = 0; |
2 | static constexpr short kreis = 1; |
3 | static constexpr short kreis = 2; |
4 | |
5 | static constexpr short breite = 3; |
6 | static constexpr short hoehe = 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?
:
Bearbeitet durch User
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.
Ah, jetzt kennt er die Flags, hatte die ja klein geschrieben...
Beitrag #5323395 wurde von einem Moderator gelöscht.
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.
Für sowas nutze ich gerne asan:
1 | daniel@colibri:~/projects/test$ g++ -g -Og -ftest-coverage -static-libasan -fsanitize=undefined -fsanitize=address -fstack-protector-all test.c -o test |
2 | daniel@colibri:~/projects/test$ ./test |
3 | ASAN:DEADLYSIGNAL |
4 | ================================================================= |
5 | ==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).
Alternativ bietet sich auch immer valgrind für sowas an.
1 | $ valgrind ./TicTacToe |
2 | ==25347== Memcheck, a memory error detector |
3 | ==25347== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. |
4 | ==25347== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info |
5 | ==25347== Command: ./TicTacToe |
6 | ==25347== |
7 | ==25347== Stack overflow in thread #1: can't grow stack to 0xffe801000 |
8 | ==25347== |
9 | ==25347== Process terminating with default action of signal 11 (SIGSEGV) |
10 | ==25347== Access not within mapped region at address 0xFFE801FF8 |
11 | ==25347== Stack overflow in thread #1: can't grow stack to 0xffe801000 |
12 | ==25347== at 0x108A46: berechnen() (TicTacToe.cpp:45) |
13 | ==25347== If you believe this happened as a result of a stack |
14 | ==25347== overflow in your program's main thread (unlikely but |
15 | ==25347== possible), you can try to increase the size of the |
16 | ==25347== main thread stack using the --main-stacksize= flag. |
17 | ==25347== The main thread stack size used in this run was 8388608. |
18 | ==25347== Stack overflow in thread #1: can't grow stack to 0xffe801000 |
19 | ==25347== |
20 | ==25347== Process terminating with default action of signal 11 (SIGSEGV) |
21 | ==25347== Access not within mapped region at address 0xFFE801FF0 |
22 | ==25347== Stack overflow in thread #1: can't grow stack to 0xffe801000 |
23 | ==25347== at 0x4A286B0: _vgnU_freeres (in /usr/lib/valgrind/vgpreload_core-amd64-linux.so) |
24 | ==25347== If you believe this happened as a result of a stack |
25 | ==25347== overflow in your program's main thread (unlikely but |
26 | ==25347== possible), you can try to increase the size of the |
27 | ==25347== main thread stack using the --main-stacksize= flag. |
28 | ==25347== The main thread stack size used in this run was 8388608. |
29 | ==25347== |
30 | ==25347== HEAP SUMMARY: |
31 | ==25347== in use at exit: 72,704 bytes in 1 blocks |
32 | ==25347== total heap usage: 1 allocs, 0 frees, 72,704 bytes allocated |
33 | ==25347== |
34 | ==25347== LEAK SUMMARY: |
35 | ==25347== definitely lost: 0 bytes in 0 blocks |
36 | ==25347== indirectly lost: 0 bytes in 0 blocks |
37 | ==25347== possibly lost: 0 bytes in 0 blocks |
38 | ==25347== still reachable: 72,704 bytes in 1 blocks |
39 | ==25347== suppressed: 0 bytes in 0 blocks |
40 | ==25347== Rerun with --leak-check=full to see details of leaked memory |
41 | ==25347== |
42 | ==25347== For counts of detected and suppressed errors, rerun with: -v |
43 | ==25347== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) |
44 | Speicherzugriffsfehler (Speicherabzug geschrieben) |
Ivo Z. schrieb: > PS: Was ist denn eure bevorzugte GUI für den GDB? KDbg natürlich: http://www.kdbg.org/
Valgrind, gibt es klickbar für Eclipse. -Wall usw. bitte aktivieren. -O2 kann auch nicht schaden.
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!!!
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.