Elementare Syntax von C++: Schleifen

Wie im entsprechenden Kapitel zur Einf├╝hrung in die Programmierung werden hier die kopfgesteuerte Schleife, die fu├čgesteuerte Schleife und die Schleife mit Z├Ąhlvariable besprochen und einige Spitzfindigkeiten erkl├Ąrt, die die C++-Syntax dazu bereith├Ąlt. Weiter wird anhand der Schleifen das sehr viel weiter reichende Konzept des G├╝ltigkeitsbereiches (scope) einer Variable vorgestellt.
Noch keine Stimmen abgegeben
Noch keine Kommentare

Einordnung des Artikels

Dieses Kapitel zeigt die Syntax f├╝r Schleifen in C++; Schleifen im Pseudocode wurden ausf├╝hrlich besprochen in

├ťbersicht

Dieses Kapitel setzt genaue Kenntnisse der entsprechenden Inhalte ├╝ber Schleifen aus dem Kapitel ├╝ber Pseudocode und formale Sprachen voraus. Dazu geh├Ârt auch, dass Sie die dort gestellten Aufgaben in Pseudocode formulieren.

Wie im Kapitel ├╝ber Pseudocode werden die drei Arten von Schleifen (Iterationen) behandelt:

  1. kopfgesteuerte Schleife
  2. fu├čgesteuerte Schleife
  3. Schleife mit Z├Ąhlvariable

Da man beim Implementieren von Schleifen immer wieder die Frage stellen muss:

  • Welche Befehle geh├Âren vor den Schleifenk├Ârper?
  • Welche Befehle geh├Âren in den Schleifenk├Ârper?
  • Welche Befehle m├╝ssen erst nach dem Verlassen des Schleifenk├Ârpers abgearbeitet werden?

wird hier ein damit zusammenh├Ąngendes ÔÇö aber eigentlich sehr viel allgemeineres Konzept ÔÇö vorgestellt: der G├╝ltigkeitsbereich einer Variable (scope).

Die kopfgesteuerte Schleife

Im Pseudocode wurde die kopfgesteuerte Schleife mit den Textbausteinen solange und wiederhole formuliert:

solange (Bedingung)
    wiederhole (Anweisung);

In C++ steht anstelle von solange das Schl├╝sselwort while und die Anweisungen werden ohne einleitendes Schl├╝sselwort geschrieben. Im folgenden Beispiel wird die Summe der nat├╝rlichen Zahlen von 1 bis 100 berechnet; dazu wird eine Variable summe vorbereitet (deklariert und mit null initialisiert) und eine Variable i, mit deren Hilfe von 1 bis 100 gez├Ąhlt wird.

/* Programm zur Berechnung der Summe der nat├╝rlichen Zahlen von 1 bis 100
    mit Hilfe einer kopfgesteuerten Schleife */

int summe {0};
short i {1};

while (i < 101)
{
    summe += i;
    i += 1;
}
    
cout << "Summe: " << summe << endl;     // Summe: 5050

Zur Erkl├Ąrung:

1. Dass die Variable summe und die Z├Ąhlvariable i unterschiedlichen Datentyp haben (Zeile 4 und 5), st├Ârt nicht, wenn sie addiert werden: die implizite Typumwandlung (hier: Aufweitung) sorgt daf├╝r, dass summe eine int-Variable bleibt.

2. Mathematisch naheliegender w├Ąre es gewesen, die Bedingung mit i ÔëĄ 100 zu formulieren:

while (i <= 100)
 . . .

Sie sollten sich aber angew├Âhnen, wenn m├Âglich echte Ungleichungen einzusetzen (spart meist einen logischen Vergleich und somit Rechenzeit).

3. In der Schreibweise oben mit Pseudocode war im K├Ârper der Schleife (also der Teil nach wiederhole) nur eine Anweisung enthalten. Hier gibt es zwei Anweisungen und daher werden geschweifte Klammern gesetzt (Zeile 8 und 11).

