Mein Informatiklehrer sagt, dass



  • Hallo,
    bei mir wird gar nicht mehr C++ unterrichtet. Ich lerne Delphi in der Schule aber da meine "Hauptsprache" nun mal
    C++ ist unterhalte ich mich mit meinem Lehrer schon mal darüber! Als ich ihm ein kleines Programm gezeigt habe, meinte er halt, dass
    break und continue schlechter Stil wäre und dass man sie meiden solle...

    Ich war damals noch nicht so erfahren und habe einfach gesagt "Ich weiß!" doch darüber schäme ich mich, denn
    ich sagte es nur aus Unwissenheit bzw und meinen Lehrer zufrieden zu stellen!

    Heute würde mir das nicht mehr passieren, da ich der Meinung bin, dass break und continue durchaus angebracht sind!

    Vielen Dank
    lg, freakC++



  • Es kommt halt immer auf die Situation an. Auch ein goto hat seine Berechtigung. Wenn man allerdings goto , oder auch break und continue ständig braucht lediglich, weil man zu faul ist sich, wie schon vorhin gezeigt, gedanken über Bedingungen o.ä. zu machen, dann ist das bestimmt schlechter Stil.
    Wen man allerdings einen Grund hat und Alternativen zu umständlich/unleserlich wären, dann kann man alles brauchen, was die Sprache hergibt.



  • Ich stelle fest, dass Gegner von break und continue in diesem Thread keine Argumente bringen

    Vollkommen richtig, ich dachte die Argumente wären allen bekannt 🙄

    Wie auch immer break, continue und return sind ebenso Sprunganweisungen wie goto, es gilt die selbe Argumentation...
    Man kann also nur diskutieren ob die Probleme, die durch Sprunganweisungen verursacht werden nicht geringer sind als die, die durch die umstrukturierung verursacht werden, deswegen gibt es nur Beispiele, wie man es besser machen kann.

    deswegen =>

    Als ich ihm ein kleines Programm gezeigt habe, meinte er halt, dass
    break und continue schlechter Stil wäre und dass man sie meiden solle...

    So formuliert imho richtig. Meiden heißt aber auch nicht, gar nicht verwenden. Wer weiß was du ihm vorgelegt hast 😃



  • JustAnotherNoob schrieb:

    Wie auch immer break, continue und return sind ebenso Sprunganweisungen wie goto, es gilt die selbe Argumentation...

    Nicht zu vergessen for, while, if/else, case



  • Gerade auf meiner Platte gefunden:
    C:\angstkopie\drvd\src\raetsel\main.cpp

    #include <iostream>
    
    using namespace std;
    
    bool istPrim(int kandidat)
    {
       bool prim=true;
    
       for(int i=2;i<=kandidat-1;i=i+1)
       {
          if(kandidat%i == 0)
          {
             prim=false;
             break;
          }
       }
    
       return prim;
    }
    
    int main()
    {
        for(int a=0;a<=9;++a)
        {
            for(int b=0;b<=9;++b)
            {
                for(int c=0;c<=9;++c)
                {
                    for(int d=0;d<=9;++d)
                    {
                        if(a+b+c+d!=26)
                            continue;
                        if((a*b*c*d)%2!=0)
                            continue;
                        if(c!=d)
                            continue;
                        if(!istPrim(100*b+10*c+d))
                            continue;
                        cout<<a<<b<<c<<d<<'\n';
                    }
                }
            }
        }
        return 0;
    }
    

    edit: das rätsel dazu war anscheinend
    http://www.bu-on.de/raetsel/raetsel2.htm

    Die Ausgabe des Programms ist

    4499
    4877
    6677
    

    Die Bedingung 3) wollte ich nicht ausprogrammieren.

    Übrigens ist die istPrim schrecklich mit der komischen Variablen da. Warum nicht gleich rausreturnen, wenn sie nicht prim ist?



  • JustAnotherNoob schrieb:

    ich dachte die Argumente wären allen bekannt 🙄

    Welche sind denn das? Bring das doch mal auf'n Punkt!

    Gesprungen wird immer irgendwo irgendwie, zB auch beim Funktionsaufruf. :p

    Das wichtige dabei ist doch die Lesbarkeit. Wenn ich ein "goto" sehe, dann muss ich erstmal die Sprungmarke suchen, um zu wissen, wo's weiter geht. Das ist schlechte daran. Es hat auch zur Folge, dass es schwieriger wird, sich von der Korrektheit des Programms zu überzeugen.

    Wie sieht es mit break, continue und return aus? Wenn Deine Schleifen mehrere Seiten lang sind, hast Du sowieso etwas falsch gemacht. Bei break und continue ist sofort klar, wo's weitergeht. Mit return springe ich aus der Funktion heraus. Willst Du mir jetzt erzählen dass die Nutzung von break, continue und return die Lesbarkeit verschlechtert? Wie würdest Du denn das Beispiel von tntnet mit der "and-a-half"-Schleife umsetzen?

    So vielleicht? (Mit Zusatzvariable)

    bool wiederholen = true;
      do {
        AAA
        wiederholen = ....; // Test
        if (wiederholen) {
          BBB
        }
      } while (wiederholen);
    

    Oder so vielleicht? (Mit Code Duplication)

    AAA
      while (...) {
        BBB
        AAA
      }
    

    ?

    Ist doch alles Käse!

    Gruß,
    SP



  • #include <iostream> 
    
    using namespace std; 
    
    bool istPrim(int kandidat) 
    { 
       bool prim=true; 
    
       for(int i=2;i<=kandidat-1;i=i+1) 
       { 
          if(kandidat%i == 0) 
          { 
             prim=false; 
             return prim; 
          } 
       } 
       return prim; 
    } 
    
    int main() 
    { 
        for(int a=0;a<=9;++a) 
        { 
            for(int b=0;b<=9;++b) 
            { 
                for(int c=0;c<=9;++c) 
                { 
                    for(int d=0;d<=9;++d) 
                    { 
                        if(a+b+c+d!=26)
                            ;
                        else if((a*b*c*d)%2!=0) 
                            ; 
                        else if(c!=d) 
                            ; 
                        else if(!istPrim(100*b+10*c+d)) 
                            ; 
                        else
                            cout<<a<<b<<c<<d<<'\n'; 
                    } 
                } 
            } 
        } 
        return 0; 
    }
    


  • adfkhl schrieb:

    #include <iostream> 
    
    using namespace std; 
    
    bool istPrim(int kandidat) 
    { 
       bool prim=true; 
    
       for(int i=2;i<=kandidat-1;i=i+1) 
       { 
          if(kandidat%i == 0) 
          { 
             prim=false; 
             return prim; 
          } 
       } 
       return prim; 
    } 
    
    int main() 
    { 
        for(int a=0;a<=9;++a) 
        { 
            for(int b=0;b<=9;++b) 
            { 
                for(int c=0;c<=9;++c) 
                { 
                    for(int d=0;d<=9;++d) 
                    { 
                        if(a+b+c+d!=26)
                            ;
                        else if((a*b*c*d)%2!=0) 
                            ; 
                        else if(c!=d) 
                            ; 
                        else if(!istPrim(100*b+10*c+d)) 
                            ; 
                        else
                            cout<<a<<b<<c<<d<<'\n'; 
                    } 
                } 
            } 
        } 
        return 0; 
    }
    

    das continue dürckt mehr sofort aus, nämlich "dieser fall ist erledigt, sofort den nächsten ausprobieren!".


  • Administrator

    Sebastian Pizer schrieb:

    Bei break und continue ist sofort klar, wo's weitergeht.

    Wo es weitergeht ist klar. Herausfinden wie der Algorithmus aussieht, kann* allerdings erschwert werden. Durch ein break kann man zum Beispiel Codeduplizierung entfernen, wie es tntnet vorgeführt hat. Dadurch hast du aber eben irgendso eine halbe Schleife. Um die Schleife zu verstehen, muss du sie in deinem Kopf wieder entpacken und hast dann im Kopf die Codeduplizierung. Daher ist auch Codeduplizierung nicht einfach nur grundlegend schlecht und wenn man das dann noch in Funktionen aufteilt oder auf Variablen verteilt (z.B. die message Variable in meinem vorherigen Code), dann sehe ich eher Vorteile in der Lesbarkeit.

    *Ich möchte, dass man dieses kann nicht vergisst: kann werden != wird 😉

    Grüssli



  • Gesprungen wird immer irgendwo irgendwie, zB auch beim Funktionsaufruf.

    Der Unterschied beim Funktionsaufruf ist, dass dieser bewusst implementierungsdetails versteckt.
    Im Gegensatz zu Sprunganweisungen wird der Lesefluss daher nicht unterbrochen.

    und break hat insofern den selben Sucheffekt wie goto, weil du nun nicht mehr beim lesen des Schleifenkopfes sagen kannst, wann die Schleife verlassen wird.



  • Hi,

    ich habe nur mal kurz geschaut, aber tut's nicht auch:

    ...
       if((a+b+c+d!=26)   ||
          (a*b*c*d)%2!=0) ||
          (c!=d) ||
          !istPrim(100*b+10*c+d))
             cout<<a<<b<<c<<d<<'\n';
    

    ?
    (OK ||-operator sollte nicht überladen sein)

    Gruß,

    Simon2.



  • JustAnotherNoob schrieb:

    und break hat insofern den selben Sucheffekt wie goto, weil du nun nicht mehr beim lesen des Schleifenkopfes sagen kannst, wann die Schleife verlassen wird.

    Ja. Aber nicht ganz so schlimm wie goto, weil man wenigstens weiß, daß ans Ende der Schleife gesprungen wird.
    return ist da noch ein wenig besser, weil man weiß, daß die ganze Funktion beendet wird.



  • JustAnotherNoob schrieb:

    und break hat insofern den selben Sucheffekt wie goto, weil du nun nicht mehr beim lesen des Schleifenkopfes sagen kannst, wann die Schleife verlassen wird.

    Da gibt's sicherlich genug Gegenbeispiele, was die Lesbarkeit von Schleifen ohne break bzgl Abbruchbedingung angeht. ZB das hier:

    bool wiederholen = true;
      do {
        AAA
        wiederholen = ...; // Test
        if (wiederholen) {
          BBB
        }
      } while (wiederholen);
    

    Hier ist es noch viel schlechter mit der Lesbarkeit. Alternativ bleibt "code duplication"

    AAA
      while (...) {
        BBB
        AAA
      }
    

    welches ich immer noch zugunsten von

    for (;;) {
        AAA
        if (!...) break;
        BBB
      }
    

    ablehnen würde.

    Gruß,
    SP


  • Mod

    Simon2 schrieb:

    Hi,

    ich habe nur mal kurz geschaut, aber tut's nicht auch:

    ...
       if((a+b+c+d!=26)   ||
          (a*b*c*d)%2!=0) ||
          (c!=d) ||
          !istPrim(100*b+10*c+d))
             cout<<a<<b<<c<<d<<'\n';
    

    ?
    (OK ||-operator sollte nicht überladen sein)

    Gruß,

    Simon2.

    War auch mein Gedanke. Andererseits repräsentiert das eine anderer Denkweise:
    Indem wir alle Fälle zu eliminieren, die garantiert unerwünscht sind, bleibt nur das richtige Ergebnis übrig. Das ist der Ausgangscode.

    Schreiben wir hingegen eine einzige Bedingung hin ist das konstruktiv: wir formulieren, wie das Ergebnis beschaffen sein muss. Das ist dann also mehr als eine bloße Änderung des Codestils.



  • Interessante Diskussion, die daraus entstanden ist. 😉

    Ich wollte eigentlich nicht den Eindruck vermitteln, dass break und continue immer gut seien; eher, dass sie nicht zwingend schlecht sind. Ich verwende sie zwar ab und zu, aber versuche sie zu vermeiden, wenn es schön ohne geht.

    Meiner Meinung nach ist es in diesem Fall didaktisch nicht sinnvoll, Aussagen wie die des Lehrers zu machen. Bei goto ist das etwas anderes, weil sich da die meisten Leute einig sind, dass goto in 99% der Fälle zu Spaghetticode führt. Da ist es besser, als Lehrer verschweigt man das eine Prozent, aber hält Anfänger davon ab, garantierte Fehler zu machen. Die Macht von continue und break ist nichts gegen goto , das sieht man alleine schon daran, dass goto die anderen beiden nachbilden kann. Entsprechend ist die Fehleranfälligkeit um ein Vielfaches kleiner als bei goto .

    Bei break und continue sind die Meinungen betreffend Codestil – wie Mitleid angetönt hat – viel differenzierter. Gerade deshalb halte ich solche Aussagen für unangebracht. Wenn die Schüler nicht neugierig wie freakC++ sind, behalten sie ihren Glauben und gehen voreingenommen Probleme an. Gut möglich, dass sie durch Workarounds hässlicheren Code schreiben, als wenn sie die bösen Schlüsselwörter benutzt hätten. Und das alles, weil ihnen jemand gesagt hat, dass continue und break böse sind.

    Das muss natürlich nicht zwingend so sein, aber oft geht es in die Richtung. Von daher bin ich relativ skeptisch gegenüber solchen Behauptungen. Vielleicht kommt das auch ein wenig davon, dass in unserem Forum ab und zu solche aufgeschnappten Halbwahrheiten kursieren (Optimierungsüberlegungen == Premature Optimization, C ist unsauber, Zeiger sind gefährlich, virtual ist langsam...).



  • ich würde vorschlagen:

    bool liesZahlZwischenEinsUndZehn(int& zahl);
    
    int zahl;
    while(!liesZahlZwischenEinsUndZehn(zahl))
    {
        // Fehlermeldung
    }
    

    damit nix doppelt ist



  • camper schrieb:

    ...War auch mein Gedanke. Andererseits repräsentiert das eine anderer Denkweise:
    Indem wir alle Fälle zu eliminieren, die garantiert unerwünscht sind, bleibt nur das richtige Ergebnis übrig. Das ist der Ausgangscode.

    Schreiben wir hingegen eine einzige Bedingung hin ist das konstruktiv: wir formulieren, wie das Ergebnis beschaffen sein muss. Das ist dann also mehr als eine bloße Änderung des Codestils.

    Das stimmt natürlich.
    Aber ich bevorzuge Zweiteres auch inhaltlich. Natürlich kann man Beides falsch machen, aber Ersteres drückt für mich (auch wegen der abgeschlossenen statements) weniger die Verbindung der Prüfungen untereinander aus. Es hat so ein wenig den Charakter des "Ach ja - und das auch noch".

    Gruß

    Simon2.



  • Nexus schrieb:

    ...Gut möglich, dass sie durch Workarounds hässlicheren Code schreiben, als wenn sie die bösen Schlüsselwörter benutzt hätten. Und das alles, weil ihnen jemand gesagt hat, dass continue und break böse sind.
    ...

    Wäre mal ein interessantes Experiment:
    50% der Schüler lernen break und continue mit derselben "Wertfreiheit" kennen wie if und for.
    Die andere Hälfte wird vor der Benutzung von break/continue gewarnt.
    ... und am Ende des Schuljahres schaut man, wer den häßlicheren Code geschrieben hat. 😉

    Gruß,

    Simon2.



  • Vermutlich will der Informatiklehrer vermeiden, daß Schleifen zwei und mehr Laufbedingungen kriegen. Das wäre schlechter Stil.



  • Dravere schrieb:

    Um die Schleife zu verstehen, muss du sie in deinem Kopf wieder entpacken und hast dann im Kopf die Codeduplizierung.

    Ahja.. 🤡


Anmelden zum Antworten