Hallo, ich bin zurzeit daran ein C++ Buch durchzuarbeiten um einfach meine Kenntnisse mal wieder weiter zu bringen (die jetzt nicht der Burner sind), allerdings bekomme ich einen Fehler, den ich nicht reproduzieren kann. Ich kann in dem Programm immer mindestens 1 Feld belegen, das geht immer, dann aber i-wann zwischen dem 2ten und dem 14ten fängt das Programm an, mir in der Ausgabe immer und durchgehend beliebige Auszüge aus dem Programm auszugeben. Ich bin ziemlich ratlas und habe stellenweise auch den Code schon vereinfacht weil ich dacte da könnte der Fehler sein, aber er kommt einfach immer wieder. Ich hoffe nun auf ein paar Tipps und eine Erklärung was ich falsch gemacht habe. Danke schon mal im Vorraus!
Markus B. schrieb: > i-wann Gewöhn Dir das ab. Markus B. schrieb: > fängt das Programm an, mir in der Ausgabe immer und durchgehend > beliebige Auszüge aus dem Programm auszugeben. Was magst Du damit meinen? Hast Du Dein Programm mal im Debugger laufen lassen und ihm auf die Finger gesehen?
Rufus Τ. Firefly schrieb: > Markus B. schrieb: >> i-wann > > Gewöhn Dir das ab. Du meinst ich soll es in Zukunft lieber ausschreiben oder meinst du ich sollte die Aussage spezifizieren? Und auf die Idee mit dem Debugger bin ich noch gar nicht gekommen, probiere ich morgen gleich mal aus Danke trotzdem schon mal!
Das Problem habe ich nicht nachvollzogen, aber
1 | sSpielfeld[PlayFieldX][PlayFieldY]; |
sollte IMO
1 | sSpielfeld[PlayFieldY][PlayFieldX]; |
heißen, wenn du so
1 | for (int y = 0; y < PlayFieldY; y++) |
2 | { |
3 | for (int x = 0; x < PlayFieldX; x++) |
4 | { |
iterierst (Geschwindigkeisgründe aufgrund der Speicherorganisation eines 2D-Arrays). Außerdem ist es üblich in 2D-Arrays erst die Zeile (y-Koordinate) und dann die Spalte (x-Koordinate) zu indizieren. Ist in IMO einfach intuitiver.
Du machst bei der Eingabe keinerlei Fehlerprüfung. Sobald da mal was falsches eingegeben wurde, geht dein cin in den Fehlerzustand, und dann landest du mit deinen Abfrageschleifen in einer Endlosschleife. Was z.B. auch zum Fehler führt, ist die Antwort "nein" auf die Frage "Soll dort ein Gegner sein?". Da das zu lang ist, bleibt ein Teil der Buchstaben in der Eingabe stecken. Beim nächsten Abfragen einer Zahl geht der Stream dann auch auf Fehler.
@D.I. Naja das XY ist für mich einfach von der Reihenfolge her so richtig, allerdings ist es, zumindest nach meinen Stand der Dinge, nicht möglich so ein Feld über
1 | for (int x = 0; x < PlayFieldX; x++) |
2 | {
|
3 | for (int y = 0; y < PlayFieldY; y++) |
4 | {
|
darzustellen @Rolf Magnus: Danke schon mal für die Antwort, ich schau es mir morgen gleich nochmal an Allerdings mal so vorweg, ich frage doch das "Nein" über das "else" ab, oder sollte eher so was wie ein "cin.ignore()" dahin?
Grundregel. Zumindest in der Entwicklungsphase lässt man sich alles, was das Programm einliest auch gleich wieder ausgeben. Einfach nur um sicher zu gehen, dass das Programm auch tatsächlich das erwartete eingelesen hat. Vor allen Dinge Sachen wie der zur Eingabe erforderliche Return machen einem nämlich gerne einen Strich durch die Rechnung, weil sie nicht richtig behandelt werden.
Und wenn du solche Sachen hast wie: Du lässt den Benutzer Zahlen von 1 bis 5 eingeben, brauchst programmintern aber 0 bis 4 (wegen Array Index), dann korrigierst du die Zahl sofort nach der Eingabe x--; anstatt dass du überall irgendwas[x-1] schreibst. Denn irgendwo vergisst du nämlich mit Sicherheit auf das -1. Und wenn nicht heute dann morgen oder nächste Woche, wenn du am Programm weiterarbeitest. Rechne damit, dass du Fehler machst und gestalte dein Programm so, dass du nach Möglichkeit keine Leichtsinnsfehler machen kannst. Je weniger Sonderfälle (wie zb Arrayindizes die immer um 1 vermindert werden müssen) du dir merken musst, desto geringer ist die Chance, dass du diesen Sonderfall irgendwo vergisst anzuwenden.
Neben den schon gesagten habe ich auch noch ein paar Sachen... (Das soll dich jetzt nicht frustrieren; prinzipiell ist das hier eines der wenigen Einsteigerprogramme, die lesbar und übersichtlich sind.) Das:
1 | using namespace std; |
wird sehr häufig gemacht, davon würde ich aber stark abraten. namespaces sind nicht dafür erfunden worden, daß man sie gleich wieder aushebelt.
1 | struct sFieldData |
2 | {
|
3 | ...
|
4 | };
|
Wenn schon C++, warum dann nicht gleich richtig? Man könnte eine Klasse machen, die Innereien gleich mit dem Konstruktor sauber initialisieren und den Inhalt über Methoden ändern und abfragen. Muß nicht gleich am Anfang sein, aber vielleicht im nächsten Schritt...
1 | int status; |
2 | /*0 = Loch ' '
|
3 | 1 = Gras '.'
|
4 | 2 = Stein 'o'
|
5 | 3 = Berg 'O'
|
6 | 4 = Wald 'X'
|
7 | 5 = Wasser '~'*/
|
Dafür wurde enum erfunden.
1 | char cName[30]; |
Was, wenn es mal mehr als 29 Zeichen sind? Mit std::string geht es besser.
1 | const int PlayFieldX = 5; |
2 | const int PlayFieldY = 5; |
Die würde ich z.B. MaxPlayFieldX o.s.ä. nennen.
1 | char Enemy[5]; |
Was, wenn der Benutzer mehr als 4 Zeichen eingibt? Auch hier lieber wieder std::string. Das Problem mit der Pufferung der Eingabe wurde ja auch schon genannt.
1 | if (Enemy[0] == 'J' || Enemy[0] == 'j' ) |
oder:
1 | if ( std::toupper(Enemy[0]) == 'J' ) |
1 | bool enemy; |
2 | char cName[30]; |
Die bool könnte eigentlich entfallen, wenn man einen leeren Namen als Zeichen für enemy==false annimmt - eine ordentliche Initialisierung des Strings vorausgesetzt.
1 | switch (sSpielfeld[x][y].status) |
2 | {
|
3 | //0 = Loch ' '
|
4 | case 0: |
5 | {
|
6 | cout << " "; |
7 | }break; |
8 | //1 = Gras '.'
|
9 | case 1: |
10 | {
|
11 | cout << "."; |
12 | }break; |
13 | //2 = Stein 'o'
|
14 | ...
|
Mit enum und schönen sprechenden Namen wäre das auch ohne Kommentare selbsterklärend...
1 | void deleteField() |
2 | {
|
3 | ...
|
4 | sSpielfeld[x][y].status = false; |
5 | ...
|
6 | }
|
Das ist unschön, weil status eine int ist (und besser eine enum wäre :-), false aber eine bool. Daß false "zufällig" deinem leeren Feld entspricht, mag sein - ist aber nicht offensichtlich. 0 oder halt besser der passende enum-Wert wäre sinnvoller.
1 | Angehängte Dateien: |
2 | |
3 | * Aufgabe_7.zip (205.6 KB, 19 Downloads) |
Der wirklich genutzte Quelltext hätte auch gereicht; mit der exe und den ungenutzten anderen Dateien kann niemand etwas anfangen. Ansonsten sehe ich auch die evtl. zu knappen Felder und ungeprüfte Eingaben als einzigen echten Fehler. mfgkw
Vielen vielen Dank für die ganzen Tipps und Verbesserungsvorschläge!! Ich werde es gleich nochmal durcharbeiten! An das "enum" habe ich gar nicht gedacht, ist aber sicherlich die bessere Lösung, ich werde es mal versuchen umzuarbeiten, genauso muss ich eingestehen, das ich schlichtweg nicht darauf gekommen bin, "--x" zu machen anstatt das umständlliche. Danke nochmal, hat mir schon sehr viel geholfen!!
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.