C++ Anweisungen: Die for-, while- und do-Schleifen

Die Programmiersprache C++ bietet einen konventionellen und flexiblen Satz von Anweisungen. Im Prinzip ist jede Programmzeile, die mit einem Semikolon endet, eine Anweisung. In diesem Unterpunkt werden wir die sogenannten Schleifenanweisungen behandeln und in der nächsten Vorlesung die Auswahlanweisungen vorstellen (siehe C++ Anweisungen: Auswahlanweisungen mit if und switch). Um die Sinnhaftigkeit von Schleifenanweisungen zu verdeutlichen, betrachten wir die (leicht abgeänderte) Programmierungsaufgabe 3 aus dem vorigen Übungsblatt (siehe Übungsblatt Nr.2, Aufgabe 3). Die Aufgabe soll jedoch nun sein, die Zahlenwerte der Folge $(a_n)_{n \in ℕ}$ mit $a_n := n^2$ für $n \in [0,1,2,..,10]$ in einem C++ Programm auszugeben. Natürlich könnte man die Inkrementierung der Variable $n$ und die cout-Ausgabe noch sieben zusätzliche Male am Ende der main()-Funktion hinzufügen und hätte die Programmieraufgabe auch gelöst. Was würde man jedoch machen, wenn $n \in [0,1,2,..,N]$ mit $N=10000$ wäre, oder die natürliche Zahl $N$ vom Benutzer des ausführbaren Programms selbst eingegeben werden sollte? Für solche und viele weitere, auf iterativen Anweisungen basierenden Problemen, sind Schleifen hilfreich und oft sogar notwendig.
Eine Schleife kann als eine for-, while- oder do-Anweisung ausgedrückt werden und die folgenden Programme zeigen die Verwendung dieser drei Schleifenanweisungen an unserem einfachen Beispiel, wobei die rechte untere Abbildung die Terminalausgabe nach dem Ausführen der Programme zeigt, die bei allen das gleiche Ergebnis liefert:

For_0.cpp
/* Berechnung und Ausgabe der Folgenglieder 
 * der Folge a_n=n^2 bis n=N */
#include <iostream>                 // Ein- und Ausgabebibliothek

int main(){                         // Hauptfunktion
    unsigned int n;                 // Deklaration des Folgenindex n 
    const unsigned int N = 10;      // Definition des maximal ausgegebenen Folgenindex 
    
    printf("%5s %5s \n","n","a_n"); // Ausgabe Beschreibung
    
    for(n=0; n<=N; ++n){            // Schleifen Anfang
        printf("%5i %5i \n",n,n*n); // Ausgabe des Folgenindex n und des Wertes des Folgengliedes
    }                               // Ende der Schleife 
}
While_0.cpp
/* Berechnung und Ausgabe der Folgenglieder 
 * der Folge a_n=n^2 bis n=N */
#include <iostream>                 // Ein- und Ausgabebibliothek

int main(){                         // Hauptfunktion
    unsigned int n = 0;             // Definition des Folgenindex n und gleichzeitige Initialisierung
    const unsigned int N = 10;      // Definition des maximal ausgegebenen Folgenindex
    
    printf("%5s %5s \n","n","a_n"); // Ausgabe Beschreibung
    
    while( n <= N ){                // Schleifen Anfang
        printf("%5i %5i \n",n,n*n); // Ausgabe des Folgenindex n und des Wertes des Folgengliedes
        ++n;                        // Folgenindex wird um eins erhöht
    }                               // Abruchbedingung der Schleife 
}
Do_0.cpp
/* Berechnung und Ausgabe der Folgenglieder 
 * der Folge a_n=n^2 bis n=N */
#include <iostream>                 // Ein- und Ausgabebibliothek

int main(){                         // Hauptfunktion
    unsigned int n = 0;             // Definition des Folgenindex n und gleichzeitige Initialisierung
    const unsigned int N = 10;      // Definition des maximal ausgegebenen Folgenindex
    
    printf("%5s %5s \n","n","a_n"); // Ausgabe Beschreibung
    
    do{                             // Schleifen Anfang
        printf("%5i %5i \n",n,n*n); // Ausgabe des Folgenindex n und des Wertes des Folgengliedes
        ++n;                        // Folgenindex wird um eins erhöht
    } while( n <= N );              // Abruchbedingung der Schleife 
}

Die for-Schleife

Die im Programm For_0.cpp verwendete for-Schleife ( for (n=0; n<=N; ++n){ ... } ) basiert auf der allgemeinen traditionellen Schreibweise einer for-Schleife, die die folgende Struktur besitzt:

for ('Initialisierungsteil'; 'Anweisungsbedingung'; 'Anweisung am Ende eines jeden Schleifendurchlaufs') { 'Block von Anweisungen' }

