6. Kontrollstrukturen
Mit Kontrollstrukturen sind die Befehle und Zeichenfolgen gemeint, die den Ablauf des
Programms steuern. Dazu gehören im wesentlichen verschiedene Verzweigungen und
Schleifen.
6.1. Sequenzen
Diese Struktur ist schon bekannt: das Semikolon (";"). Jede Anweisung
muss mit einem Semikolon abgeschlossen sein, damit der C-Compiler weiß, an welcher Stelle
die Anweisung zu Ende ist.
Es können mehrere Operationen hintereinander gestellt werden, wenn sie durch Kommata
voneinander getrennt werden. Diese Operationen werden von links nach rechts ausgewertet;
das Ergebnis der letzten Operation ist gleichzeitig das Ergebnis der gesamten Operation.
Diese Eigenschaft wird weiter unten bei der for-Schleife ausgenutzt.
Beispiel:
kap06_01.c
01 #include <stdio.h>
02
03 int main()
04 {
05 char c_alt, c_neu, c = 'z';
06
07 c_neu = (c_alt = c, c = 'a');
08 printf("c = %c\n", c);
09 printf("c_alt = %c\n", c_alt);
10 printf("c_neu = %c\n", c_neu);
11
12 return 0;
13 }
Ausgegeben wird:
c = a
c_alt = z
c_neu = a
In der Klammer in Zeile 7 wird zuerst der Inhalt von c der Variable
c_alt zugewiesen ('z'). Dann erhält
c den neuen Wert ('a'). Dieser Wert ist
gleichzeitig das Ergebnis des gesamten Klammerausdrucks und wird der Variablen
c_neu zugewiesen.
Hinweis:
Die Klammer ist dringend notwendig, da der Komma-Operator die geringste Priorität hat.
Würde die Klammer weggelassen werden, entspräche es folgender Zeile:
(c_neu = c_alt = c), c = 'a';
c_neu hätte damit das 'z' und nicht das
'a' als Inhalt.
6.2. Verzweigung: if-Anweisung
Oft ist es nötig, Anweisungen in Abhängigkeit von Bedingungen auszuführen.
Der einfachste Befehl zum Abfragen von Bedingungen und anschließendem Verzweigen in
Abhängigkeit der Bedingung ist die if-Anweisung bzw.
if-Abfrage (auf keinen Fall if-Schleife!). Sie hat
folgende Syntax:
if (Bedingung)
Anweisung1;
else
Anweisung2;
Gelesen wird dieser Block folgendermaßen: Wenn die Bedingung wahr ist, dann
führe Anweisung1 aus, sonst führe
Anweisung2 aus. Dabei kann der else-Teil
(also else Anweisung2) weggelassen werden. Wichtig ist,
dass nur hinter den Anweisungen ein Semikolon gesetzt wird aber nicht hinter
if (Bedingung) und else.
Beispiel:
kap06_02.c
01 /***********************************************
02 * Dieses Programm liest drei ganze Zahlen ein
03 * und ermittelt das Maximum der drei Zahlen.
04 * Eingabe: Zahl1, Zahl2, Zahl3
05 * Ausgabe: Maximum
06 ***********************************************/
07 #include <stdio.h>
08
09 int main()
10 {
11 long Zahl1, Zahl2, Zahl3, Maximum;
12
13 printf("Dieses Programm ermittelt das Maximum ");
14 printf("von drei eingegebenen Zahlen.\n");
15 printf("Bitte geben Sie drei ganze Zahlen ein: ");
16 scanf("%ld %ld %ld", &Zahl1, &Zahl2, &Zahl3);
17 if (Zahl1 > Zahl2)
18 Maximum = Zahl1;
19 else
20 Maximum = Zahl2;
21 if (Zahl3 > Maximum)
22 Maximum = Zahl3;
23 printf("Das Maximum der drei Zahlen lautet: ");
24 printf("%li\n", Maximum);
25
26 return 0;
27 }
Um anstelle der Anweisung1 und
Anweisung2 mehrere Anweisungen durchführen zu lassen,
müssen diese Anweisungen jeweils in einen Block geschrieben werden, d.h. sie
müssen in geschweifte Klammern gesetzt werden. Die Syntax sieht dann
folgendermaßen aus:
if (Bedingung)
{
Anweisung1a;
Anweisung1b;
Anweisung1c;
}
else
{
Anweisung2a;
Anweisung2b;
}
if-Anweisungen können auch geschachtelt werden. Dabei muss
allerdings sehr genau darauf geachtet werden, welches else zu welchem
if gehört. Durch das Einrücken der Anweisungen wird die
Zugehörigkeit sehr deutlich sichtbar.
if (Bedingung)
{
Anweisung1;
if (Bedingung1)
{
Anweisung11a;
Anweisung11b;
}
else
{
Anweisung12a;
Anweisung12b;
}
}
else
{
if (Bedingung2)
{
Anweisung21a;
if (Bedingung21)
Anweisung211;
}
else
{
Anweisung22a;
Anweisung22b;
}
Anweisung2;
}
Beispiel:
kap06_03.c
01 /***********************************************
02 * Dieses Programm liest vier ganze Zahlen ein
03 * und ermittelt das Maximum der vier Zahlen.
04 * Eingabe: Zahl1, Zahl2, Zahl3, Zahl4
05 * Ausgabe: Maximum
06 ***********************************************/
07 #include <stdio.h>
08
09 int main()
10 {
11 long Zahl1, Zahl2, Zahl3, Zahl4, Maximum;
12
13 printf("Dieses Programm ermittelt das Maximum ");
14 printf("von vier eingegebenen Zahlen.\n");
15 printf("Bitte geben Sie vier ganze Zahlen ein: ");
16 scanf("%ld %ld %ld %ld", &Zahl1, &Zahl2, &Zahl3, &Zahl4);
17 if (Zahl1 > Zahl2)
18 if (Zahl3 > Zahl4)
19 if (Zahl1 > Zahl3)
20 Maximum = Zahl1;
21 else
22 Maximum = Zahl3;
23 else
24 if (Zahl1 > Zahl4)
25 Maximum = Zahl1;
26 else
27 Maximum = Zahl4;
28 else
29 if (Zahl3 > Zahl4)
30 if (Zahl2 > Zahl3)
31 Maximum = Zahl2;
32 else
33 Maximum = Zahl3;
34 else
35 if (Zahl2 > Zahl4)
36 Maximum = Zahl2;
37 else
38 Maximum = Zahl4;
39 printf("Das Maximum der vier Zahlen lautet: ");
40 printf("%li\n", Maximum);
41
42 return 0;
43 }
Eine Mehrfachverzweigung kann als eine Serie von
if-else-Anweisungen angesehen werden. Dabei ist in
jedem (außer im letzten) else-Zweig eine weitere
if-Anweisung enthalten. Dies sieht wie folgt aus:
if (Bedingung1)
Anweisung1;
else
if (Bedingung2)
Anweisung2;
else
if (Bedingung3)
Anweisung3;
else
Anweisung4;
Dabei kann es bei vielen Verzweigung dazu führen, dass der Quelltext sehr weit nach
rechts eingerückt wird. Dies führt beim Ausdrucken unter Umständen zu sehr
unleserlichen Quelltexten und auch auf dem Bildschirm muss unter Umständen viel nach
links und rechts geblättert werden. Daher sollte die Einrückung bei
Mehrfachverzweigungen etwas variiert werden:
if (Bedingung1)
Anweisung1;
else if (Bedingung2)
Anweisung2;
else if (Bedingung3)
Anweisung3;
else
Anweisung4;
6.3. Verzweigung: ? : -Anweisung
Diese Anweisung ist eine Kurzform der if-Anweisung und sieht wie folgt
aus:
(Bedingung) ? Anweisung1 : Anweisung2;
Die entsprechende if-Anweisung sieht folgendermaßen aus:
if (Bedingung)
Anweisung1;
else
Anweisung2;
Aber nicht nur Anweisungen sondern auch einfache Ausdrücke (wie Zahlen, Zeichen, usw.)
lassen im Gegensatz zur if-Anweisung hier einsetzen. Als Ergebnis kann
dann der erste oder der zweite Ausdruck einer Variablen zugeordnet oder in einer Abfrage
verwendet werden. Dadurch können kleine Verzweigungen in einer Zeile geschrieben
werden. Das nächste Beispiel greift noch einmal die erste Variante der
Maximumsbestimmung auf. Jetzt werden aber die if-Anweisungen durch
?:-Anweisungen ersetzt.
Beispiel:
kap06_04.c
01 /***********************************************
02 * Dieses Programm liest drei ganze Zahlen ein
03 * und ermittelt das Maximum der drei Zahlen.
04 * Eingabe: Zahl1, Zahl2, Zahl3
05 * Ausgabe: Maximum
06 ***********************************************/
07 #include <stdio.h>
08
09 int main()
10 {
11 long Zahl1, Zahl2, Zahl3, Maximum;
12
13 printf("Dieses Programm ermittelt das Maximum ");
14 printf("von drei eingegebenen Zahlen.\n");
15 printf("Bitte geben Sie drei ganze Zahlen ein: ");
16 scanf("%ld %ld %ld", &Zahl1, &Zahl2, &Zahl3);
17 Maximum = (Zahl1 > Zahl2) ? Zahl1 : Zahl2;
18 Maximum = (Zahl3 > Maximum) ? Zahl3 : Maximum;
19 printf("Das Maximum der drei Zahlen lautet: ");
20 printf("%li\n", Maximum);
21
22 return 0;
23 }
6.4. Fallunterscheidung: switch-Anweisung
Die if-Anweisung ist besonders für Aufgaben geeignet, die nur ein
oder zwei Bedingungen betreffen. Durch mehrere gleichwertige Bedingungen (d.h. als
Bedingung wird immer wieder die gleiche Variable abgefragt) wird der Programmcode
durch die Verschachtelung schnell unübersichtlich. Hierfür gibt es die
switch-Anweisung. Ihre Syntax sieht wie folgt aus:
switch (Ausdruck)
{
case Wert1:
Anweisungen1;
break;
case Wert2:
Anweisungen2;
break;
case Wert3:
Anweisungen3;
break;
...
default:
Ersatzanweisungen;
}
Der Datentyp von Ausdruck muß eine ganze Zahl (int)
sein oder muss sich in eine ganze Zahl umwandeln lassen, z.B. ein Zeichen
(char). Reelle Zahlen und Zeichenketten sind nicht zugelassen!
Die Werte hinter dem case müssen konstante Werte sein. Dabei
können die Werte als ganze Zahl oder als Zeichen angegeben werden.
Mit Hilfe des break; wird die switch-Anweisung
beendet. Andernfalls werden die Anweisungen der weiteren case-Zeilen
auch durchgeführt. Dieses kann auch dazu verwendet werden, um verschiedenen Fälle
zusammenzufassen, d.h. in verschiedenen Fällen werden die gleichen Anweisungen
ausgeführt (siehe das folgende Beispiel).
Beispiel:
kap06_05.c
01 /***********************************************
02 * Dieses Programm fragt das Geschlecht ab und
03 * gibt das Ergebnis auf dem Bildschirm aus.
04 * Eingabe: Geschlecht
05 * Ausgabe: "weiblich" oder "maennlich"
06 ***********************************************/
07 #include <stdio.h>
08
09 int main()
10 {
11 char Geschlecht;
12
13 printf("Geben Sie bitte Ihr Geschlecht ein.\n");
14 printf("(w: weiblich, m: maennlich): ");
15 scanf("%c", &Geschlecht);
16 switch (Geschlecht)
17 {
18 case 'w':
19 case 'W':
20 printf("weiblich\n");
21 break;
22 case 'm':
23 case 'M':
24 printf("maennlich\n");
25 break;
26 default:
27 printf("keine Angabe\n");
28 }
29
30 return 0;
31 }
Neben der break-Anweisung kann die switch-Anweisung
auch mit den Anweisungen continue (siehe Abschnitt break und continue
in diesem Kapitel), goto und return beendet
werden.
Die Reihenfolge, in der der switch-Ausdruck mit den
case-Ausdrücken verglichen wird, ist nicht definiert. Auch die
Umsetzung der Vergleiche in die Maschinensprache hängt von der Anzahl und den Werten
der case-Ausdrücke ab. D.h., die switch-Anweisung
kann nicht als Folge von if-Anweisungen angesehen werden!
Die Anzahl der case-Ausdrücke, die in einer
switch-Anweisung verwendet werden dürfen, ist begrenzt. In C89
dürfen maximal 257, in C99 maximal 1023 case-Ausdrücke verwendet
werden.
Obwohl für den Datentypen des Ausdrucks alle Typen von ganzen Zahlen zugelassen sind, gibt
es einige ältere Compiler, die die Datentypen long und
unsigned long für den Ausdruck nicht zulassen.
6.5. Schleifen: while-Schleifen
Soll ein Programmteil mehrmals wiederholt werden, wird eine sogenannte
Schleife verwendet. In C gibt es drei verschiedene Schleifen:
while-, do-while- und
for-Schleifen. Die beiden letzten lassen sich auch durch die
while-Schleife darstellen.
Die while-Schleife hat folgende Syntax:
while (Bedingung)
Anweisung;
Ähnlich wie bei der if-Anweisung sollte die
Anweisung eingerückt werden, um schneller zu erkennen, an
welcher Stelle die while-Schleife zu Ende ist. Sollen mehrere
Anweisungen in einer Schleife wiederholt werden, werden diese (wie bei der
if-Anweisung) in einen Block geschrieben. Dies sieht dann wie folgt
aus:
while (Bedingung)
{
Anweisung1;
Anweisung2;
Anweisung3;
}
Dabei wird die Anweisung bzw. der Anweisungsblock so lange
wiederholt ausgeführt, bis die Bedingung nicht mehr wahr ist. Ist die
Bedingung von vornherein nicht erfüllt, wird die
Anweisung bzw. der Anweisungsblock in der
while-Schleife überhaupt nicht ausgeführt. Anders herum: Wird
die Bedingung niemals falsch, wird die Schleife auch niemals beendet. Dies wird eine
Endlosschleife genannt.
Beispiel:
kap06_06.c
01 /*******************************************
02 * Dieses Programm berechnet die Fakultaet
03 * einer eingegebenen Zahl und gibt das
04 * Ergebnis auf dem Bildschirm aus.
05 * Eingabe: Zahl
06 * Ausgabe: Fakult
07 *******************************************/
08 #include <stdio.h>
09
10 int main()
11 {
12 unsigned int Zahl, Zaehler = 1;
13 unsigned long Fakult = 1;
14
15 printf("Dieses Programm berechnet die ");
16 printf("Fakultaet einer ganzen Zahl.\n");
17 printf("Geben Sie bitte eine ganze Zahl ein: ");
18 scanf("%d", &Zahl);
19 while (Zaehler <= Zahl)
20 {
21 Fakult = Fakult * Zaehler;
22 Zaehler++;
23 }
24 printf("%u! = %lu\n", Zahl, Fakult);
25
26 return 0;
27 }
Mit Hilfe der Kurzform-Operatoren und der Inkrementierung von Variablen kann die
while-Schleife (Zeile 19 bis 23) drastisch verkürzt werden:
while (Zaehler <= Zahl)
Fakult *= Zaehler++;
Genauso wie if-Anweisungen lassen sich
while-Schleifen schachteln. Auch hierbei hilft das Einrücken der
Anweisungen innerhalb der Schleife, um den Überblick über die jeweiligen
Schleifenenden zu haben. Im folgenden Beispiel wird um die Schleife der
Fakultätsberechnung eine weitere Schleife herumgelegt.
Beispiel:
kap06_07.c
01 /*******************************************
02 * Dieses Programm berechnet die Fakultaet
03 * einer eingegebenen Zahl und gibt das
04 * Ergebnis auf dem Bildschirm aus.
05 * Eingabe: Zahl
06 * Ausgabe: Fakult
07 *******************************************/
08 #include <stdio.h>
09
10 int main()
11 {
12 unsigned int Zahl, Zaehler;
13 unsigned long Fakult;
14 char c = 'j';
15
16 printf("Dieses Programm berechnet die ");
17 printf("Fakultaet einer ganzen Zahl.\n");
18 while (c == 'j' || c == 'J')
19 {
20 printf("Geben Sie bitte eine ganze Zahl ein: ");
21 scanf("%d", &Zahl);
22
23 Zaehler = 1;
24 Fakult = 1;
25 while (Zaehler <= Zahl)
26 Fakult *= Zaehler++;
27 printf("%u! = %lu\n", Zahl, Fakult);
28 printf("Moechten Sie eine weitere Zahl ");
29 printf("berechnen? (j/n) ");
30 c = 0;
31 while (c != 'j' && c != 'J' && c != 'n' && c != 'N')
32 scanf("%c", &c);
33 }
34
35 return 0;
36 }
Im Gegensatz zum vorigen Beispielprogramm ist zu beachten, dass es jetzt nicht mehr
ausreicht, die Variablen Zaehler und Fakult
einmalig mit 1 zu initialisieren. Da die Berechnung mehrmals
durchgeführt werden kann, ist es wichtig, diese beiden Variablen direkt vor
der Berechnung auf den Startwert zu setzen.
Bei der äußeren while-Schleife ist es von Nachteil,
dass die Variable c zuvor mit dem Zeichen 'j'
initialisiert sein muss. Dies ist bei der do-while-Schleife
anders.
6.6. Schleifen: do-while-Schleifen
Bei der do-while-Schleife ist die Abfrage der Bedingung am Ende.
Dadurch wird die Anweisung bzw. der Anweisungsblock innerhalb der Schleife auf jeden
Fall mindestens einmal ausgeführt (Motto: Erst zuschlagen, dann fragen), während bei
der while-Schleife die Anweisung bzw. der Anweisungsblock bei
falscher Bedingung überhaupt nicht ausgeführt wird. Die Syntax für
die do-while-Schleife sieht folgendermaßen aus:
do
Anweisung;
while (Bedingung);
Entsprechend die Syntax mit einem Anweisungsblock:
do
{
Anweisung1;
Anweisung2;
Anweisung3;
} while (Bedingung);
Wichtig: Im Gegensatz zur while-Schleife wird hier
hinter while (Bedingung); ein Semikolon gesetzt!
Im folgenden Beispiel werden zwei der drei while-Schleifen vom vorigen
Beispiel durch do-while-Schleifen ersetzt. Dadurch fällt die
Initialisierung der Variablen in der Bedingung weg.
Beispiel:
kap06_08.c
01 /*******************************************
02 * Dieses Programm berechnet die Fakultaet
03 * einer eingegebenen Zahl und gibt das
04 * Ergebnis auf dem Bildschirm aus.
05 * Eingabe: Zahl
06 * Ausgabe: Fakult
07 *******************************************/
08 #include <stdio.h>
09
10 int main()
11 {
12 unsigned int Zahl, Zaehler;
13 unsigned long Fakult;
14 char c;
15
16 printf("Dieses Programm berechnet die ");
17 printf("Fakultaet einer ganzen Zahl.\n");
18 do
19 {
20 printf("Geben Sie bitte eine ganze Zahl ein: ");
21 scanf("%d", &Zahl);
22
23 Zaehler = 1;
24 Fakult = 1;
25 while (Zaehler <= Zahl)
26 Fakult *= Zaehler++;
27 printf("%u! = %lu\n", Zahl, Fakult);
28 printf("Moechten Sie eine weitere Zahl ");
29 printf("berechnen? (j/n) ");
30 do
31 scanf("%c", &c);
32 while (c != 'j' && c != 'J' && c != 'n' && c != 'N');
33 } while (c == 'j' || c == 'J');
34
35 return 0;
36 }
6.7: Schleifen: for-Schleifen
Die dritte Schleife ist die for-Schleife und ist eine sogenannte
Zählschleife. Der Name kommt daher, dass ursprünglich
bei dieser Schleifenform mit Hilfe einer Zahlenvariablen mitgezählt wurde, wie oft
die Schleife ausgeführt werden soll. Entsprechend wird in der Bedingung die
Zahlenvariable abgefragt, ob die gewünschte Anzahl von Schleifendurchläufen
bereits erreicht ist. In C/C++ sieht die for-Schleife etwas anders aus
als in anderen Programmiersprachen. Dadurch ist es möglich, auch
for-Schleifen ohne Zähler zu konstruieren.
Die Syntax sieht folgendermaßen aus:
for ([Variablen-Initialisierung];[Bedingung];[Veränderung])
Anweisung;
bzw. mit mehreren Anweisungen in einem Anweisungsblock:
for ([Variablen-Initialisierung];[Bedingung]; [Veränderung])
{
Anweisung1;
Anweisung2;
Anweisung3;
}
Das folgende Beispiel gibt alle Buchstaben von 'A' bis 'Z' auf dem Bildschirm aus. In
diesem Fall ist die Zählvariable die char-Variable
c.
Beispiel:
kap06_09.c
01 /********************************************
02 * Dieses Programm gibt alle Buchstaben von
03 * 'A' bis 'Z' auf dem Bildschirm aus.
04 ********************************************/
05 #include <stdio.h>
06
07 int main()
08 {
09 char c;
10
11 printf("Dieses Programm gibt alle Buchstaben ");
12 printf("von 'A' bis 'Z' aus.\n");
13 for (c = 'A'; c <= 'Z'; c++)
14 printf("%c ", c);
15 printf("\n");
16
17 return 0;
18 }
In der Syntax sind die Variablen-Initialisierung, die Bedingung und die
Veränderung jeweils in eckigen Klammern angegeben, d.h. sie sind optional. So
kann zum Beispiel die Variablen-Initialisierung entfallen, wenn die Variablen
bereits vorher initialisiert wurden. Die Veränderung des Zählers kann
entfallen, z.B. wenn er innerhalb der Schleife verändert wird. Auch die Bedingung kann
weggelassen werden, allerdings ist dann die Schleife eine Endlosschleife! Im folgenden
Beispiel werden Variablen-Initialisierung und Veränderung weggelassen
(oder besser gesagt: an andere Stellen umgesetzt). Trotzdem müssen die Semikolons
gesetzt werden.
Beispiel:
kap06_10.c
01 /********************************************
02 * Dieses Programm gibt alle Buchstaben von
03 * 'A' bis 'Z' auf dem Bildschirm aus.
04 ********************************************/
05 #include <stdio.h>
06
07 int main()
08 {
09 char c = 'A'; /* Variablen-Initialisierung */
10
11 printf("Dieses Programm gibt alle Buchstaben ");
12 printf("von 'A' bis 'Z' aus.\n");
13 for ( ; c <= 'Z'; )
14 printf("%c ", c++);
15 printf("\n");
16
17 return 0;
18 }
Für Variablen-Initialisierung, Bedingung und Veränderung
können aber auch mehrere Einträge gemacht werden. Diese müssen mit
Kommata voneinander getrennt werden (siehe Abschnitt Sequenzen am Anfang dieses Kapitels).
Werden mehrere Befehle oder Abfragen als Bedingung angegeben, muss darauf geachtet werden,
dass nur das Ergebnis des letzten Befehls bzw. der letzten Abfrage für die Bedingung
verwendet wird. Im folgenden Beispiel wird eine Berechnung innerhalb einer
for-Schleife in mehreren Schritten so weit verkürzt, dass
keine Anweisung innerhalb der Schleife mehr übrigbleibt. In diesem Fall muss ein
Semikolon (sozusagen eine Leeranweisung) als Anweisung für die
for-Schleife gesetzt werden.
Beispiel:
kap06_11.c
01 #include <stdio.h>
02
03 int main()
04 {
05 unsigned long a, b = 1, c = 1;
06 /* a wird in der for-Schleife initialisiert */
07
08 printf(" a | b | c\n");
09 printf("-------------------------------------\n");
10 for (a = 1; a < 10; a = a + 1)
11 {
12 b = b * c;
13 c = c + a;
14 printf("%10lu | %10lu | %10lu\n", a, b, c);
15 c = c + 1;
16 }
17 printf("-------------------------------------\n");
18
19 return 0;
20 }
Im ersten Schritt beim Verkürzen der for-Schleife werden die
Kurzform-Operatoren eingesetzt. Ferner werden auch die Startwerte der Variablen
b und c in der for-Schleife
gesetzt.
kap06_12.c
01 #include <stdio.h>
02
03 int main()
04 {
05 unsigned long a, b, c;
06
07 printf(" a | b | c\n");
08 printf("-------------------------------------\n");
09 for (a = 1, b = 1, c = 1; a < 10; a++)
10 {
11 b *= c;
12 c += a;
13 printf("%10lu | %10lu | %10lu\n", a, b, c);
14 c++;
15 }
16 printf("-------------------------------------\n");
17
18 return 0;
19 }
Im zweiten Schritt werden die Initialisierungen zu einer zusammengefasst.
Außerdem wird das c++ zu den Veränderungen
verschoben.
kap06_13.c
01 #include <stdio.h>
02
03 int main()
04 {
05 unsigned long a, b, c;
06
07 printf(" a | b | c\n");
08 printf("-------------------------------------\n");
09 for (a = b = c = 1; a < 10; a++, c++)
10 {
11 b *= c;
12 c += a;
13 printf("%10lu | %10lu | %10lu\n", a, b, c);
14 }
15 printf("-------------------------------------\n");
16
17 return 0;
18 }
Im letzten Schritt werden die drei Anweisungen in die Bedingung verschoben. Wichtig
ist, dass die ursprüngliche Bedingung die letzte ist. Nun werden aber vor der
Abfrage der Bedingung die drei Anweisungen ausgeführt. Der Ablauf ist damit
ähnlich wie bei der do-while-Schleife. Deshalb muss die
Anzahl der Schleifendurchgänge um eins verringert werden.
kap06_14.c
01 #include <stdio.h>
02
03 int main()
04 {
05 unsigned long a, b, c;
06
07 printf(" a | b | c\n");
08 printf("-------------------------------------\n");
09 for (a = b = c = 1; b *= c, c += a, printf("%10lu | %10lu | "
10 "%10lu\n", a, b, c), a < 9; a++, c++)
11 ;
12 printf("-------------------------------------\n");
13
14 return 0;
15 }
Natürlich ist diese komprimierte Schreibweise nicht sehr leserlich, sehr
fehleranfällig und daher auch nicht zu empfehlen!
Genau wie bei den beiden anderen Schleifenformen können auch
for-Schleifen beliebig verschachtelt werden. Zur besseren
Übersicht sollten auch hier die Anweisungen innerhalb der Schleife eingerückt
werden.
6.8: break und continue
Mit den Befehlen break und continue gibt es noch
zwei Befehle, mit denen der Ablauf innerhalb von Schleifen beeinflusst werden kann.
Der break-Befehl wurde bereits in der
switch-Anweisung verwendet, um aus dieser herauszuspringen. Genauso ist
es auch bei den Schleifen: Mit Hilfe des break-Befehls wird die
Schleife unabhängig von der Bedingung beendet und mit dem nächsten Befehl
nach der Schleife fortgefahren. Dies gilt für alle drei Schleifenformen. Als Beispiel
dient noch einmal das Programm zur Berechnung der Fakultät.
Beispiel:
kap06_15.c
01 /*******************************************
02 * Dieses Programm berechnet die Fakultaet
03 * einer eingegebenen Zahl und gibt das
04 * Ergebnis auf dem Bildschirm aus.
05 * Eingabe: Zahl
06 * Ausgabe: Fakult
07 *******************************************/
08 #include <stdio.h>
09
10 int main()
11 {
12 unsigned int Zahl, Zaehler;
13 unsigned long Fakult;
14 char c;
15
16 printf("Dieses Programm berechnet die ");
17 printf("Fakultaet einer ganzen Zahl.\n");
18 while (1) /* 1 => Wahr => Endlosschleife! */
19 {
20 printf("Geben Sie bitte eine ganze Zahl ein: ");
21 scanf("%d", &Zahl);
22
23 Zaehler = 1;
24 Fakult = 1;
25 while (Zaehler <= Zahl)
26 Fakult *= Zaehler++;
27 printf("%u! = %lu\n", Zahl, Fakult);
28 printf("Moechten Sie eine weitere Zahl ");
29 printf("berechnen? (j/n) ");
30 do
31 scanf("%c", &c);
32 while (c != 'j' && c != 'J' && c != 'n' && c != 'N');
33 if (c == 'n' || c == 'N')
34 break; /* hier wird die Schleife verlassen */
35 }
36
37 return 0;
38 }
Der continue-Befehl ist mehr oder weniger das Gegenteil des
break-Befehls: Mit ihm wird zum Ende des Schleifenkörpers gesprungen.
Bei while- und do-while-Schleifen wird nach
continue die Bedingung abgefragt, bei
for-Schleifen wird nach continue erst die
Veränderung aufgerufen und dann die Bedingung abgefragt.
Als Beispiel wird das Programm zur Berechnung der Fakultät erweitert: Nach der
Benutzereingabe der ganzen Zahl wird diese geprüft, ob sie größer oder
gleich eins ist. Wenn nicht, wird mit continue die Schleife neu
gestartet.
Beispiel:
kap06_16.c
01 /*******************************************
02 * Dieses Programm berechnet die Fakultaet
03 * einer eingegebenen Zahl und gibt das
04 * Ergebnis auf dem Bildschirm aus.
05 * Eingabe: Zahl
06 * Ausgabe: Fakult
07 *******************************************/
08 #include <stdio.h>
09
10 int main()
11 {
12 int Zahl, Zaehler;
13 unsigned long Fakult;
14 char c;
15
16 printf("Dieses Programm berechnet die ");
17 printf("Fakultaet einer ganzen Zahl.\n");
18 while (1) /* 1 => Wahr => Endlosschleife! */
19 {
20 printf("Geben Sie bitte eine ganze Zahl ein: ");
21 scanf("%d", &Zahl);
22 if (Zahl < 1)
23 continue; /* Schleife von vorne beginnen */
24 Zaehler = 1;
25 Fakult = 1;
26 while (Zaehler <= Zahl)
27 Fakult *= Zaehler++;
28 printf("%u! = %lu\n", Zahl, Fakult);
29 printf("Moechten Sie eine weitere Zahl ");
30 printf("berechnen? (j/n) ");
31 do
32 scanf("%c", &c);
33 while (c != 'j' && c != 'J' && c != 'n' && c != 'N');
34 if (c == 'n' || c == 'N')
35 break; /* hier wird die Schleife verlassen */
36 }
37
38 return 0;
39 }
6.9: goto
So wie im guten alten Basic gibt es auch in C/C++ den goto-Befehl. Im
Normalfall kommt man ohne diesen Befehl aus, aber es gibt ja immer die berühmten
Ausnahmen. Generell werden Programme mit goto-Befehlen sehr schnell
unübersichtlich!
Die Syntax lautet:
goto Labelname;
Dabei ist Labelname ein beliebiger Name, der irgendwo im Programm (zumindest in
der gleichen Funktion!) definiert sein muss. Ein Label wird ganz einfach definiert.
Dazu wird der Labelname gefolgt von einem Doppelpunkt vor den Befehl bzw. vor die
Anweisung geschrieben, zu der der goto-Befehl springen soll. Damit
diese Labels später schneller wiedergefunden werden, sollten sie direkt an den Anfang
der Zeile geschrieben werden. Der Befehl dahinter bleibt wie bisher
eingerückt.
Als Beispiel wird das vorige Programm genommen. Hier wird der
continue-Befehl durch den goto-Befehl ersetzt. Das
Label wird vor der ersten Anweisung in der while-Schleife
geschrieben.
Beispiel:
kap06_17.c
01 /*******************************************
02 * Dieses Programm berechnet die Fakultaet
03 * einer eingegebenen Zahl und gibt das
04 * Ergebnis auf dem Bildschirm aus.
05 * Eingabe: Zahl
06 * Ausgabe: Fakult
07 *******************************************/
08 #include <stdio.h>
09
10 int main()
11 {
12 int Zahl, Zaehler;
13 unsigned long Fakult;
14 char c;
15
16 printf("Dieses Programm berechnet die ");
17 printf("Fakultaet einer ganzen Zahl.\n");
18 while (1) /* 1 => Wahr => Endlosschleife! */
19 {
20 neu: printf("Geben Sie bitte eine ganze Zahl ein: ");
21 scanf("%d", &Zahl);
22 if (Zahl < 1)
23 goto neu; /* Schleife von vorne beginnen */
24 Zaehler = 1;
25 Fakult = 1;
26 while (Zaehler <= Zahl)
27 Fakult *= Zaehler++;
28 printf("%u! = %lu\n", Zahl, Fakult);
29 printf("Moechten Sie eine weitere Zahl ");
30 printf("berechnen? (j/n) ");
31 do
32 scanf("%c", &c);
33 while (c != 'j' && c != 'J' && c != 'n' && c != 'N');
34 if (c == 'n' || c == 'N')
35 break; /* hier wird die Schleife verlassen */
36 }
37
38 return 0;
39 }
Ein sehr gefährliches Feature der goto-Anweisung ist die
Möglichkeit, mitten in Blöcke springen zu können. Dabei wird auch die
Initialisierung von Variablen, die am Blockanfang definiert werden, übersprungen
(zumindest von den meisten Compilern). Das Ergebnis ist, dass der Inhalt der Variablen
nicht vorhersehbar ist.
Beispiel:
kap06_18.c
01 #include <stdio.h>
02
03 int main()
04 {
05 goto Label;
06
07 {
08 int Zahl = 10;
09
10 Label:
11 printf("Zahl = %i\n", Zahl); // irgendeine Zahl wird ausgegeben!
12 }
13
14 return 0;
15 }
Voriges Kapitel: 5. Einfache Ein- und Ausgabe in C
Nächstes Kapitel: 7. Strukturierte Datentypen