vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbacknächstes Kapitel


Woche 1

Tag 5

Grundlagen der Programmsteuerung

Am Tag 3, »Anweisungen, Ausdrücke und Operatoren«, haben Sie die if-Anweisung kennen gelernt, mit der Sie zum ersten Mal auf den Programmablauf Einfluss nehmen konnten. Häufig stehen Sie jedoch vor dem Problem, dass die Entscheidung zwischen wahr und unwahr allein nicht ausreicht. Heute lernen Sie daher drei weitere Wege kennen, wie Sie den Programmfluss beeinflussen können. Heute lernen Sie:

Hier, in diesem Kapitel werden wir die Themen noch nicht erschöpfend behandeln. Es soll Ihnen nur ausreichend Wissen vermittelt werden, so dass Sie mit dem Aufsetzen richtiger Programme beginnen können. Detailwissen zu diesen Themen finden Sie in Kapitel 12, »Fortgeschrittene Programmsteuerung«.

Arrays: Grundlagen

Bevor wir mit der for-Anweisung beginnen, sollten wir einen kleinen Abstecher in die Grundlagen der Arrays machen. (Siehe Tag 7, »Numerische Arrays«, für eine komplette Behandlung der Arrays.) for-Anweisung und Arrays sind in C eng miteinander verbunden. Deshalb ist es schwierig, eines ohne das andere zu erklären. Um Ihnen die Arrays in den Beispielen zu den for-Anweisungen verständlich zu machen, möchte ich erst einmal eine kurze Einführung zu den Arrays geben.

Ein Array ist eine indizierte Zusammenstellung von Datenspeicherpositionen, die den gleichen Namen tragen und sich voneinander durch einen Index unterscheiden - eine Zahl in eckigen Klammern, die auf den Variablennamen folgt. (Wenn Sie weiterlesen, wird dies sicher verständlicher.) Wie andere C-Variablen auch müssen Arrays deklariert werden. Eine Array-Deklaration umfasst den Datentyp und die Größe des Arrays (die Anzahl der Elemente im Array). So deklariert die folgende Anweisung zum Beispiel ein Array namens daten, das vom Typ int ist und 1000 int-Elemente enthält.

int daten[1000];

Um auf die einzelnen Elemente Bezug zu nehmen, verwenden Sie einen Index wie daten[0] bis daten[999]. Das erste Element lautet daten[0] und nicht daten[1]. In anderen Sprachen, wie zum Beispiel BASIC, erhält das erste Element im Array die Zahl 1. Dies gilt aber nicht für C.

Jedes Element dieses Arrays entspricht einer normalen Integer-Variablen und kann auch genauso verwendet werden. Der Index eines Arrays kann auch eine andere C-Variable sein, wie folgendes Beispiel zeigt:

int daten[1000];
int zaehlung;
zaehlung = 100;
daten[zaehlung] = 12; /* Identisch mit daten[100] = 12 */

Diese Einführung in die Welt der Arrays war sehr kurz, sollte jedoch ausreichen, um Ihnen zu zeigen, wie Arrays in den nun folgenden Programmbeispielen verwendet werden. Und sollten Sie momentan noch nicht alles im Zusammenhang mit den Arrays verstehen, dann machen Sie sich nur keine Gedanken. Am Tag 7 werden wir Arrays im Detail besprechen.

Was Sie tun sollten

Deklarieren Sie Ihre Arrays nicht mit unnötig großen Indizes. Sie verschwenden nur Speicher.

Und merken Sie sich, dass in C Arrays mit dem Index 0 und nicht 1 beginnen.

Die Programmausführung steuern

Standardmäßig wird ein C-Programm von oben nach unten ausgeführt. Die Ausführung beginnt mit der main()-Funktion und schreitet Anweisung für Anweisung weiter, bis sie das Ende von main() erreicht hat. In richtigen C-Programmen wird diese Abfolge jedoch selten eingehalten. Die Programmiersprache C bietet eine Reihe von Anweisungen zur Programmsteuerung, mit denen Sie die Programmausführung beeinflussen können. Den Bedingungsoperator und die if-Anweisung haben Sie bereits kennen gelernt, so dass wir jetzt zu drei weiteren nützlichen Steueranweisungen kommen können:

for-Anweisungen

Die for-Anweisung ist ein Programmkonstrukt, das einen Block von einer oder mehreren Anweisungen mehrmals hintereinander ausführt. Manchmal wird sie auch for-Schleife genannt, da die Programmausführung diese Anweisung normalerweise mehr als einmal durchläuft. In früheren Beispielen in diesem Buch sind Ihnen schon einige for-Anweisungen begegnet. Jetzt möchte ich Ihnen zeigen, was sich dahinter verbirgt.

Ein for-Anweisung hat die folgende Struktur:

for ( Initial; Bedingung; Inkrement )
Anweisung;

Initial, Bedingung und Inkrement sind allesamt C-Ausdrücke. Anweisung ist eine einfache oder komplexe C-Anweisung. Wenn die Programmausführung auf eine for- Anweisung stößt, passiert Folgendes:

  1. Der Ausdruck Initial wird ausgewertet. Initial ist in der Regel eine Zuweisung, die eine Variable auf einen bestimmten Wert setzt.
  2. Der Ausdruck Bedingung wird ausgewertet. Bedingung ist normalerweise ein relationaler Ausdruck (Vergleich).
  3. Wenn Bedingung zu unwahr (das heißt Null) ausgewertet wird, endet die for- Anweisung und die Ausführung fährt mit der ersten Anweisung nach Anweisung fort.
  4. Wenn Bedingung zu wahr (das heißt ungleich Null) ausgewertet wird, wird (werden) die C-Anweisung(en) in Anweisung ausgeführt.
  5. Der Ausdruck Inkrement wird ausgewertet und die Ausführung kehrt zurück zu Schritt 2.

Abbildung 5.1 zeigt den Ablauf einer for-Anweisung. Beachten Sie, dass Anweisung niemals ausgeführt wird, wenn Bedingung bereits bei der ersten Auswertung unwahr ergibt.