4. Wenn die Schleife betreten wird, ist i = 1 und summe = 0. Beachten Sie die Reihenfolge, in der das Aufsummieren (Zeile 9) und das Hochz├Ąhlen (Zeile 10) ausgef├╝hrt werden: irgendwann wird beim Hochz├Ąhlen i = 101 gebildet, aber dann ist die Bedingung f├╝r das Betreten der Schleife nicht mehr erf├╝llt ÔÇö die Schleife wird verlassen. Und zum Aufsummieren wurden also die i-Werte von 1 bis 100 verwendet.

H├Ątte man Zeile 9 und 10 vertauscht (und sonst alles identisch gelassen), erh├Ąlt man ein anderes Ergebnis.

5. Wie im Kapitel ├╝ber Pseudocode erkl├Ąrt, ist das gew├Ąhlte Beispiel einfacher mit einer Schleife mit Z├Ąhlvariable zu formulieren ÔÇö es muss aber eine gleichwertige kopfgesteuerte Schleife mit while geben.

Tip:

Testen Sie immer die Werte der relevanten Variablen beim Betreten und Verlassen der Schleife.

Aufgaben:

1. Welche Zahlen werden aufaddiert, wenn im Programm-Beispiel oben Zeile 9 und 10 vertauscht werden (alles andere bleibt gleich)?

2. Schreiben Sie obiges Programm-Beispiel mit Hilfe des Inkrement-Operators.

Die fu├čgesteuerte Schleife

Obiges Beispiel kann leicht als fu├čgesteuerte Schleife formuliert werden, die Schl├╝sselworte dazu sind do und while:

/* Programm zur Berechnung der Summe der nat├╝rlichen Zahlen von 1 bis 100
    mit Hilfe einer fu├čgesteuerten Schleife */

int summe {0};
short i {1};

do
{
    summe += i;
    i += 1;
}
while (i < 101);
    
cout << "Summe: " << summe << endl;     // Summe: 5050

Zur Erkl├Ąrung:

  1. Im Schleifenk├Ârper (do-Block) stehen wieder mehrere Anweisungen, daher sind geschweifte Klammern zu setzen (Zeile 8 und 11). F├╝r eine einzige Anweisung ist dies nicht n├Âtig, erleichtert aber das Lesen des Quelltextes.
  2. Nach der Bedingung (Zeile 12), die steuert, ob die Schleife erneut durchlaufen oder verlassen wird, folgt ein Strichpunkt.

for-Schleifen (mit Z├Ąhlvariable)

Die Syntax der for-Schleife

Zuletzt soll die Variante vorgestellt werden, die dem Problem (Zahlen von 1 bis 100 aufaddieren) angemessen erscheint: Die Schleife mit Z├Ąhlvariable, die mit dem Schl├╝sselwort for realisiert wird.

Der Quelltext dazu lautet:

/* Programm zur Berechnung der Summe der nat├╝rlichen Zahlen von 1 bis 100
    mit Hilfe einer for-Schleife */

int summe {0};

for (short i {1}; i < 101; i++)
{
    summe += i;
}
    
cout << "Summe: " << summe << endl;     // Summe: 5050

Zur Erkl├Ąrung:

  1. Im Schleifenk├Ârper steht wieder die Anweisung, die f├╝r die Summation sorgt (Zeile 8).
  2. Allerdings fehlt im Schleifenk├Ârper jetzt die Anweisung zum Hochz├Ąhlen der Z├Ąhlvariable i.
  3. Ebenso fehlt vor der Schleife die Initialisierung der Z├Ąhlvariable i.
  4. Die letzten beiden Punkte (Initialisierung der Z├Ąhlvariable und Hochz├Ąhlen) werden durch die for-Anweisung realisiert, die aus drei Bestandteilen besteht (Zeile 6):
    • Deklaration und Initialisierung der Z├Ąhlvariable i
    • Bedingung unter der die Schleife erneut ausgef├╝hrt wird (i < 101); oder negativ formuliert: Abbruchbedingung (wenn i =101 erreicht wird).
    • Schrittweite (der Inkrement-Operator sorgt hier daf├╝r, dass die Schrittweite gleich eins ist ÔÇö das muss aber nicht sein).
  5. Diese drei Bestandteile der for-Anweisung sind durch Strichpunkte getrennt (Initialisierung der Z├Ąhlvariable; Ausf├╝hrungs-Bedingung; Schrittweite).
  6. Es ist sogar erlaubt (aber nicht empfehlenswert), jeden dieser drei Bestandteile durch mehrere Befehle zu ersetzen. Ein Beispiel folgt unten. Meist f├╝hrt das aber dazu, dass Anweisungen, die entsprechend der Programm-Logik in den Schleifenk├Ârper geh├Âren, in die for-Anweisung verschoben werden. Aber dadurch entstehen meist nur unklare Quelltexte.

