C++-Programmierung/ Einführung in C++/ Verzweigungen
Eine Verzweigung (bedingte Anweisung, conditional statement) dient dazu, ein Programm in mehrere Pfade aufzuteilen. Beispielsweise kann so auf Eingaben des Benutzers reagiert werden. Je nachdem, was der Benutzer eingibt, ändert sich der Programmablauf.
Falls[Bearbeiten]
Verzweigungen werden mit dem Schlüsselwort
if
begonnen. In der einfachsten Form sieht das so aus:
Wenn die
Bedingung
erfüllt ist, wird die
Anweisung
ausgeführt, ansonsten wird sie übersprungen. Sollen nicht nur eine, sondern mehrere Anweisungen ausgeführt werden, fassen Sie diese mit
{...}
zu einer Blockanweisung zusammen:
Als
Bedingung
darf jeder Ausdruck verwendet werden, der einen
bool
zurückgibt oder dessen Ergebnis sich in einen
bool
umwandeln lässt. Ganzzahlige und Gleitkommadatentypen lassen sich nach
bool
umwandeln, die Regel lautet: Ist eine Zahl (exakt) gleich 0, so wird sie als
false
ausgewertet, andernfalls als
true
.
Andernfalls[Bearbeiten]
Das Schlüsselwort
else
erweitert die Einsatzmöglichkeiten der Verzweigung. Während ein normales (also einzelnes)
if
einen bestimmten Teil des Codes ausführt, falls eine Bedingung erfüllt ist, stellt
else
eine Erweiterung dar, anderen Code auszuführen, falls die Bedingung nicht erfüllt ist.
1int i;
2cin >> i;
3if (i)
4 cout << "Sie haben einen Wert ungleich 0 eingegeben!\n";
5else
6 cout << "Sie haben 0 eingegeben!\n";
Natürlich könnten auch hier, sowohl für die
if
-Anweisung, als auch für die
else
-Anweisung, ein Anweisungsblock stehen. Wenn Sie Pascal oder eine ähnliche Programmiersprache kennen, wird Ihnen auffallen, dass auch die Anweisung vor dem
else
mit einem Semikolon abgeschlossen wird. Da auf eine
if
- oder
else
-Anweisung immer nur eine Anweisung oder ein Anweisungsblock stehen kann, muss zwangsläufig direkt danach ein
else
stehen, um dem
if
zugeordnet zu werden.
Sie können in einer Verzweigungsanweisung auch mehr als zwei Alternativen angeben:
1int i;
2cin >> i;
3if (i == 10)
4 cout << "Sie haben zehn eingegeben\n";
5else
6 if (i == 11)
7 cout << "Sie haben elf eingegeben\n";
8 else
9 cout << "Sie haben weder zehn noch elf eingegeben\n";
Es können beliebig viele Zweige mit
else if
vorkommen. Allerdings ist es üblich, eine andere Einrückung zu wählen, wenn solche „
if
-
else
-Bäume“ ausgebaut werden:
1int i;
2cin >> i;
3if (i == 10)
4 cout << "Sie haben zehn eingegeben\n";
5else if (i == 11)
6 cout << "Sie haben elf eingegeben\n";
7else
8 cout << "Sie haben weder zehn noch elf eingegeben\n";
Außerdem ist es zu empfehlen, auch bei einer Anweisung einen Anweisungsblock zu benutzen. Letztlich ist die Funktionalität immer die gleiche, aber solche Blöcke erhöhen die Übersichtlichkeit und wenn Sie später mehrere Anweisungen, statt nur einer angeben möchten, brauchen Sie sich um etwaige Klammern keine Gedanken zu machen, weil sie sowieso schon vorhanden sind.
1int i;
2cin >> i;
3if (i == 10) {
4 cout << "Sie haben zehn eingegeben\n";
5} else if(i == 11) {
6 cout << "Sie haben elf eingegeben\n";
7} else {
8 cout << "Sie haben weder zehn noch elf eingegeben\n";
9}
Sie werden für die Positionierung der Klammern übrigens auch oft auf eine andere Variante treffen:
1int i;
2cin >> i;
3if (i == 10)
4{
5 cout << "Sie haben zehn eingegeben\n";
6}
7else
8{
9 if (i == 11)
10 {
11 cout << "Sie haben elf eingegeben\n";
12 }
13 else
14 {
15 cout << "Sie haben weder zehn noch elf eingegeben\n";
16 }
17}
Einige Programmierer finden dies übersichtlicher, für dieses Buch wurde jedoch die Variante mit den öffnenden Klammern ohne Extrazeile verwendet. Das hat den Vorteil, dass weniger Platz benötigt wird und da die Einrückung ohnehin die Zugehörigkeit andeutet, ist eine zusätzliche Kennzeichnung nicht unbedingt nötig.
Die Einrückung von Quelltextzeilen hat für den Compiler übrigens keine Bedeutung. Sie ist lediglich eine grafische Darstellungshilfe für den Programmierer. Auch die in diesem Buch gewählte Einrückungstiefe von vier Leerzeichen ist optional, viele Programmierer verwenden etwa nur zwei Leerzeichen. Andere hingegen sind davon überzeugt, dass acht die ideale Wahl ist. Aber egal, wofür Sie sich entscheiden, wichtig ist, dass Sie Ihren Stil einhalten und nicht ständig ihren Stil wechseln. Das verwirrt nicht nur, sondern sieht auch nicht schön aus.
Wenn es Sie nicht stört, in Ihrem Texteditor Tabulatorzeichen und Leerzeichen anzeigen zu lassen, dann sollten Sie für die Einrückung Tabulatorzeichen verwenden und für alles hinter der normalen Einrückung (etwa den Abstand bis zum Kommentar) Leerzeichen. Das hat den Vorteil, dass Sie die Einrückungstiefe jederzeit ändern können, indem Sie angeben wie viele Leerzeichen einem Tabulatorzeichen entsprechen.
Nachteil: Wenn Sie den Quelltext in verschiedenen Editoren bearbeiten oder weitergeben, muss in jedem Editor eingestellt werden, was die Tabulator-Breite sein soll. Beim Verwenden von Leerzeichen bleibt die Einrückung immer gleich, auch wenn die Tabulatorbreite verschieden eingestellt sein sollte.
Vergleichsoperatoren[Bearbeiten]
Im obigen Beispiel kam schon der Vergleichsoperator
==
zum Einsatz. In C++ gibt es insgesamt sechs Vergleichsoperatoren. Sie liefern jeweils den Wert
true
, wenn die beiden Operanden (die links und rechts des Operators stehen) dem Vergleichskriterium genügen, ansonsten den Wert
false
.
==
|
identisch |
<=
|
ist kleiner (oder) gleich |
>=
|
ist größer (oder) gleich |
<
|
ist kleiner |
>
|
ist größer |
!=
|
ist ungleich |
==
=
if
Problem-Beispiel:
Die „Bedingung“ weist den Wert vonb
a
a = 8
if
8
true
=
==
!=
=!
=
!
- – nicht gleich
!=
- – gleich nicht
=!
Logische Operatoren[Bearbeiten]
Mit logischen Operatoren können Sie mehrere Bedingungen zu einem Ausdruck verknüpfen. C++ bietet folgende Möglichkeiten:
!
|
Logisches Nicht | Resultat wahr, wenn der Operand falsch ist |
&&
|
Logisches Und | Resultat wahr, wenn beide Operanden wahr sind |
||
|
Logisches Oder | Resultat wahr, wenn mindestens ein Operand wahr ist (inclusive-or) |
Die Operatoren lassen sich übersichtlich mit Wahrheitstafeln beschreiben (bei der hier gewählten Darstellung ist jede Spalte für sich zu lesen):
Logisches Und (&&
| ||||
---|---|---|---|---|
a
|
true
|
true
|
false
|
false
|
b
|
true
|
false
|
true
|
false
|
a && b
|
true
|
false
|
false
|
false
|
Beispiel für die dritte Spalte: Mit a = false
und b = true
gilt a && b -> false
.
Logisches Oder (||
| ||||
---|---|---|---|---|
a
|
true
|
true
|
false
|
false
|
b
|
true
|
false
|
true
|
false
|
a || b
|
true
|
true
|
true
|
false
|
Logisches Nicht (!
| ||
---|---|---|
a
|
true
|
false
|
!a
|
false
|
true
|
Beispiel:
Aus Gründen der Lesbarkeit sollten Vergleichsausdrücke grundsätzlich von Klammern umgeben sein. Der obige Code würde folglich so aussehen:
Sowohl beim
&&
-Operatoren (Logik-und) als auch beim
||
-Operator (Logik-oder) werden die Teilausdrücke von links nach rechts bewertet, und zwar nur so lange, bis das Resultat feststeht. Wenn z. B. bei einer
&&
-Verknüpfung
A && B && C
schon die erste Bedingung 'A' falsch ist, werden 'B' und 'C' gar nicht mehr untersucht, da bei
&&
ja alle Bedingungen
true
sein müssen. Der Rückgabewert der beiden Operatoren ist vom Typ
bool
.
Gelegentlich ist daher anzutreffen:
1if ( (variable_ist_gueltig) && (variable_erfuellt_zusaetzliche_detailbedingung) ) { /* mache etwas */ }
Ob die Variable die Detailbedingung erfüllt, kann nur geprüft werden, wenn sie einen gültigen Wert enthält. Die erste Bedingung auf Gültigkeit schützt somit die nachfolgende davor, mit ungültigen Werten arbeiten zu müssen.
&&
||
1int i = 10, j = 20;
2// Erwartete Reihenfolge ((((i == 10) || (j == 20)) && (j == 20)) && (i == 5))
3// Tatsächliche Reihenfolge ((i == 10) || (((j == 20) && (j == 20)) && (i == 5)))
4if (i == 10 || j == 20 && j == 20 && i == 5) {
5 cout << "i ist Zehn und fünf oder (j ist Zwanzig und i fünf)!\n";
6} else {
7 cout << "i ist nicht Zehn oder (j ist Zwanzig oder i nicht fünf)!\n";
8}
1i ist Zehn und fünf oder (j ist Zwanzig und i fünf)!
((i == 10) || (((j == 20) && (j == 20)) && (i == 5)))
&&
||
Hinweis für fortgeschrittene Leser: Beachten Sie bitte, dass für überladende Operatoren andere Regeln gelten. Alle diejenigen, die noch nicht wissen, was überladende Operatoren sind, brauchen sich um diesen Hinweis (noch) nicht zu kümmern.
Bedingter Ausdruck[Bearbeiten]
Häufig werden Verzweigungen eingesetzt, um abhängig vom Wert eines Ausdrucks eine Zuweisung vorzunehmen. Das können Sie mit dem Auswahloperator
? ... : ...
auch einfacher formulieren:
Grafisch sieht das so aus:
Der Variablen
min
wird der kleinere, der beiden Werte
a
und
b
zugewiesen. Analog zum Verhalten der logischen Operatoren wird nur derjenige „Zweig“ bewertet, der nach Auswertung der Bedingung (
a < b
) tatsächlich ausgeführt wird.
Der Bedingungsoperator kann auch wie folgt verwendet werden:
Im Gegensatz zur
if...else
-Anweisung ist es hier aber nicht möglich, in Abhängigkeit zu einer Bedingung, nur eine Anweisung auszugeben, indem man die
else
-Anweisung einfach weg lässt:
Das liegt daran, dass der Bedingungsoperator
?:
keine Kontrollstruktur im eigentlichen Sinne ist. Vielmehr wird mit
(a) ? make(b) : make(c);
ein Ausdruck „berechnet“, der einen Wert aufweisen muss, während sich die
if
-Anweisung logisch in einen "Tu-nichts-Pfad" auflösen kann.