Listing 5.1 enthält ein einfaches Beispiel für eine for-Anweisung, die die Zahlen von 1 bis 20 ausgeben soll. Sie werden sicherlich feststellen, dass der resultierende Code wesentlich kompakter und kürzer ist, als für jeden der 20 Werte eine eigene printf()- Anweisung zu verwenden.

Listing 5.1: Eine einfache for-Anweisung.

1:   /* Beispiel für eine einfache for-Anweisung */
2:
3: #include <stdio.h>
4:
5: int count;
6:
7: int main(void)
8: {
9: /* Gibt die Zahlen von 1 bis 20 aus */
10:
11: for (count = 1; count <= 20; count++)
12: printf("%d\n", count);
13:
14: return 0;
15: }

Abbildung 5.1:  Eine schematische Darstellung einer for-Anweisung.

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

Abbildung 5.2 veranschaulicht den Ablauf der for-Schleife aus Listing 5.1.

Abbildung 5.2:  Wie die for-Schleife aus Listing 5.1 funktioniert.

Zeile 3 bindet die Header-Datei für die Standardein-/-ausgabe ein. Zeile 5 deklariert eine Variable vom Typ int namens count, die in der for-Schleife verwendet wird. Die Zeilen 11 und 12 enthalten die for-Schleife. In der for-Schleife wird die erste Anweisung zuerst ausgeführt. In diesem Listing lautet die erste Anweisung count = 1, das heißt count wird initialisiert und kann dann vom Rest der Schleife verwendet werden. Der zweite Schritt der for-Anweisung besteht darin, die Bedingung count <= 20 auszuwerten. Da count gerade mit 1 initialisiert wurde, wissen Sie, dass dieser Wert kleiner als 20 ist, so dass die Anweisung in dem for-Befehl, der printf()-Aufruf, ausgeführt wird. Nach Ausführung des printf()-Aufrufs wird der Inkrementierungs- Ausdruck count++ ausgewertet. Dadurch wird count um 1 erhöht, so dass die Variable nun den Wert 2 erhält. Jetzt beginnt das Programm in der Schleife von vorn und prüft die Bedingung erneut. Wenn sie immer noch wahr ist, wird printf() wieder ausgeführt, count erneut inkrementiert (erhöht auf 3) und die Bedingung erneut geprüft. Diese Schleife wird so lange fortgeführt, bis die Bedingung nicht mehr zutrifft, das heißt falsch ist, woraufhin das Programm die Schleife verlässt und mit der nächsten Zeile (Zeile 14) fortfährt, die 0 zurückliefert, bevor sie das Programm beendet.

Die for-Anweisung wird häufig, wie in dem obigen Beispiel, dafür verwendet, »hochzuzählen«, das heißt, ein Zähler wird um einen Wert inkrementiert. Sie können damit aber genauso gut »herunterzählen«, das heißt, die Zählervariable dekrementieren (im Gegensatz zu inkrementieren).

for (count = 100; count > 0; count-- )

Der Wert, um den Sie »hoch- bzw. herunterzählen« muss nicht 1 sein, wie folgendes Beispiel zeigt:

for (count = 0; count < 1000; count += 5)

Die for-Anweisung ist ziemlich flexibel. Sie können beispielsweise auf die Initialisierung verzichten, wenn die Variable bereits zuvor in Ihrem Programm initialisiert wurde. (Sie müssen jedoch trotzdem, wie hier gezeigt, das Semikolon als Trennzeichen verwenden.)

count = 1;
for ( ; count < 1000; count++)

Die Initialisierung muss keine Initialisierung im eigentlichen Sinn sein. Es kann ein beliebiger C-Ausdruck sein. Was auch immer es ist, es wird ausgeführt, sobald die for- Anweisung das erste Mal erreicht wird. So wird im folgenden Beispiel die Meldung »Array wird sortiert...« ausgegeben:

count = 1;
for (printf("Array wird sortiert...") ; count < 1000; count++)
/* Sortieranweisungen */

Sie können auch die Inkrementierung fortlassen und die Aktualisierung im Rumpf der for-Anweisung vornehmen. Vergessen Sie aber nicht, das Semikolon zu setzen. Um die Zahlen von 0 bis 99 auszugeben, könnten Sie zum Beispiel schreiben:

for (count = 0; count < 100; )
printf("%d", count++);

Der Test, mit dem die Schleife endet, kann ein beliebiger C-Ausdruck sein. Solange er als wahr (ungleich Null) ausgewertet wird, wird die for-Anweisung ausgewertet. Sie können mit den logischen Operatoren von C komplexe Testbedingungen konstruieren. Die folgende for-Anweisung gibt die Elemente eines Arrays namens array[] aus und stoppt erst, wenn alle Elemente ausgegeben worden sind oder ein Element mit dem Wert von 0 vorliegt:

for (count = 0; count < 1000 && array[count] != 0; count++)
printf("%d", array[count]);

Sie könnten diese for-Schleife sogar noch einfacher gestalten, indem Sie sie wie folgt formulieren. (Wenn Sie die Änderung an der Testbedingung nicht verstehen, schlagen Sie noch einmal unter Tag 3 nach.)

for (count = 0; count < 1000 && array[count]; )
printf("%d", array[count++]);

Sie können auf die for-Anweisung eine Leeranweisung folgen lassen, so dass die ganze Arbeit in der for-Anweisung ausgeführt wird. Zur Erinnerung, eine Leeranweisung ist ein Semikolon allein in einer Zeile. Um zum Beispiel alle Elemente eines Arrays mit 1000 Elementen mit dem Wert 50 zu initialisieren, könnten Sie schreiben:

for (count = 0; count < 1000; array[count++] = 50)
;

In dieser for-Anweisung wird der Wert 50 jedem Element des Arrays durch den Inkrementierungsteil der Anweisung zugewiesen.

Am Tag 3 wurde darauf hingewiesen, dass der Komma-Operator in C am häufigsten in for-Anweisungen verwendet wird. Sie können einen Ausdruck erzeugen, indem Sie zwei Unterausdrücke mit dem Komma-Operator trennen. Die zwei Unterausdrücke werden ausgewertet (von links nach rechts), und der ganze Ausdruck wird dann zu dem Wert des rechten Unterausdrucks ausgewertet. Mit Hilfe des Komma-Operators können Sie jeden Teil einer for-Anweisung mehrere Aufgaben ausführen lassen.

