Hilfe bei C++ Code

ttatoni

Neues Mitglied
Hallo, ich habe ein kleines Zahlenraten Spiel in C++ programmiert. Jetzt habe ich hinzugefügt, dass der Benutzer auswählen kann wie groß das Spektrum der gesuchten Zahl sein soll. Es kommt aber immer zu dem Fehler:Ausnahmefehler bei 0x008031A8 in spiel++.exe: 0xC0000094: Integer division by zero.
Hier der Code
C++:
#include <iostream>
#include <stdio.h>
#include <time.h>

using namespace std;

int MaxNumber;
int credits = 0;

char Menu() {
  char input = ' ';
  cout << "\n MENU\n\nSpielen\nVerlassen)\n\n";
  cout << "Gib (P) ein um zu spielen und (Q) um das Spiel zu Verlassen\n";
  cout << "Input: ";
  cin >> input;
  system("cls");
  return input;
}
int GetUserGuess() {
  int guess = 0;
  cout << "Wie lautet dein Tipp?\n";
  cin >> guess;
  return guess;
}

bool ValidateUserGuess(int guess, int rightResult) {
  if (guess == rightResult) {
    cout << "Super! Dein Tipp war richtig! Die gesuchte Zahl ist " << rightResult << '!' << endl;
    credits += 10;
    cout << "Credits: " << credits << "\n\n";

    return true;
  } else if (guess < rightResult) {
    cout << "Die gesuchte Zahl ist groesser als dein Tipp.\n";
    return false;
  } else if (guess > rightResult) {
    cout << "Die gesuchte Zahl ist kleiner als dein Tipp.\n";
    return false;
  } else {
    cout << "Eingabe nicht gueltig: " << guess << "\n";
    return false;
  }
}

void RunGame() {
  int rightResult = rand() % MaxNumber;
  int randomNumber = MaxNumber;
  int guess = 0;
  int tries = 0;

  cout << "Gib hier ein wie gross das Spektrum der gesuchten Zahl sein soll.\nVon 1 bis:  \n";
  cin >> MaxNumber;

  cout << "Die gesuchte Zahl ist zwischen 1 und " << MaxNumber + 1 << "(beide mit eingeschlossen)\n";
  do {
    guess = GetUserGuess();
    tries++;
  } while (!ValidateUserGuess(guess, randomNumber));
  cout << "Du hast " << tries << " Versuche gebraucht.\n";
}

void RunMenu() {
  while (true) {
    char input = Menu();
    if (input == 'P' || input == 'p') {
      RunGame();
    } else if (input == 'Q' || input == 'q') {
      break;
    } else {
      cout << "Input " << input << " nicht bekannt. Bitte versuche es erneut \n";
    }
  }
}

int main() {
  srand(time(NULL));
  RunMenu();
  cout << credits;

  system("pause");
  return 0;
}
 
Nur kurz überflogen und mir ist aufgefallen, dass du MaxNumber nicht verwendest. Wird uninitialisiert in Zeile 46 benutzt und dann später erst in Zeile 52 belegt.

Kannst das ja erst einmal beheben und dann weiterschauen.
 
Da ich extra für solche Fälle eine Resource geschrieben hab fangen wir wohl mal mit der an(da stehen zum Beispiel ein paar Warnings die du anstellen und beheben willst)

Generell machst du in deinem Code einiges, das für C++ echt nicht empfehlenswert ist:
1.) Du verwendest C-Header. Wenn überhaupt dann solltest du cstdio bzw. ctime verwenden, sonst können Namespaces durcheinander fliegen
2.) Du solltest i.A. überhaupt keine C-Funktionen benutzen. C++ ist eine eigene Sprache, und hat für eigentlich alles weit überlegene Funktionalitäten im Repertoire
3.) Für Zufallszahlen hat C++ extra den Header random(der ggü. srand() deutlich zu bevorzugen ist, aus verschiedenen Gründen).
Wenn du nur zufällige Integer benutzen willst geht das so:
Random Integer:
#include <random>

int main(int argc, char **argv) {
  // es gibt verschiedene Verfahren für Pseudozufallszahlen im C++-Standard, die default_engine ist i.A. okay
  std::default_random_engine generator;
  // wir wollen eine Verteilung, in der alle integer mit gleicher Wahrscheinlichkeit vorkommen, es sollen integer erzeugt werden(das ist das Argument im <>-Operator), und nicht etwa short oder longs,
  // und der Konstruktor (0,9) gibt an, dass die Zufallszahl größer oder gleich 0 und kleiner oder gleich 9 sein soll
  std::uniform_int_distribution<int> distribution(0, 9);
  /*
        Willst du stattdessen doubles produzieren muss diese Zeile lauten:
        std::uniform_real_distribution<double> distribution(0.0, 9.0);
  
    */
  // verwende den oben angelegten Generator für die Verteilung und produziere eine einzelne Zufallszahl
  int number = distribution(generator);
  return EXIT_SUCCESS;
}