Aufgaben

Aufgaben:

1. Das obige Programm soll so abge├Ąndert werden, dass zus├Ątzlich die Summe der Quadratzahlen (von 1 bis 100) berechnet und ausgegeben wird.

Zur Kontrolle: Die relevanten Formeln lauten

1 + 2 + ... + n-1 + n = n(n+1)/2

12 + 22 + ... + (n-1)2 + n2 = n(n+1)(2n+1)/6

2. Testen Sie, welchen Unterschied es macht, ob man zum Inkrementieren von i den Befehl i++ oder ++i verwendet.

3. Die scheinbar so einfachen Formeln oben zur Berechnung der Summe der Zahlen beziehungsweise der Summe der Quadratzahlen, sind f├╝r die Realisierung in einem Programm problematisch:

Berechnet man etwa

n(n+1)/2

mit einer Zahl n vom Datentyp int (oder short), h├Ąngt das Ergebnis von der Reihenfolge der Ausf├╝hrung der Operationen * und / ab. Denn man kann die Formel entweder wie

n * [(n + 1) / 2]       // zuerst: Division (Ausf├╝hrung der Operationen von rechts nach links)

oder wie

[n * (n + 1)] / 2       // zuerst: Multiplikation (Ausf├╝hrung der Operationen von links nach rechts)

lesen. Und ist jetzt n eine gerade Zahl, so ist n + 1 eine ungerade Zahl, was aber dazu f├╝hrt, dass die Ganzzahl-Division im ersten Fall nicht das gew├╝nschte Ergebnis liefert.

Lesen Sie in der Dokumentation nach, ob eine Formel wie

n * (n + 1) / 2

von rechts nach links (erste Version mit dem falschen Ergebnis) oder von links nach rechts (zweite Version mit dem richtigen Ergebnis) ausgewertet wird!

Zeigen Sie, dass

n(n+1)(2n+1)/6

immer ein ganzzahliges Ergebnis liefert.

Hinweis: 2n + 1 = (n +2) + (n - 1).

L├Âsungen:

1. Realisierung mit for-Schleife:

/* Programm zur Berechnung der Summe der Zahlen von 1 bis 100,
	sowie deren Quadratzahlen. */
	
int summe {0};
int summeQuad {0};          // Summe der Quadrate von i, i = 1,..., 100
short i {1};                // i wird VOR der Schleife deklariert und initialisiert (und nicht in der for-Anweisung), 
							// weil man sp├Ąter noch darauf zugreifen m├Âchte

for (; i < 101; i++)        // Z├Ąhlvariable muss nicht initialisiert werden: Anweisungsteil bleibt leer
{
	summe += i;
	summeQuad += i * i;
}

cout << "Summe: " << summe << endl;             // Summe: 5050
cout << "Summe der Quadrate: " << summeQuad << endl;        // Summe der Quadrate: 338350

i -= 1;         // ACHTUNG: i wurde bis 101 hochgez├Ąhlt (wegen i++) 
				// und damit war die Bedingung f├╝r die Wiederholung der Schleife nicht mehr erf├╝llt,
				// aber f├╝r die Formeln ben├Âtigt man i = 100
			
summe = i * (i + 1) / 2;
summeQuad = summe * (2 * i + 1) / 3;

cout << "Zur Kontrolle: " << endl;
cout << "Summe: " << summe << endl;             // Summe: 5050
cout << "Summe der Quadrate: " << summeQuad << endl;        // Summe der Quadrate: 338350