Angenommen Sie haben zwei Arrays, a[] und b[], mit je 1000 Elementen und Sie wollen den Inhalt von a[] in umgekehrter Reihenfolge in b[] kopieren, so dass nach dem Kopiervorgang b[0] = a[999], b[1] = a[998] ist und so weiter. Wie dies geht, zeigt die folgende for-Anweisung:

for (i = 0, j = 999; i < 1000; i++, j-- )
b[j] = a[i];

Der Komma-Operator dient also dazu, zwei Variablen, i und j, zu initialisieren und bei jeder Schleifeniteration zu inkrementieren bzw. zu dekrementieren.

Die for-Anweisung

for (Initial; Bedingung; Inkrement)
Anweisung(en);

Initial ist ein beliebiger gültiger C-Ausdruck. In der Regel ist es eine Zuweisung, die eine Variable auf einen bestimmten Wert setzt.

Bedingung ist ein beliebiger gültiger C-Ausdruck, in der Regel ein relationaler Ausdruck. Wenn Bedingung als unwahr (Null) ausgewertet wird, endet die for- Anweisung und das Programm wird mit der ersten Anweisung nach Anweisung(en); fortgesetzt. Im anderen Fall werden die Anweisungen in Anweisung(en) ausgeführt.

Inkrement ist ein beliebiger gültiger C-Ausdruck. In der Regel ist es ein Ausdruck, der eine durch den ersten Ausdruck initialisierte Variable inkrementiert.

Bei Anweisung(en) handelt es sich um die C-Anweisungen, die ausgeführt werden, solange die Bedingung wahr ist.

Die for-Anweisung gehört zu den Schleifen. Sie kann einen Initialisierungs-, einen Bedingungs- und einen Inkrementteil in sich einschließen. Die for-Anweisung führt zuerst die Initialisierungsanweisung aus. Danach wird die Bedingung geprüft. Wenn die Bedingung wahr ist, werden die mit der Bedingung verknüpften Anweisungen ausgeführt. Anschließend wird der Inkrementierungsausdruck ausgewertet. Zum Schluss prüft die for-Anweisung die Bedingung erneut und durchläuft die Schleife so lange, bis die Bedingung falsch ist.

Beispiel 1

/* Gibt beim Zählen von 0 bis 9 den Wert von x aus */
int x;
for (x = 0; x <10; x++)
printf( "\nDer Wert von x ist %d", x );

Beispiel 2

/* Liest so lange Werte ein, bis die Zahl 99 eingegeben wird */
int nbr = 0;
for ( ; nbr != 99; )
scanf( "%d", &nbr );

Beispiel 3

/* Erlaubt die Benutzereingabe von bis zu 10 Integer-Werten  */
/* Die Werte werden in einem Array namens wert gespeichert. */
/* Wenn 99 eingegeben wird, stoppt die Schleife. */
int wert[10];
int ctr, nbr=0;
for (ctr = 0; ctr < 10 && nbr != 99; ctr++)
{
puts("Geben Sie eine Zahl ein, mit 99 verlassen ");
scanf("%d", &nbr);
wert[ctr] = nbr;
}

Verschachtelte for-Anweisungen

Eine for-Anweisung kann innerhalb einer anderen for-Anweisung ausgeführt werden. Dies nennt man Verschachteln. (Am Tag 3 haben Sie bereits die Verschachtelung von if-Anweisungen gesehen). Durch das Verschachteln von for-Anweisungen lassen sich komplexe Programmierprobleme lösen. Listing 5.2 ist zwar kein komplexes Programm, aber es zeigt, wie zwei for-Anweisungen ineinander verschachtelt werden.

Listing 5.2: Verschachtelte for-Anweisungen.

1:   /* Beispiel für die Verschachtelung zweier for-Anweisungen */
2:
3: #include <stdio.h>
4:
5: void rechteck_zeichnen( int, int);
6:
7: int main(void)
8: {
9: rechteck_zeichnen( 8, 35 );
10:
11: return 0;
12: }
13:
14: void rechteck_zeichnen( int reihe, int spalte )
15: {
16: int spa;
17: for ( ; reihe > 0; reihe -- )
18: {
19: for (spa = spalte; spa > 0; spa -- )
20: printf("X");
21:
22: printf("\n");
23: }
24: }

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Die Hauptarbeit dieses Programms wird in Zeile 20 geleistet. Wenn Sie dieses Programm ausführen, werden 280 X in Form eines Rechtecks von 8 x 35 Zeichen auf dem Bildschirm ausgegeben. Das Programm weist zwar nur einen Befehl zur Ausgabe eines X auf, aber dieser befindet sich in zwei Schleifen.

In diesem Listing wird in Zeile 5 ein Funktionsprototyp für rechteck_zeichnen() deklariert. Diese Funktion übernimmt zwei Variablen, reihe und spalte, vom Typ int, die die Abmaße des auszugebenden Rechtecks enthalten. In Zeile 9 ruft main() rechteck_zeichnen() auf und übergibt für reihe den Wert 8 und für spalte den Wert 35.

Wenn Sie die Funktion rechteck_zeichnen() genau betrachten, werden Ihnen vielleicht einige Dinge auffallen, die nicht sofort verständlich sind. So kann man sich fragen, warum die lokale Variable spa deklariert oder in Zeile 22 die Funktion printf() verwendet wurde. Das alles wird etwas klarer, nachdem wir erst einmal die beiden for-Schleifen betrachtet haben.

In Zeile 17 beginnt die erste for-Schleife. Die Initialisierung wird übersprungen, da der Anfangswert für reihe der Funktion als Argument übergeben wurde. Ein Blick auf die Bedingung zeigt Ihnen, dass diese for-Schleife so lange ausgeführt wird, bis reihe gleich 0 ist. Bei der ersten Ausführung von Zeile 17 ist reihe gleich 8. Deshalb fährt das Programm mit Zeile 19 fort.

