Hilfe bei Programm für Anfänger



  • Hallo zusammen,
    seit letzter Woche habe ich aus rein aus Interesse mal mit dem Programmieren in C++ angefangen. Das ganze mache ich über Tutorialvideos auf Youtube,
    Ich habe absolut keine Vorkenntnisse (außer ein bisschen VBA aus meiner Studienzeit vor über 10 Jahren) und wäre froh, wenn ihr mir hier bei zwei kleinen Problemen helfen könntet.
    Ich bin gerade dabei mein erstes kleines Programm zu schreiben. Ist ein kleines Konsolenrechenspiel für meinen Sohn im Grundschulalter 🙂

    1. Über ein Hauptmenü kann ich über char Eingabe die jeweilige Kategorie (Addition, Subtraktion, Muliplikation, Division) auswählen. Hier hat mich aber gestört, dass man nach erfolgreicher Eingabe eines Ergebnisses direkt wieder ins Hauptmenü gesprungen ist. Habe das dann mit while(true) gelöst. Nun bekomme ich es aber nicht hin in das Programm eine Abfrage einzubauen, um wieder ins Hauptmenü zurückzukommen. Hier mal ein Beispiel des Codes:
    bool validateuserguss(int guess, int result)
    {
    	if (guess == result)
    	{
    		cout << "Richtig! Das Ergebnis lautet: " << result << "\n\n\n";
    		return true;
    	}
    	else
    	{
    		cout << "Falsch! " << guess << " ist nicht das richtige Ergebnis! Bitte versuche es noch einmal!\n\n\n";
    		return false;
    
    	}
    }
    
    void Addieren()
    {
    	int guess = 0;
    	int randnum[2];
    	while (true)
    	{
    		
    		randnum[0] = randomnumber();
    		randnum[1] = randomnumber();
    		int result = randnum[0] + randnum[1];
    		do
    		{
    			cout << randnum[0] << "+" << randnum[1] << "=";
    			cin >> guess;
    		}
    
    		while (!validateuserguss(guess, result));
    	}
    }
    
    1. Ich hatte die maximale Zahl, mit der man rechnen kann, über eine fixe Konstante im Code eingegeben.
      Nun würde ich gerne eine Abfrage in der jeweiligen Kategorie für die maximal Zahl einfügen. Das sieht im Moment so aus:
    const int Maxnumber()
    {
    	int maxnum = 0;
    	cout << "Bis zu welcher Zahl willst du rechnen? ";
    	cin >> maxnum;
    	system("cls");
    	return maxnum;
    }
    
    
    int randomnumber()
    {
    	int randnum[2] = { 0, 0 };
    	for (int i = 0; i < 2; i++)
    	{
    		randnum[i] = rand() % Maxnumber() + 1;
    		//cout << randnum[i] <<endl;
    		return randnum[i];
    	}
    }
    void Addieren()
    {
    	int guess = 0;
    	int randnum[2];
    	while (true)
    	{
    		
    		randnum[0] = randomnumber();
    		randnum[1] = randomnumber();
    		int result = randnum[0] + randnum[1];
    		do
    		{
    			cout << randnum[0] << "+" << randnum[1] << "=";
    			cin >> guess;
    		}
    
    		while (!validateuserguss(guess, result));
    	}
    }
    

    Leider wird diese Zahl aber immer zweimal abgefragt. Das liegt wohl daran, dass ich die beiden Felder meines Arrays über die zweimal die gleiche Funktion aufrufe.

    Leider stoße ich hier schon ein meine Grenzen. Wäre echt cool wenn hier jemand eine Lösung oder zumindest einen Ansatz hat, damit ich hier weiterkomme und mein Wissen etwas erweitern kann.

    Vielen Dank schon mal im Voraus!

    Gruß
    Ceejay



    1. An irgendeiner Stelle muss der Benutzer sich für eine Option entscheiden, die ihm angeboten wird. Entweder muss er im Hauptmenü eine Auswahl treffen, oder er muss nach einer Operation entscheiden, ob er in's Hauptmenü zurück oder die gleiche Operation noch mal ausführen möchte. Um das nicht in jeder Operation prüfen zu müssen würde ich immer in's Hauptmenü zurückspringen.

    2. Vermutlich hast du den Zufallszahlengenerator nicht initialisiert (=>srand()), ich hab' ehrlich gesagt keine Ahnung, wie er sich dann verhält. Statt rand() solltest du besser die RNG benutzen, die mit C++11 ergänzt worden sind:

    #include <cstdlib>
    #include <random>
    
    int main()
    {
       static unsigned int const MinRN = 1; 
       static unsigned int const MaxRN = 6;
    
       // Generator für Zufallszahlen, Bereich spielt hier keine Rolle, wird über die Verteilungsfunktion bestimmt
       std::mt19937 generator( std::time( nullptr ) );
    
       // Verteilungsfunktion für Zufallszahlen, bestimmt eine Zufallszahl im Bereich [MinRN ;MaxRn]
       std::uniform_int_distribution<unsigned int> const distribution( MinRN, MaxRN );
       
       unsigned int const random_number = distribution( generator );
    }
    

    PS:
    Statt "roher" Arrays besser std::array benutzen, das bringen einige Komfortfunktionen ohne Overhead mit.

    #include <array>
    
    int main()
    {
       unsigned int arr_old[2] = { 0,0 };
       std::array<unsigned int,2> arr_new = { 0, 0 };
    }
    


  • Hallo und willkommen,

    zu 1: Dies ist in einem Konsolenprogramm etwas schwieriger, da man nicht z.B. einfach ESC abfragen kann.
    Entweder du fragst jedesmal nach, ob noch weiter abgefragt werden soll (z.B. j/ n) oder aber du nutzt die Besonderheit des Streams cin, daß ungültige Eingaben (z.B. Buchstaben oder Sonderzeichen) bei der Zahleneingabe zu einem Fehlerzustand führen:

    while (cin)
    {
       // ...
       do
    
       while(cin && !validateuserguss(guess, result));
    }
    
    // Ungültige Zeichen aus dem Stream überlesen und Fehlerzustand des Streams löschen
    cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n')); // #include <limits> wird noch benötigt
    cin.clear();
    

    (am besten die unteren Zeilen in eine eigene Funktion packen, damit du sie mehrmals - ohne C&P - nutzen kannst).

    Alternativ könntest du auch einfach eine Zählschleife (für z.B. max 10 Rechnungen) verwenden.

    zu 2:
    Du rufst ja innerhalb von randomnumber() jedesmal Maxnumber() auf, so daß jedesmal die Abfrage kommt - diese solltest du nur einmalig (vor der Rechenschleife) erfragen und in einer Variablen merken und diese dann in randomnumber() als Parameter benutzen:

    int randomnumber(int maxnumber)
    {
        return rand() % maxnumber + 1;
    }
    

    Du gibst außerdem bisher in randomnumber() innerhalb der Schleife sofort mit return randnum[i]; diesen Wert (mit Index 0) zurück (ohne die Schleife weiterabzuarbeiten) - diese Schleife ist also hier unnötig!

    PS: Außerdem, wie @DocShoe schon geschrieben, verwendest du bisher älteres C++ (das sog. C++98) - seit C++11 gibt es modernere Funktionalitäten, s.a. Weiterentwicklung der Programmiersprache C++ nach 2005.



  • Danke für die schnellen Antworten @DocShoe und @Th69!
    Das hört sich ja alles sehr vielversprechend an. C++11 muss ich mir mal anschauen. Die Tutorialreihe die ich gerade schaue, ist in C++98 gehalten. Deshalb hab ich mich daran orientiert. Wie gesagt, bin erst seit knapp 4 Tagen dabei und bin froh, dass ich überhaupt schon einmal was zum Laufen bekommen habe 😃



  • @Ceejay Ich würde dir raten, die Tutorial Reihe abzubrechen. Heute programmiert man an vielen Stellen doch ganz anders als man es mit C++98 gemacht hat, da muss man nicht die historische Entwicklung mitmachen. Leider kann ich spontan kein gutes "modernes" C++ Tutorial empfehlen, aber in den letzten 20 Jahren ist viel passiert.



  • @Schlangenmensch Ich werde es rein fürs Grundverständniss einmal durchgehen. Kann ja nichts schaden. Die Videos sind super verständlich erklärt und gerade für die generellen Zusammenhänge mal zu durchblicken habe ich bis jetzt nichts besseres gefunden. Ich bin ja auch erst bei Video 11 von 72. Vielleicht kommt da ja auch noch was.



  • @Ceejay

    Das Problem wird sein, dass sich Paradigmen komplett verändert haben, ganz besonders bei der Verwaltung von Resourcen. Das C++98 Tutorial wird dir erklären, wie man Speicher mit new allokiert und mit delete wieder freigibt, dass man Speicher nicht mehrfach freigeben darf und aber auch sicherstellen muss, dass der Speicher wieder freigegeben wird. C++11 erklärt dir dann, dass man nicht mehr explizit macht, sondern per RAII in smart pointer verpackt. Der Unterschied ist nicht nur ein bisschen anders, sondern die Methodik hat sich geändert, und diese Methodik wird mit C++98 nicht erklärt. Durch das C++98 Tutorial erfährst du nicht, wie man heute C++ programmiert.



  • @DocShoe Danke für die Info. Dann macht es wohl doch wenig Sinn da weiterzumachen. Du kennst nicht zufällig gut verständliches Tutorial für Anfänger?
    Edit: Hab mich jetzt mal durch ein paar spätere Videos geklickt. Hier wird wohl doch mit C++11 gearbeitet, soweit ich das erkennen kann. In den ersten Videos geht es auch explizit nur um Grundlagen wie Schleifen, etc. Deshalb ist das wohl noch sehr einfach gehalten. Kann ich also doch weitermachen 😃



  • @Ceejay Wie heißt denn das Tutorial. Dann könnten wir aus interesse da auch mal rein gucken und das eventuell besser einschätzen. Vielleicht kennt sogar jemand den, der das Tutorial hält.



  • @Schlangenmensch ist auf YouTube von einem Benutzer namens Pilzschaf.
    Hier mal der Klink:
    https://youtube.com/playlist?list=PLStQc0GqppuVs05kWvLBoHcWCULX3ueIM&si=fV5cEljQT9T3IlLx



  • @Ceejay

    Ich finde die Videoserie von Bytes'n'Objects ganz gut.
    Hab gerade auch mal in die Pilzschaf Videoserie reingeguckt, die scheint auch ok zu sein. Anfangs holt er immer etwas aus und demonstriert an altem C-Code, was C++ besser macht.



  • @Ceejay Hm, von einem ersten reinschauen, bin ich didaktisch nicht überzeugt. Zeiger, C-Strings, Plain Arrays,Old School for-Loops und new + delete, vor std::string, std::vector, std::array und range based for loops, würde ich so nicht unterrichten.
    Ein weitere Punkt, den ich nicht so schön finde ist, dass überall Ein und Ausgaben gemacht werden. Ich weiß, dass das den Anfang einfacher macht, aber aus professioneller Sicht, würde ich Ein/Ausgabe direkt zu Anfang von dem Rest trennen, das macht es einfacher irgendwann mal mit Unit Tests anzufangen (was ich deutlich mehr zu Anfang unterrichten würde).


Anmelden zum Antworten