Die neueste CRAY bewältigt eine Endlosschleife in sechs Sekunden.
– Computer-Folklore
Anweisungen und Anweisungsfolgen
Eine Anweisung ist ein durch Semikolon abgeschlossener Ausdruck. Neben Anweisungen, die tatsächlich Daten verarbeiten, enthält ein Programm Definitionen und Deklarationen (Ankündigungen) für Variablen, Datentypen und Funktionen. Eine Anweisungsfolge wird von geschweiften Klammern als Block umschlossen:
//> cpp_basics/anweisungsblock.cppimport std;int main(){ int a = 2, b = 4; std::println("{} {}", a, b); { int temp = a; a = b; b = temp; } std::println("{} {}", a, b);}
Wiederholungen
Heutige Computer können viele Millionen von Operationen je Sekunde (MOPS-Geschwindigkeit!), sogar Milliarden, ausführen. Dennoch gelingt es, sie auf Jahre mit Arbeit auszulasten. Das Geheimnis liegt darin, nicht jeden Befehl für jede Operation einzeln zu schreiben, sondern den Computer dazu zu bringen, dieselben Operationen mit anderen Werten wiederholt auszuführen. Weil Wiederholungsanweisungen so bedeutsam sind, besitzt C++ dafür mehrere Ausdrucksformen:
Syntax
do Anweisung while (Bedingung);while (Bedingung) Anweisungfor (Initialisierung; Bedingung; Inkrement) Anweisungfor (Element : Wertefolge) Anweisung
kopfgesteuert
fußgesteuert
n+1/2-Schleife
Eine Bedingung wird geprüft. Ist sie erfüllt, wird die Anweisung oder Anweisungsfolge ausgeführt und danach wiederum geprüft, ob die Bedingung erfüllt ist. Bei nicht erfüllter Bedingung wird die Schleife abgebrochen. Formulierungen wie „Wiederhole bis …“ werden als gegenteilige Bedingung „Wiederhole, solange nicht …“ formuliert.
Der Rumpf einer while-Anweisung wird nur ausgeführt, nachdem die Bedingung als wahr ausgewertet wurde (kopfgesteuerte Schleife). Der Rumpf einer do ... while (...);-Anweisung wird dagegen mindestens einmal ausgeführt. Die Prüfung, ob wiederholt werden muss, erfolgt nach der ersten Ausführung (fußgesteuerte Schleife).
Die for-Anweisung bündelt die Festlegung von Startwerten, Bedingung und Aktualisierung an ihrem Anfang und ist äquivalent zu einer while-Anweisung. Die Lebensdauer in der Initialisierung definierter Variablen endet beim Verlassen der Schleife:
//> cpp_basics/zaehlschleifen.cppimport std;int main(){ for (int i = 0; i < 10; ++i) { std::print("{} ", i); } std::println(); // äquivalent zu { int i = 0; while (i < 10) { std::print("{} ", i); ++i; } } std::println();}
Solche Wiederholungsanweisungen werden als Zählschleifen bezeichnet. Im Steuerteil der for-Anweisung definierte Variablen existieren nur bis zum Verlassen der Schleife. In einer Zählschleife müssen Bedingung und Inkrement tatsächlich den Schleifenzähler betreffen. Nachlässig kopierte verschachtelte Schleifenköpfe, die Schleifenzähler i und j verwechseln, werden gern übersehen. Compiler übergehen solche Anfängerfehler ebenfalls, denn for- und while-Anweisungen sind nicht auf das Zählen beschränkt.
Bleibt die Bedingung einer for-Anweisung leer, wird diese als true gewertet: for(;;) ... kann als „für immer“ gelesen werden und als while (true) ... formuliert werden. Eine solche „Endlosschleife“ wird durch eine bedingte return-Anweisung, oder break; im Schleifenrumpf verlassen („n+1/2-Schleife“).1
Ansammlungen gegebener Werte verarbeitet man bequem mit einer „range-based for loop“, ohne sich um Schleifenzähler kümmern zu müssen:
//> cpp_basics/for_range.cppimport std;int main(){ for (auto element : { 2, 3, 5, 7 }) { std::println("{}", element); }}
Man kann hier noch einen Startwert für einen Zähler voranstellen:
//> cpp_basics/for_range_counted.cppimport std;int main(){ for (auto n = 1; auto element : { 2, 3, 5, 7 }) { std::println("{}. Primzahl = {}", n++, element); }}
Aufgaben
Schreibe kleine Programme, die unter Nutzung von Schleifen Folgendes ausgeben:
20 mal "I will not waste chalk." oder einen beliebigen anderen Tafelspruch von Bart Simpson.
die einstelligen natürlichen Zahlen einschließlich der Null in aufsteigender bzw. absteigender Folge,
deren 2-, 3-, bzw. Vielfache,
ein Rechteck aus Sternchen "*" mit vorgegebener Breite und Höhe,
ein Dreieck bzw. halbes Quadrat links/rechts oberhalb/unterhalb der Diagonale.
Formuliere die Schleifen jeweils als while- und als for-Anweisungen. Vergleiche.
Schreibe ein Programm, welches mmittels zweier verschachtelter Schleifen das kleine Einmaleins ausgibt, tabellarisch formatiert mit "\t".
Finde einen Anwendungsfall für eine n+1/2-Schleife.
Entscheidungen
Eine Entscheidungsanweisung hat diese allgemeine Form:
Syntax
if (Bedingung) dann_Anweisung else sonst_Anweisungif (Bedingung) dann_Anweisung
Der Sonst-Zweig muss nicht angegeben werden. Beide Zweige als geschweifte Klammerblöcke zu schreiben, erhöht die Lesbarkeit auch dann, wenn nur Einzelanweisungen darin enthalten sind. In begründeten Fällen kann man davon abweichen.
Eine quadratische Gleichung in der Normalform x2+px+q=0 ist nur bei lösbar, wenn deren Diskriminante D=p2/4−q nicht negativ ist. Diese Bedingung in einer if-Anweisung entscheidet, welcher Zweig von Anweisungen abgearbeitet wird:
//> cpp_basics/pq-formel.cppimport std;int main(){ double p = 2.0, q = -1.0; double D = p * p / 4 - q; if (D >= 0) { double x1 = -p/2 - std::sqrt(D); double x2 = -p/2 + std::sqrt(D); std::println("{} {}", x1, x2); } else { std::println("nicht lösbar"); }}
Sind mehr als zwei Alternativwege zu berücksichtigen (Mehrfachverzweigung, „if-else-Leiter“), sollte zwischen den Schlüsselwörtern elseund if kein geschweifter Klammerblock eröffnet werden:
Das erspart eine weitere Einrückung und lässt alle drei Fälle gleichberechtigt erscheinen.
Aufgaben
Entwirf ein Programm, welches quadratische Gleichungen der Form ax2+bx+c=0 nach Eingabe beliebiger reellwertiger Koeffizienten a, b, c löst.
Setze den Entwurf um und teste dein Programm.
Wie reagiert dein Programm auf Spezialfälle (Nullen in a,b oder c)?
Wie viele Entscheidungen sind verschachtelt? Bewerte die Verständlichkeit des Quelltextes.
Anmerkungen
Die Anweisung break; unterbricht nur die innerste von verschachtelten Schleifen. Soll die umgebende Funktion nicht verlassen werden, scheint ein Sprung zu einer Textmarke außerhalb der Schleifen einer der wenigen sinnvollen Anwendungsfälle für goto ...; zu sein. ↩