2. Es macht keinen Unterschied, ob man i++ oder ++i verwendet: Dazu muss man wissen, das der Inkrement-Befehl immer so ausgef├╝hrt wird als w├╝rde er am Ende des Schleifenk├Ârpers stehen.

3. Reihenfolge bei der Auswertung eines Termes

  • Die Multiplikation und Division wird tats├Ąchlich von links nach rechts ausgewertet. Wenn Sie sich aber nicht sicher sind, sollten in derartigen F├Ąllen stets durch Klammer-Setzungen die richtige Reihenfolge erzwingen.
  • Es ist n(n + 1)(2n + 1) = n(n + 1)(n + 2) + (n - 1)n(n+1). Das Produkt dreier aufeinanderfolgender Zahlen enth├Ąlt je einen Faktor, der durch 3 teilbar ist und einen Faktor, der durch 2 teilbar ist. Folglich ist n(n + 1)(2n + 1) durch 6 teilbar.

Gegenbeispiele

Allgemein besteht die for-Schleife aus folgenden Bestandteilen:

for ((Initialisierung); (Bedingung zur Wiederholung der Schleife); (Inkrement))
{
    (Anweisungen)
}

Ist die Bedingung zur Wiederholung der Schleife schon beim Betreten der Schleife nicht erf├╝llt (false), wird der Schleifenk├Ârper ├╝bersprungen, es wird sofort die Anweisung nach der Schleife ausgef├╝hrt.

Es ist stets ratsam, die hier nochmals ausdr├╝cklich benannten Bestandteile einer for-Schleife auch so einzusetzen wie es nach dieser Nomenklatur vorgesehen ist ÔÇö andernfalls sind die Quelltexte nur schwerer zu lesen. In diesem Abschnitt werden einige Beispiele gezeigt, wie man for-Schleifen nicht einsetzen soll; die Beispiele sind zwar syntaktisch korrekt, haben aber schwer verst├Ąndliche Quelltexte oder k├Ânnen zu nicht vorhersagbarem Verhalten f├╝hren.

├ťberladen der for-Anweisung

Die drei Bestandteile in der for-Anweisung sind durch Strichpunkte getrennt. Es ist sogar m├Âglich anstelle jedes dieser Bestandteile mehrere Befehle einzusetzen, die dann durch Kommas getrennt werden. Ein ÔÇö nicht nachahmenswertes ÔÇö Beispiel zeigt, wie dies aussehen k├Ânnte:

// NICHT NACHAHMEN

int sum;
int i;

for (sum = 0,  i = 1; i < 101; sum += i, i++);

cout << sum << endl;

Das Programm berechnet wieder einmal die Summe der Zahlen von 1 bis 100. Auf den ersten Blick scheint das Programm schlanker zu sein als die bisher gezeigten Versionen; allerdings ist der Quelltext aus mehreren Gr├╝nden schwerer zu lesen:

1. Die Deklaration und Initialisierung der Variablen ist getrennt; wie schon gesagt, soll man dies nur aus gutem Grund voneinander trennen ÔÇö hier besteht kein Grund dazu. Die Initialisierungen wurden hier nur in die for-Anweisung aufgenommen, um die Trennung der Befehle durch ein Komma zu zeigen.

2. Die eigentliche Aufgabe der Schleife, n├Ąmlich die Summe zu bilden mittels

sum += i;

geschieht jetzt zusammen mit dem Inkrement-Befehl f├╝r die Z├Ąhlvariable (Zeile 6). Dies ist ganz schlechter Stil: Die Befehle sollen immer dort stehen, wo man sie logisch erwartet (Summation im Schleifenk├Ârper, Inkrementieren als dritter Teil der for-Anweisung).

Z├Ąhlvariable als Gleitkommazahl (float oder double)

Das folgende Programm macht, was man von ihm erwartet:

// NICHT NACHAHMEN

float sum {0};

for (float i {1.0}; i < 2.0; i += 0.1)
    {
        sum += i;
    }
cout << sum << endl;

Es werden die Zahlen 1.0, 1.1, 1.2, ... , 1.9 addiert und ausgegeben (bei i == 2.0 wird die Schleife verlassen).

