Schleifen in C/C++/Java Alle 3 Sprachen stellen mindestens die folgenden 3 Schleifenkonstruktionen zur Verfügung. In C gibt es auch keine weiteren, C++, Java und C# haben noch weitere nützliche Varianten. Im Unterschied zur if-anweisung, bei der die davon abhängige Anweisung nur ein Mal durchlaufen wird (wenn überhaupt), wird bei Schleifen diese Anweisung (oder der ganze Block) so lange wiederholt, wie die Bedingung wahr bleibt (u.u. auch unendlich oft!). while Schleife while (Ausdruck) // die runden Klammern sind Pflicht // Einrücken erhöht die Übersichtlichkeit oder: while (Ausdruck) { Noch-eine-Anweisung;... } Die von while abhängige Anweisung (bzw. der ganze {}-Block) wird solange wiederholt, wie der Ausdruck wahr (ungleich 0 in C/true in C++) ist. Ist der Ausdruck schon am Beginn falsch (= 0), so wird die Schleife NIE durchlaufen. In Java muss die Bedingung ein Ausdruck vom Typ boolean sein. Eine sehr nützliche Eigenschaft der Streameingabe >> von C++ ist, dass sie bei der Verwendung als Bedingung in einer Schleife oder in einem if den Erfolg oder Misserfolg der Einleseoperation zurückgibt! Beispiel: while (x > 0) while (1) // Warte auf den Überlauf // die EWIGE Schleife in C/C++, in Java/C++: while (true) while (0) // die NIEMALS durchlaufene Schleife in C/C++, Fehler in Java while (cin >> x) // lies Werte ein, solange welche da sind cout << "Habe erfolgreich " << x << " eingelesen!\n";
Fehler: while (x > 0); // Der Strichpunkt zählt als leere Anweisung // ist NICHT MEHR in der Schleife while (x > 0) cout << "x: " << x << '\n'; // nicht mehr in der Schleife do while Schleife do while (Bedingung); oder do { noch eine Anweisung;... } while (Bedingung); Die do while Schleife wird mindestens 1x durchlaufen, da die Bedingung erst am Ende gecheckt wird. for Schleife for (vorher; Bedingung; am_ende_jedes_durchlaufs) Anweisung; // oder mit {} geklammerter Block Diese for-schleife lässt sich zu der folgenden äquivalenten while-schleife umschreiben: { vorher; while (Bedingung) {
} } Anweisung; am_ende_jedes_durchlaufs; vorher: Anweisung, die immer ausgeführt wird (auch wenn der eigentliche Schleifenrumpf gar nicht durchlaufen wird). Sie wird vor dem erstmaligen Check der Bedingung ausgeführt. Hier setzt man oft Zählvariablen oder Summenvariablen auf einen Anfangswert. Wird hier eine Variable deklariert, dann ist diese nur INNERHALB der Schleife bekannt. Bedingung: Was bei while in den runden Klammern steht. Die Bedingung wird hier OHNE die Klammern geschrieben. Eine fehlende Bedingung wird als immer wahr (true) interpretiert. am_ende_jedes_durchlaufs: Wird meist zum Erhöhen der Zählvariablen verwendet. Beispiel: Countdown von 10: for (int i = 10; i >= 0; --i) cout << i << '\n'; Da die for-schleife sehr kompakte Konstruktionen erlaubt, wird sie am häufigsten von allen Schleifentypen eingesetzt. Falls man keine vorher-anweisung oder kein am_ende_jedes_durchlaufs benötigt, muss man trotzdem die 2 Strichpunkte machen. for (i = 10; i >= 0;) cout << i-- << '\n'; // das Dekrementieren wurde // hierher verlagert Range based for-schleife in C++ Diese steht ab dem Sprachstandard C++11 zur Verfügung und erlaubt es, alle Elemente einer Containerklasse (z.b. std::vector, std::list aber auch normale Arrays) zu durchlaufen. Die Syntax ist: for (variablendeklaration : container-variable) Anweisung; // oder Block in {}
std::vector<int> v{1,2,3,4,5}; for (int i : v) // oder: for (auto i : v) cout << i <<'\n'; double u[] = {1,2,3,4,5}; for (auto x : u) cout << x <<'\n'; // x hat den Typ, der in u gespeichert ist // gibt alle Werte von u aus for (auto x : u) x = 5; // x hat den Typ, der in u gespeichert ist // ändert die Variable x aber nicht u (= Unsinn) for (auto& x : u) // x ist Referenz auf den Typ, der in u gespeichert ist x = 5; // ändert alle Elemente von u!!!!! for (const auto& x : u) // x ist konstante Referenz x = 5; // das ist ein Fehler, da x konstant ist break und continue Anweisungen Diese 2 Anweisungen zählt man zu den erweiterten Sprunganweisungen. Sie sind nur in Schleifen erlaubt (break zusätzlich noch in switch case Blöcken). break: Bricht die innerste (bei mehreren ineinander geschachtelten Schleifen) Schleife ab und verzweigt hinter diese. continue: Bricht den aktuellen Durchlauf der innersten (bei mehreren ineinander geschachtelten Schleifen) Schleife ab und beginnt einen neuen Durchlauf. Hierbei wird nicht die Schleife selbst beendet sondern nur der aktuelle Durchlauf durch diese. Bei einer while oder do while Schleife springt continue auf den Test der Bedingung, bei einer for Schleife auf am_ende_jedes_durchlaufs gefolgt von der Bedingung. Beispiel: Wir fordern ganze Zahlen an (bis 0 kommt) und untersuchen die geraden positiven int x, gelesen, positiv, gerade; for (gerade = positiv = gelesen = 0;;) { cout << "int Nr. " << ++gelesen << "(Ende bei 0): "; if (! (cin >> x) x == 0) break; // Keine Zahl oder 0 wurde eingegeben!
} if (x < 0) // negative Zahlen ignorieren wir continue; // brich hier ab und lies die nächste Zahl ein ++positiv; // hier muss die Zahl sicher positiv sein if (x % 2!= 0) // Divisionsrest durch 2 nicht 0 => ungerade continue; ++gerade; Hier haben wir z.b. keine Bedingung, also handelt es sich im Prinzip um eine Endlosschleife. Wir haben aber in der Schleife selbst ein ordnungsgemäßes Ende mittels if und break programmiert. Mit der continue-anweisung halten wir die Anzahl der Einrückungen klein, weil wir sofort zur Eingabe der nächsten Zahl verzweigen, wenn wir die Bearbeitung der aktuellen abgeschlossen haben (keine verschachtelten if else Konstruktionen). Die break Anweisung beendet nur die innerste Schleife. Will man gleich mehrere verschachtelte Schleifen auf einmal beenden, verwendet man am besten eine goto- Anweisung, selbst wenn diese einen schlechten Ruf besitzt (Spaghetti-Code). Auch ein return (falls möglich) beendet sämtliche Schleifen auf einmal und verlässt die Funktion.