Zeile 19 enthält die zweite for-Anweisung. Dort wird der übergebene Parameter spalte in eine lokale Variable, spa, vom Typ int kopiert. Der Wert von spa ist anfänglich 35 (der Wert der via spalte übergeben wurde), und spalte behält seinen ursprünglichen Wert bei. Da spa größer als 0 ist, wird Zeile 20 ausgeführt und ein X ausgegeben. Daraufhin wird spa dekrementiert und die Schleife fortgeführt. Wenn spa gleich 0 ist, endet die for-Schleife und der Programmfluss springt in Zeile 22. Zeile 22 bewirkt, dass die Ausgabe auf dem Bildschirm in einer neuen Zeile fortgesetzt wird. (Mehr zur Ausgabe erfahren Sie am Tag 6, »Grundlagen der Ein- und Ausgabe«.) Mit dem Sprung in die neue Bildschirmzeile hat die Programmausführung das Ende der Anweisungen in der ersten for-Schleife erreicht und führt den Dekrementierungsausdruck aus, der 1 von reihe subtrahiert, so dass der Wert jetzt 7 beträgt. Damit geht die Programmsteuerung zurück in Zeile 19. Beachten Sie, dass der Wert von spa bei seiner letzten Verwendung 0 war. Wenn Sie anstelle von spa spalte verwendet hätten, würde diese Variable den Bedingungstest nicht bestehen, da sie zu keiner Zeit größer als 0 werden würde. Es würde nur die erste Zeile ausgegeben. (Sie können sich selbst davon überzeugen, indem Sie aus Zeile 19 den Initialisierungsteil löschen und die beiden spa-Variablen in spalte ändern.)

Was Sie tun sollten

Was nicht

Denken Sie daran, das Semikolon zu setzen, wenn Sie eine for-Anweisung mit einer Leeranweisung verwenden. Setzen Sie den Semikolon-Platzhalter in eine eigene Zeile oder fügen Sie ein Leerzeichen zwischen dem Semikolon und dem Ende der for-Anweisung ein. Deutlicher ist es, wenn das Semikolon in einer eigenen Zeile steht.

for (count = 0; count < 1000; array[count] = 50) ;
/* beachten Sie das Leerzeichen! */

Erliegen Sie nicht der Versuchung, in der for-Anweisung zu viele Arbeitsschritte unterzubringen. Sie können zwar das Komma-Trennzeichen verwenden, aber oft ist es übersichtlicher, die Funktionalität im Rumpf der Schleife stehen zu haben.

while-Anweisungen

Die while-Anweisung, auch while-Schleife genannt, führt einen Anweisungsblock so lange aus, wie eine spezifizierte Bedingung wahr ist. Die while-Anweisung hat folgende Form:

while (Bedingung)
Anweisung;

Bedingung ist ein beliebiger C-Ausdruck und Anweisung ist eine einfache oder komplexe C-Anweisung. Wenn die Programmausführung auf eine while-Anweisung stößt, passiert Folgendes:

  1. Der Ausdruck Bedingung wird ausgewertet.
  2. Wenn Bedingung als unwahr (das heißt als Null) ausgewertet wird, endet die while- Anweisung und die Ausführung fährt mit der ersten Anweisung nach Anweisung fort.
  3. Wenn Bedingung als wahr (das heißt ungleich Null) ausgewertet wird, wird (werden) die C-Anweisung(en) in Anweisung ausgeführt
  4. Die Ausführung kehrt zurück zu Schritt 1.

In Abbildung 5.3 sehen Sie den Ablauf der Programmausführung in einer while- Anweisung.

Abbildung 5.3:  Ablauf der Programmausführung in einer while-Anweisung.

Listing 5.3 enthält ein einfaches Programm, das eine while-Anweisung dazu verwendet, die Zahlen von 1 bis 20 auszugeben. (Die gleiche Aufgabe wurde auch von der for-Anweisung in Listing 5.1 ausgeführt.)

Listing 5.3: Eine einfache while-Anweisung.

1:   /* Beispiel einer einfachen while-Anweisung */
2:
3: #include <stdio.h>
4:
5: int count;
6:
7: int main(void)
8: {
9: /* Gibt die Zahlen von 1 bis 20 aus */
10:
11: count = 1;
12:
13: while (count <= 20)
14: {
15: printf("%d\n", count);
16: count++;
17: }
18: return 0;
19: }

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

Analysieren Sie Listing 5.3 und vergleichen Sie es mit Listing 5.1, in der das gleiche Problem mit Hilfe einer for-Anweisung gelöst wurde. Zeile 11 initialisiert count mit dem Wert 1. Da die while-Anweisung keinen Initialisierungsabschnitt enthält, müssen Sie daran denken, alle Variablen vor der while-Schleife zu initialisieren. Zeile 13 enthält die eigentliche while-Anweisung, einschließlich der gleichen Bedingung wie in Listing 5.1: count <= 20. Zeile 16 in der while-Schleife übernimmt die Inkrementierung von count. Was würde Ihrer Meinung nach passieren, wenn Sie die Zeile 16 in Ihrem Programm weggelassen hätten? Ihr Programm wüsste nicht, wann es aufhören sollte, da count immer 1 und damit immer kleiner als 20 wäre.

Vielleicht haben Sie inzwischen bemerkt, dass eine while-Anweisung im Wesentlichen einer for-Anweisung entspricht, bei der die Initialisierung und Inkrementierung fehlen. Demzufolge ist

for ( ; Bedingung ; )

äquivalent zu

while (Bedingung)

Aufgrund dieser Ähnlichkeit kann alles, was mit einer for-Anweisung möglich ist, auch mit einer while-Anweisung bewältigt werden. Wenn Sie jedoch while verwenden, müssen alle erforderlichen Initialisierungen zuvor in einer eigenen Anweisung vorgenommen werden und die Aktualisierung muss in Form einer Anweisung in der while-Schleife selbst erfolgen.