Das folgende Programm erscheint auf den ersten Blick gleichwertig zu sein:

// NICHT NACHAHMEN

float sum {0};

for (float i {1.0}; i != 2.0; i += 0.1)
    {
        sum += i;
    }
cout << sum << endl;

Hier wurde nur bei der Bedingungspr├╝fung i < 2.0 durch i != 2.0 ersetzt. Man erwartet wieder, dass die Schleife bei i == 2.0 verlassen wird. F├╝hrt man dieses Programm aus, wird eine Endlos-Schleife ausgef├╝hrt.

Aufgrund von Rundungsfehlern bei der Verwendung von Gleitkommazahlen wird die Zahl 2.0 nicht erreicht und die Schleife l├Ąuft endlos weiter.

Tip:

Verwenden Sie niemals Gleitkommazahlen als Z├Ąhlindex in einer Schleife; es kann immer zu unvorhersagbarem Verhalten kommen.

Mit ein wenig Bruchrechnen kann man die Summation oben auch mit Hilfe einer ganzzahligen Z├Ąhlvariable realisieren:

int sum = 0;

for (int i = 10; i < 20; i++)
{
    sum += i;
}
cout << static_cast<float> (sum) / 10 << endl;

Jetzt werden die Zahlen i = 10, 11, ... , 19 addiert und am Ende wird durch 10 dividiert.

Verschachtelte Schleifen

Schleifen k├Ânnen ÔÇö wie alle Strukturelemente eines Algorithmus ÔÇö beliebig ineinander verschachtelt werden.

Im folgenden Beispiel soll ein W├╝rfel zweimal geworfen werden und alle m├Âglichen Kombinationen der Augenzahlen sollen ausgegeben werden:

/* Ausgabe aller Ergebnisse beim zweimaligen Werfen eines W├╝rfels */

for (short i {1}; i < 7; i++)
{
    for (short k {1}; k < 7; k++)
    {
        cout << i << k << endl;
    }
}

Die Ausgabe besteht aus allen 36 Kombinationen, die aufsteigend angeordnet sind:

11
12
13
...
65
66

Aufgabe:

Der folgende Quelltext versucht die verschachtelten for-Schleifen durch eine einzige Schleife zu ersetzen, wobei die Komma-getrennten Anweisungen verwendet werden. Erzeugt der Quelltext die identische Ausgabe wie das Programm oben?

for (short i {1}, k {1}; i < 7, k < 7; i++, k++)
{
    cout << i << k << endl;
}

Das Komma zwischen i {1} und k {1} bedeutet hier: es werden zwei Variablen vom Typ short angelegt (und mit 1 initialisiert).

Welche Bedeutung hat die Warnung, die hier beim Compilieren erzeugt wird?

Die Schl├╝sselworte break und continue

So wie die Schleifen bisher behandelt wurden, kann man sie noch nicht sehr flexibel einsetzen: Allein die Bedingung steuert, ob die Schleife wiederholt oder verlassen wird und der gesamte Schleifenk├Ârper muss bei jedem Durchlauf abgearbeitet werden. Manchmal ist es aber w├╝nschenswert, dass

  • unter gewissen Umst├Ąnden, die Schleife vorzeitig verlassen wird oder dass
  • nur ein Teil des Schleifenk├Ârpers abgearbeitet wird (und sofort der n├Ąchste Durchlauf startet).

Diese beiden M├Âglichkeiten werden durch die Schl├╝sselworte break und continue realisiert; es folgen zwei Beispiele, die deren Einsatz demonstrieren.

1. Beispiel f├╝r die Verwendung von break:

Das Schl├╝sselwort break wurde schon bei der switch-Anweisung behandelt (siehe Elementare Syntax: Bedingung, Alternative und Mehrfachalternative); es kann auch bei Schleifen eingesetzt werden.

Im folgenden Programm wird die Summe

13 + 23 + ... + 993 + 1003

├Ąhnlich wie in den einf├╝hrenden Beispielen mit einer for-Schleife berechnet. Allerdings wird f├╝r die Summe der (ungeeignete) Datentyp short verwendet. Die Berechnung wird abgesichert: wenn durch den neu hinzukommende Summand der Wertebereich von short ├╝berschritten wird (siehe Zeile 16), wird die Schleife verlassen (Zeile 19).

