5 Bedingte Anweisung und Verzweigung
In diesem Kapitel erfahren Sie, was bedingte Anweisungen sind. Bis jetzt können Sie nämlich nur Programme schreiben, die Zahlen oder- nach dem Durchlesen der Manpages zu scanf()- zur Not auch eine Zeichenkette von der Tastatur einlesen und diese wieder auf dem Bildschirm ausgeben. Außerdem können Sie Berechnungen mit den eingelesenen Zahlen ausführen. Stellen Sie sich aber nun vor, Sie wollen ein Programm schreiben, das feststellen kann, ob ein bestimmtes Jahr ein Schaltjahr ist. In diesem Fall muss Ihr Programm prüfen, ob bestimmte Bedingungen zutreffen, nämlich die, dass das Jahr durch 4, nicht aber durch 100 teilbar ist, und zusätzlich alle Jahre Schaltjahre sind, die durch 400 teilbar sind. Wenn Sie dieses Kapitel gelesen haben, können Sie solche bedingten Anweisungen ausführen.
5.1 Bedingte Anweisungen
Es wurde ja schon angedeutet, dass Ihr Prozessor Befehle kennt, um an eine bestimmte Stelle zu springen und an dieser Stelle die Ausführung des Programms fortzusetzen. Nun kann Ihr Prozessor noch mehr, z. B. anhand bestimmter Bits in einer internen Speicherstelle feststellen, ob z. B. das Ergebnis einer Addition positiv, negativ oder null war. Ebenso werden bestimmte Bits (die Prozessor-Flags) gesetzt, wenn ein Überlauf passiert ist. Es gibt zusätzlich neben den direkten Sprüngen und Vergleichsbefehlen auch bedingte Sprünge, die z. B. die internen Statusbits auswerten und nur dann ausgeführt werden, wenn z. B. das Ergebnis einer Addition wirklich null war. Nun ist C eine Hochsprache, das heißt, sie hat u. a. das Ziel, von der komplexen Maschinenebene zu abstrahieren. Auch im Falle der bedingten Sprungbefehle des Prozessors tut C genau dies und stellt die bedingten Anweisungen zur Verfügung. Eine bedingte Anweisung dient dazu, einen bestimmten Codeabschnitt nur dann auszuführen, wenn eine bestimmte Bedingung erfüllt ist.
5.1.1 Bedingte Anweisungen mit if
Die Syntax einer bedingten if-Anweisung in C sieht wie folgt aus:
if(ausdruck) {
anweisung1;
}
anweisung2;
Zuerst wird die Bedingung ausdruck ausgewertet. Je nachdem, ob ausdruck wahr (bzw. ungleich 0) ist, wird die Anweisung anweisung1 im Anweisungsblock zwischen den geschweiften Klammern ausgeführt oder übersprungen, wenn die Bedingung ausdruck unwahr ist. Anschließend wird die Programmausführung mit der Anweisung anweisung2 fortgesetzt. Das heißt: Ist die Bedingung ausdruck unwahr (bzw. gleich 0), werden die Anweisungen im Anweisungsblock nicht ausgeführt, und das Programm fährt sofort mit der Anweisung anweisung2 fort.
Ich werde auf Anweisungsblöcke im Anschluss an die Vergleichsoperatoren noch ausführlicher eingehen, nämlich dann, wenn mehr als eine Anweisung bedingt ausgeführt werden soll. Sie sollten sich an dieser Stelle aber schon einmal angewöhnen, die Anweisungen innerhalb eines Anweisungsblocks mit der Tabulatortaste einzurücken. Nur so behalten Sie in komplexen Programmen, in denen Anweisungsblöcke durchaus geschachtelt werden können, einen guten Überblick.
Logische Ausdrücke
Die runden Klammern hinter if sind für den logischen Ausdruck unbedingt erforderlich. »Logisch« bedeutet in C immer ganzzahlig. Daher kann der Ausdruck in if jeden beliebigen numerischen Wert annehmen. 0 wird, wie bereits erwähnt, als falsch (unwahr) und jeder andere Wert als richtig (wahr) interpretiert.
Abbildung 5.1 stellt die bedingte if-Anweisung in einem Programmablaufplan schematisch dar.
Sehen Sie sich hierzu folgendes Programmbeispiel an:
00 // Kapitel5/if_beispiel.c
01 #include <stdio.h>
02 int main(void) {
03 int ival = 0;
04 printf("Bitte eine Ganzzahl eingeben: ");
05 int check = scanf("%d", &ival);
06 if( check ) {
07 // Der Code wird ausgeführt, wenn die Bedingung, dass
08 // der Wert check nicht 0 ist, wahr ist.
09 printf("Ihre Eingabe: %d\n", ival);
10 }
11 printf("Außerhalb der if-Verzweigung\n");
12 return 0;
13 }
Das letzte Beispiel ist absichtlich sehr einfach gehalten. In Zeile (04) werden Sie aufgefordert, eine Ganzzahl einzugeben. Die Eingabe wird mit scanf() in Zeile (05) eingelesen und in der Variable ival (Zeile (03)) gespeichert. Der Rückgabewert von scanf() wird in der Variablen check gespeichert. In Zeile (06) wird die Bedingung (oder besser der Ausdruck) daraufhin überprüft, ob die Anzahl der eingegebenen Werte von scanf() »stimmt«. Dies ist der Fall, wenn check hier ungleich 0 (= wahr) ist. Hat der Anwender einen zum Umwandlungszeichen %d gültigen Wert eingegeben, wird die printf()-Anweisung in Zeile (09) im Anweisungsblock der if-Anweisung ausgeführt. Es werden also alle Anweisungen im Anweisungsblock zwischen den Zeilen (06) bis (10) ausgeführt (hier allerdings nur eine einzige Anweisung).
Hat der Anwender hingegen z. B. einen Buchstaben eingegeben, werden die Anweisungen zwischen dem Anweisungsblock (Zeile (06) bis (10)) nicht ausgeführt, weil die if-Bedingung in diesem Fall 0 war, und es wird gleich mit der printf()-Anweisung in Zeile (11) fortgefahren. Diese Zeile wird natürlich auch dann ausgeführt, wenn die Anweisungen im if-Anweisungsblock zwischen den Zeilen (07) bis (10) ausgeführt wurden.
Das Programm gibt bei der Ausführung z. B. Folgendes aus:
Bitte eine Ganzzahl eingeben: 10
Ihre Eingabe: 10
Außerhalb der if-Verzweigung
Bitte eine Ganzzahl eingeben: a
Außerhalb der if-Verzweigung
5.1.2 Vergleichsoperatoren
Ein Vergleich wie in Zeile (06) des obigen Listings if_beispiel.c dürfte Sie vielleicht ein wenig irritieren. Sie hätten hier genauso gut Folgendes verwenden können:
06 if(check !=0) {
07 // Der Code wird ausgeführt, wenn die Bedingung, dass
08 // der Wert check nicht 0 ist, wahr ist.
09 printf("Ihre Eingabe: %d\n", ival);
10 }
Dieser Vergleich in Zeile (06) mit dem !=-Operator (Nicht-gleich-Operator, einem Vergleichsoperator), ob der Ausdruck zwischen den Klammern von if ungleich 0 ist, entspricht dem in Listing 5.1 verwendeten Ausdruck. Bevor Sie weitere Verzweigungsmöglichkeiten kennenlernen, soll hier kurz auf die vorhandenen Vergleichsoperatoren eingegangen werden. Alle in Tabelle 5.1 aufgelisteten Vergleichsoperatoren vergleichen zwei Operanden und liefern einen Wert vom Typ int zurück. Ist der Vergleich wahr, geben die Operatoren einen Wert ungleich 0 zurück. Ist der Vergleich unwahr, wird 0 zurückgegeben.
Operator |
Bedeutung |
Beispiel |
Rückgabewert |
---|---|---|---|
kleiner |
a < b |
ungleich 0, wenn a kleiner als b, ansonsten 0 |
|
kleiner oder gleich |
a <= b |
ungleich 0, wenn a kleiner oder gleich b, ansonsten 0 |
|
größer |
a > b |
ungleich 0, wenn a größer b, ansonsten 0 |
|
größer oder gleich |
a >= b |
ungleich 0, wenn a größer oder gleich b, ansonsten 0 |
|
gleich |
a == b |
ungleich 0, wenn a gleich b, ansonsten 0 |
|
ungleich |
a != y |
ungleich 0, wenn a ungleich b, ansonsten 0 |
So ganz können Sie den Code in if_beispiel.c allerdings mit dem Vergleich auf ungleich 0 nicht stehen lassen, da scanf() ja auch den Wert EOF im Fehlerfall vor der ersten Umwandlung zurückgeben kann, was oftmals als –1 implementiert ist. Somit wird der Anweisungsblock der bedingten if-Anweisung vielleicht auch dann ausgeführt, wenn ein EOF-Fehler bei scanf() auftritt. Daher sind Sie bei diesem Beispiel auf der sicheren Seite, wenn Sie prüfen, ob check gleich dem Wert 1 entspricht. scanf() gibt ja die Anzahl der erfolgreich eingelesenen Werte zurück (hier nur einen Wert). Daher sollten Sie das Beispiel besser wie folgt abändern:
06 if(check ==1 ) {
07 // Der Code wird ausgeführt, wenn die Bedingung, dass
08 // der Wert check gleich 1 ist, wahr ist.
09 printf("Ihre Eingabe: %d\n", ival);
10 }
Anstelle einer Zuweisung des Rückgabewertes von scanf() an die zusätzliche Variable check können Sie den Rückgabewert dieser Funktion mit der Anzahl erfolgreich eingelesener Werte (hier: ein Wert) natürlich auch direkt und ohne Umweg in die bedingte if-Anweisung einbauen. Zwar wurden Rückgabewerte von Funktionen noch nicht behandelt, aber das Beispiel dazu wollen wir Ihnen nicht vorenthalten:
...
int ival = 0;
printf("Bitte eine Ganzzahl eingeben: ");b
if( scanf("%d", &ival) == 1 ) {
// Der Code wird ausgeführt, wenn die Bedingung, dass
// scanf den Wert 1 zurückgibt, wahr ist.
printf("Ihre Eingabe: %d\n", ival);
}
...
Vergleichsoperatoren müssen übrigens nicht unbedingt zwischen Vergleichen von if-Verzweigungen oder Schleifen stehen. So können Vergleichsoperatoren auch wie folgt verwendet werden:
int ival1 = 10 > 5; // ival1 = 1
int ival2 = 5 == 4; // ival2 = 0
int ival3 = ival1 != ival2; // ival3 = 1
printf("%d : %d : %d\n", ival1, ival2, ival3);
5.1.3 Mini-Exkurs: Anweisungsblock
Wenn Sie bedingte Anweisungen oder Verzweigungen erstellen, werden Sie häufig aufgrund einer Bedingung oder Verzweigung mehr als nur eine Anweisung ausführen wollen. Mehrere Anweisungen können Sie in C in einem Anweisungsblock (engl. compound statement) zwischen geschweiften Klammern in einer Sequenz von Anweisungen zusammenfassen, beispielsweise:
{ // Anweisungsblock – Anfang
Anweisung1;
Anweisung2;
...
AnweisungN;
} // Anweisungsblock – Ende
Solche Anweisungsblöcke lassen sich auch ineinander verschachteln. Es empfiehlt sich jedoch, hiervon selten Gebrauch zu machen, weil sonst die Strukturierung und somit die Lesbarkeit des Programms erheblich leidet. Es gibt natürlich immer Fälle, in denen sich eine gewisse Verschachtelung nicht vermeiden lässt.