In allen Fällen, in denen Initialisierung und Aktualisierung unverzichtbar sind, bevorzugen die meisten erfahrenen C-Programmierer die for-Anweisung - hauptsächlich wegen der besseren Lesbarkeit des Quelltextes. Bei einer for- Anweisung stehen die Ausdrücke für Initialisierung, Test und Inkrementierung alle zusammen und sind damit leicht zu finden und zu ändern. Bei einer while-Anweisung stehen Initialisierung und Aktualisierung an getrennten Stellen und sind mitunter nicht leicht auszumachen.

Die while-Anweisung

while (Bedingung)
Anweisung(en);

Bedingung ist ein beliebiger gültiger C-Ausdruck, in der Regel ein relationaler Ausdruck. Wenn Bedingung als unwahr (Null) ausgewertet wird, endet die while- Anweisung und die Ausführung fährt mit der ersten Anweisung nach Anweisung(en); fort. Im anderen Fall wird die erste Anweisung in Anweisung(en) ausgeführt.

Bei Anweisung(en) handelt es sich um die C-Anweisungen, die ausgeführt werden, solange die Bedingung wahr ist.

Die while-Anweisung gehört zu den Schleifen. Mit ihrer Hilfe kann man eine Anweisung oder einen Anweisungsblock so lange wiederholt ausführen lassen, wie eine gegebene Bedingung wahr ist (ungleich Null). Wenn die Bedingung bereits bei der ersten Ausführung des while-Befehls nicht wahr ist, werden die Anweisung(en) nie ausgeführt.

Beispiel 1

int x = 0;
while (x < 10)
{
printf("\nDer Wert von x ist %d", x );
x++;
}

Beispiel 2

/* Liest solange Werte ein, bis die Zahl 99 eingegeben wird */
int nbr=0;
while (nbr <= 99)
scanf("%d", &nbr );

Beispiel 3

/* Erlaubt die Benutzereingabe von bis zu 10 Integer-Werten */
/* Die Werte werden in einem Array namens wert gespeichert. */
/* Wenn 99 eingegeben wird, stoppt die Schleife. */
int wert[10];
int ctr = 0;
int nbr;
while (ctr < 10 && nbr != 99)
{
puts("Geben Sie eine Zahl ein, mit 99 verlassen ");
scanf("%d", &nbr);
wert[ctr] = nbr;
ctr++;
}

Verschachtelte while-Anweisungen

Wie schon vorher die for- und if-Anweisungen können auch while-Anweisungen verschachtelt werden. In Listing 5.4 finden Sie ein Beispiel für verschachtelte while- Anweisungen. Dies ist zwar nicht der beste Einsatzbereich für eine while-Anweisung, aber das Beispiel hält einiges Neue für Sie bereit:

Listing 5.4: Verschachtelte while-Anweisungen.

1:   /* Beispiel für verschachtelte while-Anweisungen */
2:
3: #include <stdio.h>
4:
5: int array[5];
6:
7: int main(void)
8: {
9: int ctr = 0,
10: nbr = 0;
11:
12: printf("Dies Programm fordert Sie auf, 5 Zahlen einzugeben\n");
13: printf("Jede Zahl muss zwischen 1 und 10 liegen\n");
14:
15: while ( ctr < 5 )
16: {
17: nbr = 0;
18: while (nbr < 1 || nbr > 10)
19: {
20: printf("\nGeben Sie Zahl %d von 5 ein: ", ctr + 1 );
21: scanf("%d", &nbr );
22: }
23:
24: array[ctr] = nbr;
25: ctr++;
26: }
27:
28: for (ctr = 0; ctr < 5; ctr++)
29: printf("Der Wert von %d lautet %d\n", ctr + 1, array[ctr] );
30:
31: return 0;
32: }

Dies Programm fordert Sie auf, 5 Zahlen einzugeben
Jede Zahl muss zwischen 1 und 10 liegen

Geben Sie Zahl 1 von 5 ein: 3

Geben Sie Zahl 2 von 5 ein: 6

Geben Sie Zahl 3 von 5 ein: 3

Geben Sie Zahl 4 von 5 ein: 9

Geben Sie Zahl 5 von 5 ein: 2

Der Wert von 1 lautet 3
Der Wert von 2 lautet 6
Der Wert von 3 lautet 3
Der Wert von 4 lautet 9
Der Wert von 5 lautet 2

Wie schon in den vorherigen Listings enthält Zeile 1 einen Kommentar, der das Programm beschreibt, und Zeile 3 eine #include-Anweisung für die Header-Datei der Standardein-/-ausgabe. Zeile 5 deklariert ein Array (namens array), das fünf Integer- Werte aufnehmen kann. Die Funktion main() deklariert zwei zusätzliche lokale Variablen, ctr und nbr (in den Zeilen 9 und 10). Beachten Sie, dass diese Variablen bei ihrer Deklaration mit 0 initialisiert werden. Auch möchte ich Sie auf den Komma- Operator am Ende von Zeile 9 hinweisen, der als Trennzeichen dient und nbr als int deklariert, ohne dass dafür in Zeile 10 die Angabe des int-Typs wiederholt werden muss. Deklarationen dieser Art sind gängige Praxis unter vielen C-Programmierern. Die Zeilen 12 und 13 geben eine Meldung aus, die darüber informiert, was das Programm macht und was vom Anwender erwartet wird. In den Zeilen 15 bis 26 stehen der erste while-Befehl und seine Anweisungen. Eingebettet darin befindet sich in den Zeilen 18 bis 22 eine verschachtelte while-Schleife mit eigenen Anweisungen, die Teil der äußeren while-Anweisung ist.

Die äußere Schleife wird so lange ausgeführt, wie ctr kleiner als 5 ist (Zeile 15). Solange ctr kleiner als 5 ist, setzt Zeile 17 nbr auf 0, die Zeilen 18 bis 22 (die verschachtelte while-Anweisung) lesen eine Zahl in die Variable nbr ein, Zeile 24 legt die Zahl in array ab und Zeile 25 inkrementiert ctr. Die Aufgabe der äußeren Schleife besteht also darin, fünf Zahlen entgegenzunehmen, sie jeweils in array abzulegen und sie mit ctr zu indizieren.