/* Programm zur Berechnung der Summe der Zahlen i^3, i = 1,..., 100;
    Die Berechnung wird im folgenden Sinn abgesichert:
    Wenn der n├Ąchste Summand daf├╝r sorgen w├╝rde, dass die Grenze von short ├╝berschritten wird,
    bricht die Summation ab.
    */

short summe {0};
short i {0};

// Maximum von short berechnen
const short MAX_SHORT = std::numeric_limits<short>::max();

for (; i < 101; i++)
{
    short summand = i * i * i;
    if (summe > MAX_SHORT - summand)
    {
        cout << "vorzeitiger Abbruch mit: i = " << i << "\t\t Summe (bis i - 1) = "<< summe << endl;
        break;
    }
    summe += summand;
}
if (i == 101)
    cout << "kein vorzeitiger Abbruch mit: i = " << i << "\t\t Summe = "<< summe << endl;
            // vorzeitiger Abbruch mit: i = 19          Summe (bis i - 1) = 29241

2. Beispiel f├╝r die Verwendung von continue:

Es sollen alle Zahlen von 1 bis 100 ausgegeben werden, allerdings sollen die durch 7 teilbaren Zahlen weggelassen werden.

/* Ausgabe aller Zahlen von 1 bis 100 mit Ausnahme der durch 7 teilbaren Zahlen */

for (short i {1}; i < 101; i++)
{
if (i % 7 == 0)
    continue;
cout << i << endl;
}

Mithilfe des modulo-Operators l├Ąsst sich feststellen, ob eine Zahl durch 7 teilbar ist (Zeile 5). Die Anweisung continue in Zeile 6 sorgt daf├╝r, dass die folgenden Anweisungen des Schleifenk├Ârpers nicht mehr ausgef├╝hrt werden (hier ist dies nur die Ausgabe der entsprechenden Zahl). Stattdessen wird die Z├Ąhlvariable um 1 hochgez├Ąhlt und der n├Ąchste Schleifendurchlauf gestartet.

Die Ausgabe des Programmes lautet:

1
2
3
4
5
6
8
9
10
11
12
13
15
16
17
18
19
20
22
. . .

Der G├╝ltigkeitsbereich einer Variable (scope)

Oben wurden schon zwei Varianten zur Berechnung der Summe der Zahlen von 1 bis 100 vorgestellt, wobei auf den diffizilen Unterschied nicht eingegangen wurde. Die relevanten Quelltexte werden hier nochmals gezeigt:

1. Deklaration der Z├Ąhlvariable vor der Schleife:

int summe {0};
short i {1};

for (; i < 101; i++)
{
    summe += i;
}

cout << "Summe = " << summe << endl;                    // Summe = 5050
cout << "Index bei Abbruch der Schleife: " << i << endl;        // i = 101

2. Deklaration der Z├Ąhlvariable in der for-Anweisung:

int summe {0};

for (short i {1}; i < 101; i++)
{
    summe += i;
}

cout << "Summe = " << summe << endl;                // Summe = 5050
cout << "Index bei Abbruch der Schleife: " << i << endl;        // Compiler-Fehler: "error: 'i' was not declared in this scope"

Auf den ersten Blick unterscheiden sich die Quelltexte nur darin, wo der Z├Ąhlindex i definiert wird (einmal vor der Schleife in Zeile 2, einmal in der Schleife in Zeile 3). Dieser kleine Unterschied hat aber weitreichende Konsequenzen, es gilt n├Ąmlich die Regel:

Eine Variable ist in dem Block definiert, in dem sie deklariert wurde.
  • Im ersten Fall ist der Z├Ąhlindex i vor der Schleife, somit in der Methode main() deklariert und kann folglich in der gesamten main()-Methode verwendet werden. Hier in Zeile 10, wo ausgegeben wird, mit welchem Wert von i die Schleife verlassen wurde.
  • Dagegen ist im zweiten Fall i nur innerhalb der Schleife definiert (man sagt auch sichtbar) und daher f├╝hrt die folgende Ausgabe von i nach der Schleife zu einem Compiler-Fehler (Zeile 9).

