Warum Programme Verzweigungen brauchen
Jedes Programm bisher lief geradeaus durch: Zeile 1, Zeile 2, Zeile 3. Echte Programme treffen Entscheidungen. Ist das Passwort richtig? Ist die Zahl negativ? Ließ sich die Datei öffnen? Die if-Anweisung ist Cs Art, eine Frage zu stellen und Code nur auszuführen, wenn die Antwort ja lautet.
Die Bedingung temperature > 30 wird einmal geprüft. Sie gilt, also wird die Meldung ausgegeben. Die letzte Zeile steht außerhalb der Klammern, sie wird also auf jeden Fall ausgegeben. Ändere 31 in 18 und führe es erneut aus - die erste Meldung verschwindet und die zweite bleibt.
Syntax: Klammern, geschweifte Klammern und kein Semikolon
Ein if hat in C eine feste Gestalt:
if (condition) {
// läuft, wenn die Bedingung ungleich null ist
}
Drei Regeln lohnen sich früh zu merken. Die Klammern um die Bedingung sind Pflicht. Ein Schlüsselwort then gibt es nicht. Und nach der schließenden Klammer steht kein Semikolon - ein verirrtes beendet die Anweisung genau dort:
// BUG: das if tut nichts; das printf läuft immer
if (x > 10);
{
printf("gross\n");
}
Das kompiliert sauber. Das ; ist eine leere Anweisung, die zum Rumpf des if wird, und die geschweiften Klammern darunter sind nur ein freistehender Block, der immer läuft. Mit gcc -Wall zu kompilieren fängt es ab.
Die geschweiften Klammern selbst sind bei einer einzelnen Anweisung optional, aber lass sie stehen. Ein klammerloses if, das später eine zweite Zeile bekommt, ist eine klassische Fehlerquelle, denn Einrückung gruppiert in C keine Anweisungen.
else und else if
else liefert den anderen Pfad:
Für mehr als zwei Ausgänge verkettest du mit else if. C prüft jede Bedingung der Reihe nach und hört bei der ersten auf, die gilt:
Die Reihenfolge zählt hier enorm. Weil die Kette bei der ersten Übereinstimmung stoppt, sieht die zweite Prüfung nur noch Punktzahlen unter 90 - weshalb score >= 80 nicht zusätzlich && score < 90 sagen muss. Schreibe die Kette von der einschränkendsten zur lockersten Bedingung, sonst fällt jeder Wert in den ersten Zweig.
Das abschließende else ist optional. Nimm eines, wann immer die Kette jeden Fall abdecken soll; sein Fehlen bedeutet „wenn nichts passte, tu nichts", was in Ordnung ist, aber bewusst sein sollte.
Wahrheit: 0 ist falsch, alles andere ist wahr
Cs Kernsprache hat in Bedingungen keinen eigenen Wahrheitstyp. Ein if fragt schlicht, ob der Ausdruck ungleich null ist.
Die letzten beiden Zeilen zeigen die andere Hälfte der Regel: Vergleichsoperatoren sind gewöhnliche Ausdrücke, die 1 für wahr und 0 für falsch liefern. Deshalb funktioniert if (5 > 2) - in Wahrheit ist es if (1).
Deshalb ist -3 in C auch wahr. Die Regel lautet ungleich null, nicht positiv. Willst du wissen, ob eine Zahl positiv ist, sag if (n > 0), nicht if (n).
C99 fügte <stdbool.h> mit einem echten bool-Typ plus true und false hinzu, was sich in neuem Code besser liest. Unter der Haube sind sie weiterhin 1 und 0, an der obigen Regel ändert sich also nichts - siehe Booleans in C.
Die Vergleichs- und Logikoperatoren, die du in Bedingungen benutzen wirst:
== gleich && logisches UND (beide Seiten wahr)
!= ungleich || logisches ODER (eine Seite wahr)
< kleiner als ! logisches NICHT
> größer als
<= kleiner oder gleich
>= größer oder gleich
&& und || werten abkürzend aus: a && b wertet b nie aus, wenn a falsch ist, und a || b wertet b nie aus, wenn a wahr ist. Das ist eine Garantie, keine Optimierung, es ist also sicher, if (n != 0 && total / n > 5) zu schreiben - die Division kann nicht laufen, wenn n null ist.
Der = statt ==-Bug
Das ist der mit Abstand häufigste Fehler in C-Bedingungen:
// BUG: weist x den Wert 5 zu, testet dann 5 (ungleich null), das läuft also IMMER
if (x = 5) {
printf("x ist fuenf\n");
}
C erlaubt eine Zuweisung innerhalb eines Ausdrucks, die Zeile ist also gültig. Sie speichert 5 in x, liefert den Wert 5, und 5 ist ungleich null - der Zweig läuft jedes einzelne Mal, und x wurde still überschrieben.
Zwei Verteidigungen. Erstens: Kompiliere immer mit eingeschalteten Warnungen:
gcc -Wall -Wextra program.c -o program
GCC und clang melden beide „suggest parentheses around assignment used as truth value". Zweitens schreiben manche Programmierer die Konstante vor die Variable - if (5 == x) -, sodass ein vertipptes if (5 = x) ein harter Übersetzungsfehler statt eines stillen Bugs ist. Dieser Stil ist Geschmackssache; Warnungen einzuschalten ist es nicht.
Verschachtelung
Ein if kann ein weiteres if enthalten. Verschachtelung drückt Bedingungen aus, die erst Sinn ergeben, wenn eine frühere gilt:
Zwei Ebenen sind lesbar. Vier sind es nicht. Wenn die Verschachtelung tiefer wird, suche nach einem Weg, sie zu verflachen - oft, indem du Bedingungen mit && kombinierst oder die Fehlerfälle zuerst behandelst und früh zurückkehrst:
// flacher: die Ausnahmen erledigen, dann die eigentliche Arbeit
if (age < 18) { printf("Nur fuer Erwachsene.\n"); return 0; }
if (!hasTicket) { printf("Bitte kaufe ein Ticket.\n"); return 0; }
printf("Willkommen.\n");
Das baumelnde else
Wenn ein klammerloses if in einem anderen steckt, zu welchem if gehört dann ein else? Cs Regel: Ein else bindet an das nächstliegende unzugeordnete if, unabhängig davon, wie der Code eingerückt ist.
// Das else gehört zum INNEREN if, trotz der Einrückung
if (a > 0)
if (b > 0)
printf("beide positiv\n");
else
printf("a ist nicht positiv\n"); // FALSCH - läuft, wenn a > 0 und b <= 0
Die Einrückung sagt, dass das else zum äußeren if gehört. Der Compiler ordnet es dem inneren zu. Geschweifte Klammern beseitigen die Mehrdeutigkeit vollständig, und das ist das eigentliche Argument dafür, sie immer zu setzen:
if (a > 0) {
if (b > 0) {
printf("beide positiv\n");
}
} else {
printf("a ist nicht positiv\n");
}
Der ternäre Operator
Wenn ein Zweig nur existiert, um einen Wert zu wählen, sagt es der Bedingungsoperator ? : in einem Ausdruck:
Lies bed ? x : y als „wenn bed, dann x, sonst y". Genau einer der beiden Zweige wird ausgewertet, und das Ganze liefert einen Wert - weshalb es zugewiesen oder als Argument übergeben werden kann, wo eine Anweisung es nicht könnte.
Behalte es für einfache Wertentscheidungen. Verschachtelte ternäre Operatoren (a ? b : c ? d : e) sind erlaubt und fast immer schwerer zu lesen als die else if-Kette, die sie ersetzen.
Häufig gestellte Fragen
Wie schreibt man eine if-else-Anweisung in C?
Setze die Bedingung in Klammern und den Code in geschweifte Klammern: if (score >= 60) { printf("Bestanden\n"); } else { printf("Durchgefallen\n"); }. Der else-Block läuft nur, wenn die Bedingung falsch ist, und ein Schlüsselwort then gibt es in C nicht.
Was gilt in einer C-if-Anweisung als wahr?
Jeder Wert, der nicht null ist. C hat in seiner Kernsyntax keinen eigenen Wahrheitstyp, if (n) läuft also, wenn n alles außer 0 ist, und if (!n) läuft nur, wenn n genau 0 ist. Vergleichsoperatoren wie == und < liefern 1 für wahr und 0 für falsch.
Was ist der Unterschied zwischen = und == in C?
== vergleicht, = weist zu. if (x = 5) zu schreiben weist x den Wert 5 zu und testet dann 5, was ungleich null ist, der Zweig läuft also immer. Es kompiliert ohne Fehler, weshalb es der häufigste Anfängerfehler in C-Bedingungen ist - die meisten Compiler warnen mit -Wall davor.
Wie funktioniert der ternäre Operator in C?
bedingung ? wertWennWahr : wertWennFalsch ist ein Ausdruck, der einen von zwei Werten liefert, er kann also in einer Zuweisung oder einem printf-Argument stehen: int max = a > b ? a : b;. Nimm ihn zum Auswählen eines Werts und ein gewöhnliches if, wenn du Anweisungen ausführen musst.