4.) du solltest extrem selten "NULL" benutzen in C++(das ist nämlich nicht notwendigerweise das gleiche wie in C), sondern lieber std::nullptr
5.) Du nutzt deklarierte Variablen(wie rightResult) nicht.
6.) system("cls") ist ein windows-ism, der nur da läuft und wie beinahe jede Nutzung von system() eine gänzlich furchtbare Idee ist, die du lassen solltest(auch system("pause") ist furchtbar).
Pausing a program:
#include <chrono>
#include <iostream>
#include <thread>

int main(int argc, char **argv) {
  /*
        Wenn du ein Programm pausieren willst gibt es drei Wege, die sich empfehlen:
            1.) Warten auf einen Tastendruck
            2.) Warten auf das Verstreichen von einer bestimmten Zeit
            3.) Warten auf einen bestimmten Zeitpunkt
    */

  // warten auf einen Tastendruck, braucht <iostream>
  std::cin.get();

  // warten bis eine bestimmte Zeit vorbei ist, nutzt Funktionen aus <chrono>(es geht mit Zeitliteralen schöner, aber die sind komplex) und braucht <thread>
  std::this_thread::sleep_for(std::chrono::seconds(1))

      // warten bis zu einem bestimmten Zeitpunkt, hier 1s nach Aufruf von system_clock::now()
      std::this_thread::sleep_until(std::chrono::system_clock::now() + std::chrono::seconds(1));

  return EXIT_SUCCESS;
}

für ein cls ohne Betriebssystem-Shellbefehle reicht es, ein paar Newlines(und ein std::endl oder std::flush!, ich weiß grad nicht wie viele) auszugeben, damit spulst du quasi bis auf die nächste "Seite" vor und siehst von den vorherigen Eingaben nichts mehr.

7.) wenn du ein Zeilenende ausgeben willst empfiehlt sich, zumindest für Anfänger, std::endl zu verwenden, das leert auch gleich den Puffer
8.) time ist auch so ein Ding, das du in C++ nicht benutzen solltest( es gibt vernünftige objektorientierte Interfaces dafür) und zum Initialisieren von srand() taugt das auch in C nicht wirklich gut(hat tiefere Gründe, ist für Anfänger nicht schlimm, aber man sollte sich sowas gar nicht erst angewöhnen).
9.) Globale Variablen sind keine gute Idee(und man sollte sie meistens initialisieren).
10.) "using namespace std;" wird in vielen Lehrbüchern etc. gemacht um Zeichen zu sparen, gilt aber im Allgemeinen als kein guter Stil.
Wenn du Objekte, Namespaces etc. öfter brauchst kannst du dir einzelne mit einer using-direktive in den derzeitigen Namespace holen. Damit du nicht immer std::cout tippen musst zum Beispiel mit "using std::cout;"

(Diese Aufzählung ist nicht vollständig, sind nur ein paar Sachen die ich auf die Schnelle gesehen habe, ein guter Linter(wie clang-tidy) und entsprechende Compiler-Warnings sollten da helfen, und gerade in modernem C++ gäbe es da einiges zu verbessern)

Nun aber dazu was das wichtigste Problem ist:
Du initialisierst MaxNumber nicht(was dazu führt, dass die Variable mit 0 initialisiert wird, was aber nicht so sein muss, i.A. ist das Undefined Behaviour), dann teilst du in Zeile 46 durch diese Zahl(Modulo führt auch eine Division durch), und da diese Operation undefiniert ist wirft das Programm eine Exception und wird vom Kernel beendet. Du solltest MaxNumber also initialisieren, und zwar mit etwas anderem als 0.

MfG,

Lowl3v3l

(Wenn du das mit einem Buch lernst und das Buch in dieser Weise Code schreibt, es gibt einige wirklich furchtbare C++-Bücher, dann organisier dir ein anderes. Wenn du einen Lehrer hast der sowas macht... Kauf dir ein vernünftiges Buch und hör ihm nicht mehr zu)

P.S. Ja ich weiß, das wirkt alles nitpicky, aber C++ ist ziemlich komplex UND weit einfacher zu benutzen(wenn man es richtig macht) als es oft unterrichtet wird. Daher ist es für Neulinge gut, darauf zu achten es gleich richtig und auf einem "C++-Weg" zu lernen, das ist einfacher und man muss später nicht versuchen, das was man falsch gelernt hat noch einmal in richtig neu zu lernen.
 
Zuletzt bearbeitet:
Zurück
Oben Unten