Die innere Schleife ist ein gutes Beispiel für den sinnvollen Einsatz einer while- Anweisung. Im Programm stellen nur die Zahlen von 1 bis 10 gültige Eingaben dar und solange der Anwender keine gültige Zahl eingibt, soll das Programm nicht fortgeführt werden. Die Zeilen 18 bis 22 enthalten den zugehörigen Code. Die while- Anweisung sorgt dafür, dass für Eingaben kleiner als 1 oder größer als 10 der Anwender erneut aufgefordert wird, eine Zahl einzuzugeben, und diese dann eingelesen wird.

Die Zeilen 28 und 29 geben die Werte aus, die in array gespeichert sind. Beachten Sie, dass der for-Befehl die Variable ctr verwenden kann, weil diese von den while- Anweisungen nicht mehr benötigt wird. Die for-Schleife, die bei Null beginnt und um 1 inkrementiert, wird fünfmal durchlaufen und gibt den Wert von ctr plus 1 (da die Zählung bei Null begann) sowie den entsprechenden Wert in array aus.

Es gibt zwei Dinge in diesem Programm, die Sie zu Übungszwecken einmal ändern sollten. Zum einen können Sie den Wertebereich, den das Programm akzeptiert, verändern. Erweitern Sie ihn doch einfach von 1 bis 10 auf 1 bis 100. Außerdem können Sie die Anzahl der einzugebenden Werte variieren. Im jetzigen Programm sind das fünf Zahlen. Versuchen Sie es doch einmal mit 10.

Was Sie tun sollten

Was nicht

Verwenden Sie keine while-Anweisung, sondern eine for-Anweisung, wenn Sie in Ihrer Schleife Werte initialisieren und inkrementieren müssen. In der for- Schleife stehen die Initialisierungs-, Bedingungs- und Inkrementierungsanweisungen dicht beieinander. In der while-Anweisung nicht.

Verwenden Sie die folgende Konvention nur, wenn es unbedingt nötig ist:

while (x)

Halten Sie sich stattdessen an folgende Konvention:

while (x != 0)

Beide Konventionen sind möglich, doch die zweite ist klarer beim Debuggen des Codes (bei der Fehlersuche). Die Kompilierung erzeugt aus beiden Zeilen praktisch den gleichen Code.

do...while-Schleifen

Das dritte Schleifenkonstrukt von C ist die do...while-Schleife, die einen Anweisungsblock so lange ausführt, wie eine bestimmte Bedingung wahr ist. Eine do...while-Schleife testet die Bedingung allerdings erst am Ende der Schleife und nicht am Anfang, wie das bei den for- und der while-Schleifen der Fall ist.

Der Aufbau einer do...while-Schleife sieht folgendermaßen aus:

do
Anweisung;
while (Bedingung);

Bedingung ist ein beliebiger C-Ausdruck und Anweisung ist eine einfache oder komplexe C-Anweisung. Wenn das Programm auf eine do...while-Anweisung trifft, passiert Folgendes:

  1. Die Anweisungen in Anweisung werden ausgeführt.
  2. Die Bedingung wird ausgewertet. Ist sie wahr, kehrt die Ausführung zurück zu Schritt 1. Ist sie falsch, wird die Schleife beendet.

Den Ablauf einer do...while-Schleife finden Sie in Abbildung 5.4.

Abbildung 5.4:  Der Ablauf einer do...while-Schleife.

Die Anweisungen einer do...while-Schleife werden immer mindestens einmal ausgeführt. Dies liegt daran, dass die Testbedingung am Ende der Schleife und nicht am Anfang ausgewertet wird. for- und while-Schleifen dagegen werten die Testbedingung zu Beginn der Schleife aus, so dass ihre Anweisungen nicht ausgeführt werden, wenn die Testbedingung bereits bei Eintritt in die Schleife unwahr ist.

do...while-Schleifen werden seltener verwendet als while- und for-Schleifen. Sie sind vor allem dort angebracht, wo die Anweisung(en) der Schleife zumindest einmal ausgeführt werden muss (müssen). Sie können das Problem auch ohne weiteres mit einer while-Schleife lösen, indem Sie sicher stellen, dass die Testbedingung wahr ist, wenn die Programmausführung die Schleife das erste Mal erreicht. Allerdings wäre eine do...while-Schleife wahrscheinlich unkomplizierter.

Listing 5.5 zeigt Ihnen ein Beispiel für eine do...while-Schleife.

Listing 5.5: Eine einfache do...while-Schleife.

1:   /* Beispiel für eine einfache do...while-Anweisung */
2:
3: #include <stdio.h>
4:
5: int menue_option_einlesen( void );
6:
7: int main(void)
8: {
9: int option;
10:
11: option = menue_option_einlesen();
12:
13: printf("Sie haben die Menü-Option %d gewählt\n", option );
14:
15: return 0;
16: }
17:
18: int menue_option_einlesen( void )
19: {
20: int auswahl = 0;
21:
22: do
23: {
24: printf("\n" );
25: printf("\n1 - Datensatz hinzufügen" );
26: printf("\n2 - Datensatz ändern ");
27: printf("\n3 - Datensatz löschen ");
28: printf("\n4 - Verlassen");
29: printf("\n" );
30: printf("\nGeben Sie Ihre Wahl ein: " );
31:
32: scanf("%d", &auswahl );
33:
34: }while ( auswahl < 1 || auswahl > 4 );
35:
36: return auswahl;
37: }

1 - Datensatz hinzufügen
2 - Datensatz ändern
3 - Datensatz löschen
4 - Verlassen

Geben Sie Ihre Wahl ein: 8

1 - Datensatz hinzufügen
2 - Datensatz ändern
3 - Datensatz löschen
4 - Verlassen

Geben Sie Ihre Wahl ein: 4
Sie haben die Menü-Option 4 gewählt