Im Initialisierungsteil ( n=0 ) wird die zuvor deklarierte Variable 'n' mit einem Anfangswert initialisiert. In unserem Beispiel stellt diese Variable den Folgenindex dar, und da wir die einzelnen Glieder der Folge beginnend von 'n = 0' ausgeben möchten, wird der Anfangswert auf Null gesetzt. Man hätte an dieser Stelle auch die Deklaration der Variable 'n' direkt in den Initialisierungsteil schreiben können (for (unsigned int n=0; n<=N; ++n){ ... } ), ohne dass man sie zu Beginn der main()-Funktion deklarieren müsste. Vollzieht man jedoch eine solche Deklaration im Initialisierungsteil der for-Schleife muss man beachten, dass die Verwendung der Variable 'n' nur auf den Gültigkeitsbereich der Schleife begrenzt ist, welcher durch die beiden geschweiften Klammern begrenzt ist (Gültigkeitsbereich: { 'Block von Anweisungen' }). Der zweite Eintrag der for-Schleife stellt die Anweisungsbedingung dar und definiert mittels logischer Vergleichsoperatoren wie lange die Schleife durchlaufen werden soll (in unserem Beispiel 'n<=N') und der dritte Eintrag gibt an welche Operation am Ende eines jeden Schleifendurchlaufs durchgeführt werden soll (in unserem Beispiel '++n'). Die in jedem Schleifendurchlauf zu erledigenden Anweisungen sind in einem Bereichsblock angeordnet, der durch die beiden geschweiften Klammern begrenzt ist (in unserem Beispiel: { printf("%5i %5i \n",n,n*n); }). Man hätte in unserem einfachen Beispiel die geschweiften Klammern auch weglassen können, da es sich ja um nur eine Anweisung handelt. Die so programmierte for-Schleife beginnt somit bei $n=0$, gibt diesen Wert und den Wert $n^2=0$ im Terminal aus und gelangt an das Ende des Schleifen-Blockes. Nun führt sie die definierte Anweisung am Ende eines jeden Schleifendurchlaufs aus, sie erhöht den Folgenindex $n$ um eins, und prüft mittels der Anweisungsbedingung, ob die Schleife ein weiteres Mal durchlaufen werden kann. In einem iterativen Prozess wird somit der Folgenindex immer weiter erhöht und die Anweisungsaufgaben erledigt, bis dann schließlich $n=11 > N=10$ ist und die Anweisungsbedingung nicht mehr erfüllt ist - dann erst wird der Schleifendurchlauf beendet.
Es sei hierbei noch erwähnt, dass es mehrere unterschiedliche Schreibweisen von for-Schleifen in C++ gibt, die sich von der vorgestellten traditionellen Schreibweise unterscheiden. So kann man z.B. mittels der sogenannten Bereichsbasierten for-Anweisungsbedingungen über eine zuvor definierte Zahlenmenge die Schleife laufen lassen (in unserem Beispiel z.B. 'for (auto n : n_array){ ... }' ), wobei die Zahlenmenge über die Schleife laufen soll in dem Zahlenarray 'n_array' zuvor mittels 'unsigned int n_array[N+1] = {0,1,2,3,4,5,6,7,8,9,10};' definiert werden muss (näheres zur Definition von Arrays unterschiedlicher Datentypen siehe ...). Das entsprechende C++ Programm finden Sie unter For_0b.cpp.

Die while-Schleife

Die im Programm While_0.cpp verwendete while-Schleife ( while ( n <= N ){ ... } ) basiert auf der allgemeinen Schreibweise einer while-Schleife, die die folgende Struktur besitzt:

while ('Anweisungsbedingung der Schleife') { 'Block von Anweisungen' }

Im Vergleich zu dem Programm, das die for-Schleife verwendet, muss man die Variable 'n' schon vor Beginn der Schleife mit Null initialisieren und am Ende des 'Blockes von Anweisungen' den Wert dieser Variable inkrementieren ( ++n; ). Eine while-Schleife führt den 'Block von Anweisungen' solange aus, bis die Anweisungsbedingung der Schleife nicht mehr erfüllt ist. while-Schleifen werden oft benutzt, wenn es keine offensichtliche Schleifenvariable (in unserem Beispiel die Variable 'n') gibt oder wenn die Aktualisierung der Schleifenvariable nicht am Ende des 'Anweisungsblockes' gemacht wird. In unserem Beispiel ist dies jedoch nicht der Fall und somit ist eine Formulierung mittels einer for-Schleife geeigneter, da man direkter den iterativen Ablauf der Schleife sieht.

Die do-Schleife

Die im Programm Do_0.cpp verwendete do-Schleife ( do { ... } while( n <= N ); ) basiert auf der allgemeinen Schreibweise einer do-Schleife, die die folgende Struktur besitzt:

do { 'Block von Anweisungen' } while ('Anweisungsbedingung der Schleife');

Wie im Programm, das die while-Schleife verwendet, muss die Variable 'n' auch hier schon vor Beginn der Schleife mit Null initialisieren und am Ende des 'Blockes von Anweisungen' den Wert dieser Variable inkrementieren ( ++n; ) werden. Eine do-Schleife führt den 'Block von Anweisungen' solange aus, bis die Anweisungsbedingung der Schleife nicht mehr erfüllt ist. Eine do-Schleife ist einer while-Schleife sehr ähnlich, außer dass die Anweisungsbedingung erst nach dem Schleifenkörper, dem 'Block von Anweisungen', steht. Im Gegensatz zur while-Schleife wird der 'Block von Anweisungen' somit mindestens einmal ausgeführt, bevor die, in der 'Anweisungsbedingung der Schleife' formulierte Abbruchbedingung der Schleife, getestet wird .

Schleifenanweisungen finden ihre Verwendung in den unterschiedlichsten Anwendungsbereichen und wir werden im nächsten Unterpunkt die Anwendung auf mathematische Folgen vertiefen und die Anwendung auf mathematisch definierte Reihen vorstellen (siehe Unterkapitel Anwendungsbeispiel: Folgen und Reihen).