C++ Kurs

for-Schleife

Die Themen:

Syntax
Initialisierungsausdruck
Abbruchbedingung
Schleifenaktion
Schleifenanweisung
Beispiel und Übung

Syntax

Sollen eine oder mehrere Anweisungen wiederholt ausgeführt werden, so werden hierfür Schleifen eingesetzt. In dieser Lektion lernen Sie eine der Schleifen kennen, die for-Schleife.

Die for-Schleife wird hauptsächlich dann eingesetzt, wenn bereits vor dem Eintritt in die Schleife bekannt ist, wie oft die in ihr enthaltenen Anweisungen ausgeführt werden sollen. Sie hat folgende Syntax:

for (Ausdruck1; Ausdruck2; Ausdruck3)
   Aktion;

Beachten Sie bitte, dass die Ausdrücke in der Klammer jeweils durch ein Semikolon voneinander getrennt werden und nach der schließenden Klammer der for-Schleife kein Semikolon steht. Sehen wir uns nun Schritt für Schritt den Aufbau der Schleife an.

Initialisierungsausdruck

Der erste Ausdruck innerhalb der Klammer ist der Initialisierungsausdruck. Er wird nur einmal ausgeführt und zwar bevor die erste Schleifenaktion ausgeführt wird.


for (int index=0; ... ; ...)
   Aktion;

Im Regelfall initialisiert er eine Schleifenvariable, d.h. er legt einen Startwert fest, mit dem die Schleife begonnen wird. Im Beispiel wird innerhalb der for-Schleife die Variable index definiert und mit dem Wert 0 initialisiert. Diese Variable aber nur innerhalb der for-Schleife gültig.

Der Initialisierungsausdruck kann auch aus mehreren Anweisungen bestehen. Die Anweisungen werden dann durch Komma (kein Semikolon!) getrennt, so wie unten dargestellt. Selbstverständlich müssen die im Beispiel verwendeten Variablen count und loop vorher irgendwo definiert worden sein.


for (count=10, loop=0; ... ; ...)
   Aktion;

Abbruchbedingung

Der nächste Ausdruck bestimmt das Ende der Schleife, d.h. unter welcher Bedingung die Schleife verlassen wird. Dieser Ausdruck ist in der Regel ein vergleichender Ausdruck. Die Schleife wird so lange durchlaufen, wie die Auswertung dieses Ausdrucks true ergibt.


for (int index=0; index<10; ...)
   Aktion;

count = 10;
for (loop=0; count<10; ...)
   Aktion;

Ergibt die Auswertung von Ausdruck2 schon vor dem Eintritt in die Schleife false, so wird die Schleifenaktion nicht ausgeführt! Dies ist z.B. in der zweiten for-Schleife oben der Fall.

Im obigen Beispiel bestand die Abbruchbedingung nur aus einem einfachen vergleichenden Ausdruck. Genauso gut können hier aber auch mehrere Bedingungen stehen, die dann durch entsprechende logische Operatoren verknüpft werden. Im nachfolgenden ersten Beispiel wird die for-Schleife so lange durchlaufen, so lange index kleiner 10 ist und done gleich false (Negation beachten!). Das zweite Beispiel enthält eine 'hinterlistige' Falle: der Compiler meldet Ihnen hier keinen Fehler (er gibt höchsten noch eine Warnung aus). Hier werden die Ergebnisse der Ausdrücke bitweise verundet, und das ist nun einmal etwas anderes wie eine logische Verundung.


for (index=0; (index<10) && (!done); ...)
   Aktion;
// Aber nie so!
for (index=0; (index<10) & (!done); ...)
   Aktion;

Die Anzahl der Bedingungen, die Sie in einer for-Schleife angegeben können, ist nicht begrenzt. Jedoch wird es bereits ab 3 Bedingungen schon etwas unübersichtlich, und damit später auch schwerer zu lesen. Versuchen Sie deshalb die Anzahl der Bedingung zu minimieren.

Und noch ein Hinweis bevor wir zum letzten Ausdruck übergehen: setzen Sie die einzelnen Bedingungen immer in Klammern. Dies ist zwar keine Vorschrift, jedoch vermeiden die Klammern oft unliebsame Überraschungen in Bezug auf die Rangfolge der Operatoren.