Dieses Programm stellt ein Menü mit vier Optionen bereit. Der Anwender wählt eine der vier Optionen aus, und das Programm gibt dann die gewählte Zahl aus. Spätere Programme in diesem Buch verwenden und erweitern dieses Konzept. Der größte Teil des Listings sollte Ihnen vom Verständnis her keine Schwierigkeiten bereiten. Die Funktion main() in den Zeilen 7 bis 16 enthält nichts, was Sie nicht schon kennen.

Der Rumpf von main() hätte auch wie folgt in einer Zeile geschrieben werden können:

printf( "Sie haben die Menü-Option %d gewählt", menue_option_einlesen() );

Wenn man aber das Programm erweitern und auf die getroffene Auswahl reagieren möchte, benötigt man den von menue_option_einlesen() zurückgegebenen Wert. Deshalb ist es ratsam, diesen Wert einer Variablen (wie option) zuzuweisen.

Die Zeilen 18 bis 37 enthalten die Funktion menue_option_einlesen(). Diese Funktion gibt auf dem Bildschirm ein Menü aus (Zeilen 24 bis 30) und nimmt den Zahlencode der getroffenen Auswahl entgegen. Da Sie ein Menü mindestens einmal anzeigen müssen, um eine Antwort zu erhalten, bietet sich hier die Verwendung einer do...while-Schleife an. In unserem Programm wird das Menü so oft angezeigt, bis eine gültige Auswahl getroffen wurde. Zeile 34 enthält den while-Teil der do...while- Anweisung und wertet den eingegebenen Wert für die Menüauswahl (sinnvollerweise auswahl genannt) aus. Wenn der eingegebene Wert nicht zwischen 1 und 4 liegt, wird das Menü erneut angezeigt und der Benutzer zu einer neuen Menüauswahl aufgefordert. Wird eine gültige Zahl eingegeben, fährt das Programm mit Zeile 36 fort, die den Wert der Variablen auswahl zurückliefert.

Die do...while-Anweisung

do
{
Anweisung(en);
}while (Bedingung);

Bedingung ist ein beliebiger gültiger C-Ausdruck, in der Regel ein relationaler Ausdruck. Wenn Bedingung als unwahr (Null) ausgewertet wird, endet die while- Anweisung und die Ausführung fährt mit der ersten Anweisung nach der while- Anweisung fort. Im anderen Fall springt das Programm zurück zu dem do-Teil und die C-Anweisung(en) in Anweisung(en) wird (werden) ausgeführt

Bei Anweisung(en) handelt es sich um eine einfache C-Anweisung oder einen Block von Anweisungen. Diese Anweisungen werden beim ersten Durchlauf der Schleife und danach so lange, wie Bedingung wahr ist, ausgeführt.

Die do...while-Anweisung gehört zu den Schleifen. Mit ihrer Hilfe kann man eine Anweisung oder einen Anweisungsblock so lange wiederholt ausführen lassen, wie eine gegebene Bedingung wahr ist (ungleich Null). Im Gegensatz zu einem while- Befehl werden die Anweisungen einer do...while-Schleife mindestens einmal ausgeführt.

Beispiel 1

/* Ausgabe erfolgt, auch wenn die Bedingung falsch ist! */
int x = 10;
do
{
printf("\nDer Wert von x ist %d", x );
}while (x != 10);

Beispiel 2

/* Liest so lange Werte ein, bis die Zahl 99 eingegeben wird */
int nbr;
do
{
scanf("%d", &nbr );
}while (nbr <= 99);

Beispiel 3

/* Erlaubt die Benutzereingabe von bis zu 10 Integer-Werten  */
/* Die Werte werden in einem Array namens wert gespeichert. */
/* Wenn 99 eingegeben wird, stoppt die Schleife. */
int wert[10];
int ctr = 0;
int nbr;
do
{
puts("Geben Sie eine Zahl ein, mit 99 verlassen ");
scanf( "%d", &nbr);
wert[ctr] = nbr;
ctr++;
}while (ctr < 10 && nbr != 99);

Verschachtelte Schleifen

Der Begriff verschachtelte Schleife bezieht sich auf eine Schleife, die innerhalb einer anderen Schleife verwendet wird. Sie haben bereits einige Beispiele für verschachtelte Schleifen kennen gelernt. Bezüglich der Verschachtelungstiefe sind Ihnen in C praktisch keine Grenzen gesetzt. Sie müssen nur aufpassen, dass jede innere Schleife komplett von der äußeren Schleife eingeschlossen ist. Schleifen dürfen sich nicht überlappen. Aus diesem Grund ist folgender Code nicht erlaubt:

for ( count = 1; count < 100; count++)
{
do
{
/* die do...while-Schleife */
} /* Ende der for-Schleife */
}while (x != 0);

Wenn die do...while-Schleife komplett von der for-Schleife umschlossen ist, gibt es keine Probleme:

for (count = 1; count < 100; count++)
{
do
{
/* die do...while-Schleife */
}while (x != 0);
} /* Ende der for-Schleife */

Wenn Sie verschachtelte Schleifen verwenden, sollten Sie daran denken, dass Änderungen in der inneren Schleife unter Umständen Auswirkungen auf die äußere Schleife haben können. Die innere Schleife kann jedoch auch völlig unabhängig von den Variablen der äußeren Schleife sein. In unserem Beispiel ist dem allerdings nicht so. Wenn in dem obigen Beispiel der Wert count in der inneren do...while-Schleife geändert wird, hat das Einfluss darauf, wie oft die äußere for-Schleife ausgeführt wird.

Einrückungen erhöhen die Lesbarkeit von Code mit verschachtelten Schleifen. Jede Schleifenebene sollte sich von der vorherigen durch Einrückung abheben. Damit machen Sie deutlich, welcher Code zu welcher Schleife gehört.

Was Sie tun sollten

Was nicht

Verwenden Sie die do...while-Schleife, wenn Sie wissen, dass die Schleife mindestens einmal ausgeführt werden soll.

Versuchen Sie nicht, Schleifen zu überlappen. Sie können sie zwar verschachteln, doch Sie müssen dabei darauf achten, dass sie völlig ineinander liegen.

Zusammenfassung

Nach der heutigen Lektion sind Sie schon fast gerüstet, um selbst richtige C- Programme aufzusetzen.

