Fehlerhafte Variablen durch eine Funktion



  • €: Alles Editiert!
    Hallo! Cpp Gemeinde!

    Ich habe mich gestern mal mit den Funktionen von rand() vertraut gemacht, und wollte nun mein erstes Programm schreiben, es geht dabei um ein Spiel und dessen Upgradechancen.

    Was soll das Programm können?
    Als erstes wird eine Meldung ausgegeben, welcher Wert (bzw. Plus im Spiel) der Gegenstand derzeit hat, und zu welchem er werden soll (im Code: Satz(0, 1) - 0 steht für das derzeitige +, die 1 ist für das Plus, welches als nächstes kommt), dazu dachte ich mir wäre es einfach eine Funktion zu schreiben, anstatt immer wieder den selben Code, so wird also eine Zahl eingelesen (Satz(0, 1)...) und diese wird danach in einem Satz ausgegeben (siehe Funktion int Satz(int a)).
    Nun - danach wählt das Programm eine Zufällige Zahl von 1-100, im Anschluss soll getestet werden ob die Zahl einen Wert hat, der unter 80 liegt, falls ja, soll die Anzahl der Versuche ausgegeben werden, und die while Schleife wird verlassen.
    Falls nicht, soll sich die Anzahl der Versuche, sowie die Anzahl der gesamt Versuche um 1 erhöhen.

    Mein Problem:
    Das Programm gibt zwar die Anzahl der Versuche aus, jedoch falsch (etwas in die 4,1 millionen bei einer 80% Chance) - es liegt irgendwie an der Funktion von int Satz(int a), denn sobald ich den Typ der Funktion auf short Satz(int a) ändere, wird die Zahl der Versuche niedriger, es wird also nicht der korrekte Wert der Variable "Versuche" ausgegeben - warum?

    Hier der Code:

    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    #include <cstddef>
    #include <conio.h>
    
    using namespace std;
    
    int Upgr, Versuche, VersucheGes;
    
    int CalcSp(int c);
    //         Chance
    int BerechneEq();
    void Berechnung();
    int Satz(int a);
    
    int main(){
        srand(time(0));
        Berechnung();
    
    }
    
    void Berechnung(){
        Upgr = 0, Versuche = 1, VersucheGes = 0;    
        cout << "SP-Upgradeversuche:" << endl;
        cout << "+ \t\tVersuche" << endl;
        cout << Satz(1) << CalcSp(80) << endl;
        cout << "\n" << "\n" << endl;
        cout << "+ \tVersuche" << endl;
        cout << "EQ-Upgradeversuche:" << endl;
        cout << "Druecke eine beliebige Taste, um ein neues Ergebnis zu bekommen!\n" << endl;
        getch();
        Berechnung();
        //cout << BerechneEq();
    }
    
    int CalcSp(int c){
        while(1){
            Upgr = 1+(rand()%100);
            if(Upgr >= c){ // Wenn Erfolg
                return Versuche;
                Versuche = 0;
                break;
            }
            else{
                Versuche = Versuche + 1;
                VersucheGes = VersucheGes + 1;
            }
        }
    
    }
    
    int Satz(int a){
        cout << a-1 << " -> " << a << "\t\t";
    }
    

    Danke schonmal für die Hilfe! 🙂


  • Mod

    Das Programm ist nicht compilierbar. Das Programm ist Spaghetticode mit goto, globalen Variablen, unerreichbarem Code und Funktionen mit komischen Nebeneffekten (z.B. Ausgabe in Funktion, deren Wert ausgegeben wird). Aus deiner Fehlerbeschreibung wird man auch nicht schlau. Deine Beschreibung dessen, was das Programm machen soll, passt ebenfalls überhaupt nicht zum Code (Satz() soll laut dir etwas lesen, aber man sieht nichts in dieser Richtung).

    Nochmal neuen Beitrag verfassen, dieses Mal ordentlich. Siehe:
    http://www.c-plusplus.net/forum/200753
    http://www.c-plusplus.net/forum/304133
    http://www.tty1.net/smart-questions_de.html



  • Ich werd versuchen es nocheinmal umzuschreiben, trotzdem danke! 🙂


  • Mod

    Schon deutlich besser.

    Der Fehler ist eine Folge der Dinge, die ich schon erwähnt habe. Hier ist die unmittelbare Ursache der Rückgabewert von Satz(). Das hat nämlich einen Rückgabewert, gibt aber nichts zurück. Daher kommt da irgendein uninitialisierter Wert bei raus. Und der wird dann ausgegeben.

    Benutz keine globale Variablen! Wenn du den obigen Fehler berichtigt hast, wirst du feststellen, dass du noch mehr Fehler drin hast, die du ohne globale Variablen nicht hattest. Viel Spaß, diesen Fehler zu finden. Das ist bei globalen Variablen nämlich besonders schwer.

    Keine Rekursion, ohne sie zu verstehen!

    Möglichst keine Funktionen mit Nebeneffekten. Das ist hier die Ursache des Fehlers. Du willst etwas ausgeben, das etwas ausgibt. Das ist Unsinn!

    Das sind keine Kleinigkeiten. Die drei Punkte (und das goto, das du vorher hattest) sind alle in den Top 10 der Programmiersünden. Sie provozieren Fehler, machen den Code unlesbar und schwer zu debuggen. Dein Programm ist ein hervorragendes Beispiel dafür. Wenn du sauber programmierst, funktionieren deine Programme praktisch von alleine fehlerfrei. Bei unsauberem Code passiert das Gegenteil.



  • Oh mein Gott - danke ich habs!^^

    Den Typ von Satz habe ich mehrmals versucht in void zu ändern, dies ging jedoch nicht, da er in dem cout stand.

    cout << Satz(1) << ...
    

    Wie ich mitbekam kann eine void Funktion nicht in einer Ausgabe stehen - ein wenig zu spät, aber trotzdem. 😛

    Das mit den globalen Variablen habe ich auch behoben, ich dachte ich brauche diese in CalcSp() und in Berechnung(), brauche sie jedoch nur bei der Calc(), danke auch noch für das hinweisen des goto's bzw. der Label, werde ein Programm in Zukunft dann doch besser in einzelne Funktionen unterteilen.^^

    Vielen Dank nochmal für die Hinweise! 🙂



  • Hallo Shortyoo,

    warum nimmst du für die Sache mit den Zufallszahlen nicht die schicken Zufallsgeneratoren von C++11. 🙂

    Gruß,
    -- Klaus.


  • Mod

    Habe leider gerade keine Zeit, das Programm sauber (und anfängerfreundlich) zu schreiben, um mal zu zeigen, wie das aussehen könnte 😞 . Vielleicht findet sich jemand anderes, der mal zeigt, wie man die Funktionen sauber aufteilt. Das wichtigste wäre wohl, die Zeile

    cout << Satz(1) << CalcSp(80) << endl;
    

    in eine Funktion auszulagern. Diese Zeile wiederholt sich in deinem Originalcode vielfach. Außerdem wird man so das Ausgabeproblem mit der Satz-Funktion los. Das könnte dann ungefähr so aussehen:

    void calculation_output(int to, int value)
    {
       cout << from-1 << " -> " << from << "\t\t" << CalcSp(value) << '\n';
    }
    


  • Ich habe mal eine Klasse entworfen, um die Sache mit den Zufallszahlen in den Hintergrund zu drücken.

    Die Klasse uprade lässt sich mit dem Schwellenwert initialisieren (in diesem Fall 80% = 0.8) und gibt beim Aufruf von check ein true oder false zurück, also ob ein Upgradeversuche zu 80% erfolgreich war oder nicht ... zumindest verstehe ich so einen Teil des Programms.

    #include <iostream>
    #include <random>
    #include <vector>
    
    class upgrade
    {
    	public:
    		upgrade(double const threshold):
    			_engine( 815 ), _rng(0.0,1.0), _threshold( threshold)  {}
    		bool check();
    
    	private:
    		std::mt19937 _engine;
    		std::uniform_real_distribution<double> _rng;
    		double const _threshold;
    };
    
    bool upgrade::check()
    {
    	if( _rng( _engine ) < _threshold )
    		return true;
    
    	return false;
    }
    
    int main()
    {
    	upgrade upgr( 0.8 );
    
    	for(unsigned int i = 0; i < 10; ++i)
    	{
    		if( upgr.check() )
    			std::cout << "YES!" << std::endl;
    		else
    			std::cout << "NO!" << std::endl;
    	}
    
    	return 0;
    }
    

    Hope that helps.
    -- Klaus.



  • Vielen Dank für die Antwort, Klaus82.
    Leider verstehe ich davon nicht viel, bin noch ein Anfänger in C++.^^

    SeppJ, versuche gerade genau das zu machen, die Value entnehme ich dann einem Vector 🙂



  • Shortyoo schrieb:

    Vielen Dank für die Antwort, Klaus82.
    Leider verstehe ich davon nicht viel, bin noch ein Anfänger in C++.^^

    Nicht schlimm, dann lernst du es eben. 😉

    Wo du die Details zu den Zufallsgeneratoren nachlesen kannst, habe ich dir oben verlinkt. 🙂

    Viele Grüße,
    -- Klaus.


Log in to reply