Schleifenaktion

Der letzte Ausdruck in der Schleifenklammer legt die Aktion fest, die nach dem Ausführen des Schleifenblocks (wird im Anschluss beschrieben) und vor dem erneuten Auswerten der Abbruchbedingung ausgeführt wird.


for (int index=0; index<10; index++)
   Aktion;

In der Regel wird hier die mit dem ersten Ausdruck initialisierte Schleifenvariable verändert. Auch dieser Ausdruck kann aus mehreren Anweisungen bestehen, die wieder durch Kommas getrennt werden. Der Lesbarkeit wegen sollten Sie jedoch hier wirklich nur die Schleifenvariable beeinflussen und alles andere mit in dem Anschluss beschriebenen Schleifenblock durchführen. Im Beispiel oben wird die Schleifenvariable um eins erhöht.

Jeder der 3 Ausdrücke, Schleifeninitialisierung, Abbruchbedingung und Schleifenaktion, ist optional, jedoch müssen die beiden Semikolon innerhalb der Klammer immer angegeben werden. Eine for-Schleife ohne Abbruchbedingung erzeugt z.B. eine Endlos-Schleife.


for (Ausdruck1; ; Ausdruck2)
   Aktion;

Schleifenanweisung

Kommen wir nun zum letzten Teil der for-Schleife, der Schleifenanweisung. Die Schleifenanweisung besteht standardmäßig nur aus einer einzigen Anweisung, so wie im ersten Beispiel unten. Sollen mehrere Anweisungen ausgeführt werden, was auch fast immer der Fall ist, so sind die Anweisungen in einen Block {...} einzuschließen (zweites Beispiel unten). Auch die Angabe ein Schleifenanweisung ist (zumindest in der Theorie) optional. Aus diesem Grund liefert die dritte dargestellt for-Schleife beim Übersetzen auch keinen Fehler. Hier wird einfach 10-mal gar nichts getan. Gute Compiler (und die meisten sind gut!) optimieren eine solche Schleife weg. Und noch bessere Compiler geben dann auch noch eine Warnung aus.


// Schleife mit einer Schleifenanweisung
for (int index=0; index<10; index++)
    cout << "Schleifenzähler: " << index << endl;

// Schleife mit mehreren Schleifenanweisungen
for (int index=0; index<10; index++)
{
   ... // Hier können jetzt mehrere
   ... // Anweisungen stehen
}

// Aber Achtung! Leerschleife
for (int index=0; index<10; index++);
   cout << "Schleifenzähler: " << index << endl;

Beispiel und Übung

Beispiel:

Das Programm berechnet die Bahngleichung eines schrägen Wurfs nach folgender Formel:

Weite = (Abwurfgeschwindigkeit2 * sin(2*Abwurfwinkel)) / G
Höhe  = (Abwurfgeschwindigkeit2 * sin(Abwurfwinkel)2) / (2*G)

Die Bibliotheksfunktion sin(...) zur Berechnung des Sinus hat folgende Funktionsdeklaration in cmath:

double erg = sin (double rad);

sin(...) erwartet den Winkel als Radiant und nicht in Grad! Die Abwurfgeschwindigkeit ist in beiden Formeln in m/s und G ist die Erdbeschleunigung 9.81m/s2. Beide Formeln liefern das Ergebnis in m zurück.

Beachten Sie im Beispiel, dass als Schleifenvariable der for-Schleife eine Gleitkommazahl verwendet wird. Die Abbruchbedingung der for-Schleife prüft auf kleiner als ab und nicht auf Gleichheit! Außerdem wird die Schleifenvariable hier pro Durchgang um 5 erhöht.