In C gibt es drei Schleifenanweisungen, die den Programmfluss steuern: for, while und do...while. Jedes dieser Konstrukte lässt Ihr Programm einen Anweisungsblock in Abhängigkeit von dem aktuellen Wert bestimmter Programmvariablen keinmal, einmal oder mehrere Male ausführen. Viele Programmieraufgaben lassen sich durch die wiederholte Ausführung, wie sie durch diese Schleifenanweisungen möglich sind, elegant lösen.

Auch wenn sich alle drei Anweisungen auf das gleiche Problem anwenden lassen, unterscheiden sie sich doch durch besondere Eigenheiten. Bei der for-Anweisung können Sie in einem Befehl initialisieren, auswerten und inkrementieren. Die while- Anweisung wird ausgeführt, solange eine Bedingung wahr ist, und die do...while- Anweisung führt ihre Anweisungen mindestens einmal aus und anschließend so lange, bis die Bedingung zu unwahr ausgewertet wird.

Unter Verschachtelung versteht man die Unterbringung eines Befehls innerhalb eines anderen. In C können alle Befehle verschachtelt werden. Am Tag 3 habe ich Ihnen bereits gezeigt, wie Sie die if-Anweisung verschachteln. Heute wurden die for-, die while- und die do...while-Anweisungen verschachtelt.

Fragen und Antworten

Frage:
Woher weiß ich, welche Anweisung ich zur Programmsteuerung verwenden muss - for, while oder do...while?

Antwort:
Wenn Sie sich die einzelnen Syntaxbeispiele anschauen, werden Sie feststellen, dass man mit allen dreien ein Schleifenproblem lösen kann. Jede Anweisung hat jedoch so ihre Eigenheiten. Die for-Anweisung eignet sich am besten, wenn Sie wissen, dass Sie in Ihrer Schleife initialisieren und inkrementieren müssen. Wenn Sie lediglich eine Bedingung abfragen und keine bestimmte Anzahl von Schleifeniterationen durchführen wollen, ist while zu empfehlen. Und wenn Sie davon ausgehen, dass der zugehörige Anweisungsblock mindestens einmal ausgeführt werden muss, ist do...while die beste Wahl. Da alle drei für die meisten Probleme verwendet werden können, möchte ich Ihnen empfehlen, sich mit allen dreien vertraut zu machen und dann in jeder Programmsituation individuell abzuwägen, welches Konstrukt am besten geeignet ist.

Frage:
Wie tief kann ich meine Schleifen verschachteln?

Antwort:
Für die Verschachtelungstiefe sind Ihnen keine Grenzen gesetzt. Wenn Ihr Programm mehr als zwei Verschachtelungsebenen benötigt, sollten Sie überlegen, ob Sie nicht besser eine Funktion verwenden. Vielleicht stellen Sie fest, dass die vielen geschweiften Klammern das Lesen des Codes erschweren - dann könnte eine Funktion Abhilfe schaffen.

Frage:
Kann ich unterschiedliche Schleifenbefehle verschachteln?

Antwort:
Sie können if, for, while, do...while oder irgendwelche anderen Befehle verschachteln. Sie werden bald feststellen, dass viele Programme, die Sie schreiben wollen, das Verschachteln von zumindest einigen dieser Befehl erforderlich machen.

Workshop

Der Workshop enthält Quizfragen, die Ihnen helfen sollen, Ihr Wissen zu festigen, sowie Übungen, die Sie anregen sollen, das Gelernte umzusetzen und eigene Erfahrungen zu sammeln. Die Lösungen zu den Fragen und den Übungen finden Sie in Anhang C.

Quiz

  1. Wie lautet der Indexwert des ersten Elements in einem Array?
  2. Worin besteht der Unterschied zwischen einer for- und einer while-Anweisung?
  3. Worin besteht der Unterschied zwischen einer while- und einer do...while- Anweisung?
  4. Stimmt es, dass man eine while-Anweisung verwenden und mit dieser die gleichen Ergebnisse erzielen kann wie mit einer for-Anweisung?
  5. Woran müssen Sie denken, wenn Sie Anweisungen verschachteln?
  6. Kann eine while-Anweisung in einer do...while-Anweisung verschachtelt werden?
  7. Wie lauten die vier Teile einer for-Anweisung?
  8. Wie lauten die zwei Teile einer while-Anweisung?
  9. Wie lauten die zwei Teile einer do...while-Anweisung?

Übungen

  1. Deklarieren Sie ein Array, dass 50 Werte vom Typ long enthält.
  2. Schreiben Sie eine Anweisung, die dem 50. Element im Array von Übung 1 den Wert 123.456 zuweist.
  3. Wie lautet der Wert von x, nachdem die folgende Anweisung ausgeführt wurde?
    for (x = 0; x < 100, x++) ;
  4. Wie lautet der Wert von ctr, nachdem die folgende Anweisung ausgeführt wurde?
    for (ctr = 2; ctr < 10; ctr += 3) ;
  5. Wie viele X gibt der folgende Code aus?
    for (x = 0; x < 10; x++)
    for (y = 5; y > 0; y - )
    puts("X");
  6. Schreiben Sie eine for-Anweisung, die in Dreierschritten von 1 bis 100 zählt.
  7. Schreiben Sie eine while-Anweisung, die in Dreierschritten von 1 bis 100 zählt.
  8. Schreiben Sie eine do...while-Anweisung, die in Dreierschritten von 1 bis 100 zählt.
  9. FEHLERSUCHE: Was ist falsch an folgendem Codefragment?
    datensatz = 0;
    while (datensatz < 100)
    {
    printf( "\nDatensatz %d ", datensatz );
    printf( "\nNächste Zahl..." );
    }
  10. FEHLERSUCHE: Was ist falsch an folgendem Codefragment? (MAXWERTE ist nicht das Problem!)
    for (zaehler = 1; zaehler < MAXWERTE; zaehler++);
    printf("\nZaehler = %d", zaehler );


vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbackKapitelanfangnächstes Kapitel


© Markt&Technik Verlag, ein Imprint der Pearson Education Deutschland GmbH