Der Bereich, in dem eine Variable definiert (oder g├╝ltig oder sichtbar) ist, wird als ihr G├╝ltigkeitsbereich (scope) bezeichnet.

Das folgende Beispiel zeigt dies vielleicht noch deutlicher als die beiden vorhergehenden:

/* Programm zur Berechnung der Summe der geraden beziehungsweise ungeraden Zahlen zwischen 1 und 100 */

int summe {0};

for (short i {1}; i < 101; i += 2)          // ungerade Zahlen
{
    summe += i;
}
cout << "Summe der ungeraden Zahlen: " << summe << endl;            // 2500

summe = 0;
for (short i {2}; i < 101; i += 2)          // gerade Zahlen
{
    summe += i;
}
cout << "Summe der geraden Zahlen: " << summe << endl;          // 2550

Der Z├Ąhlindex i hat zwar in beiden Schleifen den identischen Namen, die beiden Variablen haben aber nichts miteinander zu tun; deshalb muss in der zweiten Schleife i neu deklariert werden. H├Ątte man dort nur initialisiert (mit i = 2), liefert dies einen Compiler-Fehler, da der Befehl i = 2 au├čerhalb des G├╝ltigkeitsbereiches der Variable i (aus Zeile 5) liegt.

Dagegen ist die Variable summe vor den Schleifen definiert (Zeile 3): summe ist jetzt ├╝berall sichtbar. Und daher muss vor der zweiten Schleife summe auch wieder auf null zur├╝ckgesetzt werden (Zeile 11) ÔÇö man w├╝rde sonst von 2500 ausgehend weitere Zahlen addieren.

Oben wurde gesagt, dass der G├╝ltigkeitsbereich einer Variable immer der Block ist, in dem sie definiert wurde. Dies muss keine Schleife oder dergleichen sein, man kann einen derartigen Block auch k├╝nstlich erzwingen, indem man geschweifte Klammern setzt, wie das folgende Beispiel zeigt:

{
    short i {1};
    doSomething(i);
}

{
    short i {2};
    doSomething(i);
}

Wieder verwendet man identische Namen f├╝r die Variable; und wieder muss i neu deklariert werden (Zeile 7), da der G├╝ltigkeitsbereich von i aus Zeile 2 nur innerhalb der ersten geschweiften Klammern liegt.

Identische Namen f├╝r Variablen aus unterschiedlichen G├╝ltigkeitsbereichen sollte man vermeiden, sobald auch nur die geringste Verwechslungsgefahr besteht.

Fehlerquelle:

Verwenden Sie niemals identische Namen f├╝r Variablen, die einen unterschiedlichen G├╝ltigkeitsbereich haben. F├╝r den Compiler ist zwar jede Variable eindeutig definiert, als Programmierer kann man die Variablen aber leicht verwechseln und semantische Fehler erzeugen.

Im Zusammenhang mit objektorientierter Programmierung wird man sehen, dass das Konzept des G├╝ltigkeitsbereiches sehr viel weitreichender ist als es hier erscheinen mag. Es erm├Âglicht die sogenannte Datenkapselung. Aber aus den hier vorgestellten Beispielen kann man vielleicht schon eine Grundregel erahnen:

Tip:

Versuchen Sie f├╝r jede Variable den G├╝ltigkeitsbereich so klein wie m├Âglich zu machen.

Aufgabe: Testen Sie, wie sich Variablen mit identischem Namen bei verschachtelten G├╝ltigkeitsbereichen verhalten, etwa wie im folgenden Beispiel:

{
int i {1};

    {
    int i {2};
    cout << "i = " << i << endl;
    }
}

Welchen Wert liefert die Ausgabe von i?

Aufgaben zu Schleifen

Im Kapitel ├╝ber Pseudocode und formale Sprachen wurden Aufgaben gestellt, die dort noch als Pseudocode zu formulieren waren.

Schreiben Sie nun die zugeh├Ârigen C++-Programme!