Winkel: 10.00 Grad -> Wurfweite: 3.49 m, Wurfhöhe: 0.15 m
Winkel: 15.00 Grad -> Wurfweite: 5.10 m, Wurfhöhe: 0.34 m
Winkel: 20.00 Grad -> Wurfweite: 6.55 m, Wurfhöhe: 0.60 m
Winkel: 25.00 Grad -> Wurfweite: 7.81 m, Wurfhöhe: 0.91 m
Winkel: 30.00 Grad -> Wurfweite: 8.83 m, Wurfhöhe: 1.27 m
Winkel: 35.00 Grad -> Wurfweite: 9.58 m, Wurfhöhe: 1.68 m
Winkel: 40.00 Grad -> Wurfweite: 10.04 m, Wurfhöhe: 2.11 m
Winkel: 45.00 Grad -> Wurfweite: 10.19 m, Wurfhöhe: 2.55 m
Winkel: 50.00 Grad -> Wurfweite: 10.04 m, Wurfhöhe: 2.99 m
Winkel: 55.00 Grad -> Wurfweite: 9.58 m, Wurfhöhe: 3.42 m
Winkel: 60.00 Grad -> Wurfweite: 8.83 m, Wurfhöhe: 3.82 m
Winkel: 65.00 Grad -> Wurfweite: 7.81 m, Wurfhöhe: 4.19 m
Winkel: 70.00 Grad -> Wurfweite: 6.55 m, Wurfhöhe: 4.50 m
Winkel: 75.00 Grad -> Wurfweite: 5.10 m, Wurfhöhe: 4.76 m
Winkel: 80.00 Grad -> Wurfweite: 3.49 m, Wurfhöhe: 4.94 m
Winkel: 85.00 Grad -> Wurfweite: 1.77 m, Wurfhöhe: 5.06 m 


// Beispiel zur for-Schleife

// Zuerst Dateien einbinden

#include <iostream>
#include <iomanip>
#include <cmath>

using std::cout;
using std::endl;

// main() Funktion
int main ()
{
   // Konstanten definieren
   const double GRAVITATION = 9.81;
   const double GRAD2RAD = 2.0 * 3.1416 / 360.0;

   // Abwurfgeschwindigkeit
   double geschw = 10.0;

   // Ausgabe mit Festkomma und 2 Nachkommastellen
   cout << std::fixed << std::setprecision(2);

   // Abwurfwinkel im Bereich 10...85 durchlaufen
   for (double winkel=10.0; winkel<90.0; winkel += 5.0)
   {
      // Winkel von Grad in Radiant umrechnen
      double wrad = winkel*GRAD2RAD;
      // Wurfweite berechnen
      double weite = (geschw*geschw*sin(2.0*wrad))/GRAVITATION;
      // Wurfhöhe berechnen
      double hoehe = (geschw*geschw)*(sin(wrad)*sin(wrad))/(2.0*GRAVITATION);
      // Ergebnis ausgeben
      cout << "Winkel: " << winkel << " Grad -> Wurfweite: "
           << std::setw(6) << weite << " m," << " Wurfhöhe: "
           << std::setw(6) << hoehe << " m" << endl;
   }
}

Übung:

Es ist eine Tabelle der ASCII-Zeichen mit den dezimalen Codes 32 bis 127 wie unten dargestellt auszugeben. Zuerst ist der jeweilige ASCII-Code 3-stellig auszugeben und dann das dazugehörige ASCII-Zeichen. Die Tabelle soll 5 Spalten besitzen.

Verwenden Sie für die Schleifenvariable eine unsigned char Variable. Wie Sie eine unsigned char Variable als Wert (und nicht als ASCII-Zeichen) ausgeben, das haben Sie hier erfahren.


 32     33 !   34 "   35 #   36 $
 37 %   38 &   39 '   40 (   41 )
 42 *   43 +   44 ,   45 -   46 .
 47 /   48 0   49 1   50 2   51 3
 52 4   53 5   54 6   55 7   56 8
 57 9   58 :   59 ;   60 <   61 =
 62 >   63 ?   64 @   65 A   66 B
 67 C   68 D   69 E   70 F   71 G
 72 H   73 I   74 J   75 K   76 L
 77 M   78 N   79 O   80 P   81 Q
 82 R   83 S   84 T   85 U   86 V
 87 W   88 X   89 Y   90 Z   91 [
 92 \   93 ]   94 ^   95 _   96 `
 97 a   98 b   99 c  100 d  101 e
102 f  103 g  104 h  105 i  106 j
107 k  108 l  109 m  110 n  111 o
112 p  113 q  114 r  115 s  116 t
117 u  118 v  119 w  120 x  121 y
122 z  123 {  124 |  125 }  126 ~
127

Lösung ansehen!