For-Schleife soll warten



  • Michael E. schrieb:

    while(true)
    {
    	if(foo())
    		continue;
    	if(bar())
    	{
    		++counter;
    		continue;
    	}
    	if(bar())
    		continue;
    	baz();
    	baz();
    }
    
    while(true)
    {
    	if(!foo())
    	{
    		if(bar())
    			++counter;
    		else
    		{
    			if(!bar)
    			{
    				baz();
    				baz();
    			}
    		}
    	}
    }
    

    Beides nichtssagend und hässlich



  • Haben die Funktionen Seiteneffekte?



  • 314159265358979 schrieb:

    Haben die Funktionen Seiteneffekte?

    Möglich.



  • Und jetzt zeig mir produktiven Code, wo sowas vorkommt.



  • Aus libbzip2:

    while (True) {
             /* try to finish existing run */
             while (True) {
                if (s->strm->avail_out == 0) return False;
                if (s->state_out_len == 0) break;
                *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
                BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
                s->state_out_len--;
                s->strm->next_out++;
                s->strm->avail_out--;
                s->strm->total_out_lo32++;
                if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
             }
    
             /* can a new run be started? */
             if (s->nblock_used == s->save_nblock+1) return False;
    
             /* Only caused by corrupt data stream? */
             if (s->nblock_used > s->save_nblock+1)
                return True;
    
             s->state_out_len = 1;
             s->state_out_ch = s->k0;
             BZ_GET_SMALL(k1); s->nblock_used++;
             if (s->nblock_used == s->save_nblock+1) continue;
             if (k1 != s->k0) { s->k0 = k1; continue; };
    
             s->state_out_len = 2;
             BZ_GET_SMALL(k1); s->nblock_used++;
             if (s->nblock_used == s->save_nblock+1) continue;
             if (k1 != s->k0) { s->k0 = k1; continue; };
    
             s->state_out_len = 3;
             BZ_GET_SMALL(k1); s->nblock_used++;
             if (s->nblock_used == s->save_nblock+1) continue;
             if (k1 != s->k0) { s->k0 = k1; continue; };
    
             BZ_GET_SMALL(k1); s->nblock_used++;
             s->state_out_len = ((Int32)k1) + 4;
             BZ_GET_SMALL(s->k0); s->nblock_used++;
          }
    


  • Was ist den das schreckliches? 😮 Sehr schön pseudomäsig Verschachtelungstiefen gespart: "if (k1 != s->k0) { s->k0 = k1; continue; };" Leserlichkeit 👎

    /* Only caused by corrupt data stream? */
             if (s->nblock_used > s->save_nblock+1)
                return True;
    

    Warum steht da ein Fragezeichen hinterm Kommentar? Waren die sich nicht sicher, dass das nur bei einem korrupten Stream passiert? Warum geben die dann True zurück?



  • continue ist auch deswegen übersichtlicher, weil man nicht noch schauen muss, ob nach dem if noch etwas passiert. Es wird klar gesagt: Hier macht eine Prüfung den weiteren Verlauf des Schleifenrumpfs unnötig. Das gefällt mir.

    Und was das Beispiel angeht: Wenn es sich anders schreiben lässt, ist das Beispiel eben nicht gut genug. Wer Beispiele bringt, hat die Bringschuld und darf nicht davon ausgehen, dass "der Sinn schon rüberkommt", denn dann kann man sich das Beispiel auch einfach schenken. So genau müssen wir im C++-Umfeld schon sein.



  • Gerade hab ich dieses Werk gebaut, und das hat mich an diesen Thread erinnert.

    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    
    using namespace std;
    
    int main()
    {
        srand(time(0));
        int punkte=0;
        while(punkte<100){
            int basis=rand()%10;
            int exponent=rand()%10;
            if(basis==0 && exponent==0)
                continue;
            int potenz=pow(basis,exponent);
            if(potenz>500)
                continue;
            cout<<basis<<'^'<<exponent<<'=';
            int tip;
            cin>>tip;
            if(tip==potenz){
                cout<<"richtig!\n";
                ++punkte;
            }
            else{
                cout<<"falsch!\n";
                punkte/=2;
            }
            cout<<"Punkte: "<<punkte<<'\n';
            cout<<"\n\n\n\n\n";
        }
        cout<<"Gewonnen!\n";
        return 0;
    }
    

    Die beiden continues finde ich schön.



  • müsste das nicht if(basis==0 || exponent==0) heissen? Das erste finde ich überflüssig - ich würde eher beide rand() 's anpassen auf rand()%10+1; . Das zweite ist ok, ich empfinde ein continue meist schöner als das if-pendant da ich dann (gedanklich, debuggend) zum Schleifenkopf zurückspingen kann - beim einer gleichwertigen if () { /* ... */ } muss ich erst das Ende suchen und dort schaun ob noch was passiert.



  • padreigh schrieb:

    müsste das nicht if(basis==0 || exponent==0) heissen?

    Warum? Er nimmt nur den nicht einheitlich definierten Fall 0^0 raus.

    Das erste finde ich überflüssig - ich würde eher beide rand() 's anpassen auf rand()%10+1; .

    Geht nicht, wenn lediglich 0^0 verhindert werden soll.



  • volkard schrieb:

    Gerade hab ich dieses Werk gebaut, und das hat mich an diesen Thread erinnert.

    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    
    using namespace std;
    
    int main()
    {
        srand(time(0));
        int punkte=0;
        while(punkte<100){
            int basis=rand()%10;
            int exponent=rand()%10;
            if(basis==0 && exponent==0)
                continue;
            int potenz=pow(basis,exponent);
            if(potenz>500)
                continue;
            cout<<basis<<'^'<<exponent<<'=';
            int tip;
            cin>>tip;
            if(tip==potenz){
                cout<<"richtig!\n";
                ++punkte;
            }
            else{
                cout<<"falsch!\n";
                punkte/=2;
            }
            cout<<"Punkte: "<<punkte<<'\n';
            cout<<"\n\n\n\n\n";
        }
        cout<<"Gewonnen!\n";
        return 0;
    }
    

    Die beiden continues finde ich schön.

    Auch nur, weil das ganze ein Minispiel ist, das total in sich verstrickt ist und Modularisierung sich nicht lohnt.



  • Ich hab mir sagen lassen, dass sich auch große Projekte in viele kleine Mini-"Projekte" zerlegen lassen, bei denen sich Modularisierung nicht lohnt...



  • mmmmmmmmmmmmmm schrieb:

    Auch nur, weil das ganze ein Minispiel ist, das total in sich verstrickt ist und Modularisierung sich nicht lohnt.

    Ja, absolut.
    Wäre das Programm größer, oder sollte es länger leben oder mal ausgebaut werden oder sowas, dann wäre die frage() längst ausgelagert. In ernsthaften Projekten würde ich mehr auf funktionale Zerlegung achten:

    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    
    using namespace std;
    
    bool frage();
    
    int main()
    {
        srand(time(0));
        int punkte=0;
        while(punkte<100)
        {
            if(frage())
            {
                cout<<"richtig!\n";
                ++punkte;
            }
            else
            {
                cout<<"falsch!\n";
                punkte/=2;
            }
            cout<<"Punkte: "<<punkte<<'\n';
            cout<<"\n\n\n\n\n";
        }
        return 0;
    }
    
    bool frage()
    {
    nochmal:
        int basis=rand()%10;
        int exponent=rand()%10;
        if(basis==0 && exponent==0)
            goto nochmal;
        int potenz=pow(basis,exponent);
        if(potenz>500)
            goto nochmal;
        cout<<basis<<'^'<<exponent<<'=';
        int tip;
        cin>>tip;
        return tip==potenz;
    }
    //something went wrong
    


  • In einem Anflug von Genialität konnte ich sogar noch die beiden gotos wegmachen.

    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    
    using namespace std;
    
    bool frage();
    
    int main()
    {
        srand(time(0));
        int punkte=0;
        while(punkte<100)
        {
            if(frage())
            {
                cout<<"richtig!\n";
                ++punkte;
            }
            else
            {
                cout<<"falsch!\n";
                punkte/=2;
            }
            cout<<"Punkte: "<<punkte<<'\n';
            cout<<"\n\n\n\n\n";
        }
        return 0;
    }
    
    bool frage()
    {
        for(;;)
        {
            int basis=rand()%10;
            int exponent=rand()%10;
            if(basis==0 && exponent==0)
                continue;
            int potenz=pow(basis,exponent);
            if(potenz>500)
                continue;
            cout<<basis<<'^'<<exponent<<'=';
            int tip;
            cin>>tip;
            return tip==potenz;
        }
    }
    

    Aber mir scheint, ich bin ein continue-Junkie. Ist das nicht traurig?



  • Wenn es sich lohnen würde, würde man eine Klasse für das Spielchen machen und dann z.B. sowas:

    bool isValidData()
    	{
    		if(basis==0 && exponent==0)
    			return false;
    
    		potenz=pow(basis,exponent);
    		return potenz>500;
    	}
    

    Du würdest dann wahrscheinlich so weiter machen

    if(!isValidData())
        continue;
    auswerten(frage());
    

    Ich wahrscheinlich so

    if(isValidData())
    {
        auswerten(frage());
    }
    

    😃



  • mmmmmmmmmmmmmm schrieb:

    Wenn es sich lohnen würde, würde man eine Klasse für das Spielchen machen und dann z.B. sowas:

    Nein, das würdest Du (hoffentlich!) auch nicht.

    bool isValidData()//ACHTUNG! Diese Methode tut NICHT nur prüfen,
    //sondern sie berechnet erstmalig das Attribut potenz. Sie muß daher 
    //nach createData() aber vor jeder weiteren Verwendung aufgerufen werden. 
    	{
    		if(basis==0 && exponent==0)
    			return false;
    		potenz=pow(basis,exponent);
    		return potenz>500;
    	}
    

    Das wäre zu bereinigen, indem man potenz schon in createData() und vor allen Prüfungen berechnet, aber das wollte ich ja gerade nicht.



  • Wo ist meine Antwort hin?



  • Mis2com.. schrieb:

    Wo ist meine Antwort hin?

    Von mir aus Versehen gelöscht.



  • Michael E. schrieb:

    padreigh schrieb:

    müsste das nicht if(basis==0 || exponent==0) heissen?

    Warum? Er nimmt nur den nicht einheitlich definierten Fall 0^0 raus.

    Das erste finde ich überflüssig - ich würde eher beide rand() 's anpassen auf rand()%10+1; .

    Geht nicht, wenn lediglich 0^0 verhindert werden soll.

    Schon klar, aber wie witzlos ist "Rate irgendwas hoch 0" ... daher würd ich gleich beide wechmachen 😉



  • padreigh schrieb:

    Schon klar, aber wie witzlos ist "Rate irgendwas hoch 0" ... daher würd ich gleich beide wechmachen 😉

    Wie witzlos ist x^1? Wie witzlos ist 1^x? Die Funktionalität nach eigenem Gusto veränder, gilt nicht 😉


Anmelden zum Antworten