if-Verzweigung
Syntax
Die if-Verzweigung wird eingesetzt, wenn in Abhängigkeit von einer Bedingung unterschiedliche Anweisungen auszuführen sind. Sie hat folgende Syntax:
if ([INIT;] BEDINGUNG)
ANWEISUNG1; // if-Zweig
[else
ANWEISUNG2;] // else-Zweig
INIT ist ein optionaler Initialisierungsausdruck und BEDINGUNG ein beliebiger Ausdruck, der entweder ein ganzzahliges oder ein boolsches Ergebnis liefert. In der Regel ist BEDINGUNG ein Vergleichs- oder Logikausdruck.
Ergibt die Auswertung der Bedingung true (oder einen Wert ungleich 0), wird ANWEISUNG1 ausgeführt und ansonsten die ANWEISUNG2.
#include <print>
int main ()
{
int var = 10;
// Ausdruck mit logischem Vergleich
if (var == 10) // Falls var gleich 10
var = 0; // var auf 0 setzen
else // sonst
var++; // var inkrementieren
//Ausdruck mit ganzzahligem Vergleich
if (var) // Falls var ungleich 0 (=true!)
std::println("var ungleich Null");
else // sonst
std::println("var gleich Null");
}
var gleich Null
Nach der Klammer der if-Abfrage steht kein Semikolon. Wird hier ein Semikolon gesetzt, gilt dies als leere Anweisung, d.h. bei erfüllter Bedingung wird nichts ausgeführt!
Der else-Zweig ist optional. Ist er nicht vorhanden und die Auswertung des Ausdrucks ergibt false, wird mit der nächsten Anweisung nach dem if-Zweig fortgefahren. Im nachfolgenden Beispiel wird die Variable var nur dekrementiert, wenn deren Inhalt größer 0 ist.
#include <print>
int main ()
{
int var = 10;
if (var > 0)
var--;
std::println("var: {}\n",var);
}
var: 9
Sehen Sie sich einmal die folgenden if-Anweisungen an:
if (var == 10)
...
if (var = 10)
...
Beide Anweisungen sind syntaktisch korrekt! Im ersten Fall wird die Variable var mit dem Wert 10 verglichen. Im zweiten Fall wird der Variable var der Wert 10 zugewiesen und das Ergebnis der Zuweisung ausgewertet, welches immer true ist.
Auszuführende Anweisungen
Standardmäßig folgt auf ein if oder else nur eine Anweisung. Sollen mehrere Anweisungen ausgeführt werden, sind sie in einen Block {...} einzuschließen. Dabei sollte auf eine saubere Formatierung geachtet werden, damit das Programm übersichtlich bleibt.
#include <print>
#include <iostream>
int main()
{
short var;
// Datum einlesen
// Im Fehlerfall Eingabestream zuruecksetzen
if (std::cin >> var; std::cin.fail())
{
// Fehler löschen und restl. Eingabe verwerfen
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(),'\n');
}
else
std::cout << std::format("Eingabe war {}\n",var);
}
Innerhalb eines if- oder else-Zweigs sind alle Anweisungen zulässig. So können in einem Zweig weitere if-Anweisungen folgen oder Variablen definiert werden. Diese Variablen sind dann nur innerhalb des Zweigs gültig.
Übrigens: Im obigen Beispiel ist die Anweisung std::cin >> var; der Initialisierungsausdruck INIT.
Mehrere Bedingungen
Eine if-Anweisung kann mehrere Bedingungen enthalten, die mit logischen Operatoren verknüpft werden.
#include <print>
int main()
{
int var = 10;
int count = 0;
// Hier müssen beide Bedingungen erfüllt sein
if ((var == 10) && (count != 0))
std::println("var==10 UND count != 0");
// Hier genügt es, wenn eine Bedingung erfüllt ist
if ((var == 10) || (count != 0))
std::println("var==10 ODER count != 0");
}
var==10 ODER count != 0
Die Klammern um die einzelnen Bedingungen sind nicht vorgeschrieben, aber dennoch empfehlenswert, damit es keine bösen Überraschungen in Bezug auf die Reihenfolge der Auswertung der einzelnen Operatoren gibt.
Die Anweisung
if ((AUSDRUCK1) & (AUSDRUCK2))
...
ist syntaktisch korrekt und erzeugt keinen Fehler beim Übersetzen des Programms. Hier werden die beiden Ausdrücke bitweise verundet und nicht logisch (was vermutlich erfolgen sollte).
constexpr if-Anweisung
Mithilfe der constexpr if-Anweisung können alternativ zu übersetzende Anweisungen in Abhängigkeit von einer Bedingung definiert werden.
if constexpr ([INIT;] BEDINGUNG)
ANWEISUNG1; // if-Zweig
[else
ANWEISUNG2;] // else-Zweig
Die Bedingung muss ein konstanter Ausdruck sein, der ein boolsches Ergebnis liefert. Im nachfolgenden Beispiel werden je nach Wert der Konstanten DEBUG_LEVEL verschiedene Ausgaben zur Verfolgung des Programmablaufs ausgegeben werden.
#include <print>
const int DEBUG_LEVEL = 1;
int main()
{
if constexpr (DEBUG_LEVEL == 1)
{
std::println("Einfache Debug-Ausgabe.");
}
else
if constexpr (DEBUG_LEVEL == 2)
{
std::println("Detaillierte Debug-Ausgabe!");
}
}
Einfache Debug-Ausgabe.
Enthält die Konstante DEBUG_LEVEL den Wert '1', erfolgt eine einfache Debug-Ausgabe und für den Fall, dass sie den Wert '2' enthält, eine detailliertere Debug-Ausgabe. In allen anderen Fällen erfolgt keine Ausgabe.
Wie erwähnt, erfolgt die Auswertung der Bedingung nicht wie bei der 'normalen' if-Abfrage zur Laufzeit des Programmes, sondern zur Compilezeit. D.h., der Compiler erzeugt je nach Inhalt der Konstanten DEBUG_LEVEL keinen Code oder den entsprechenden Code für eine einfache oder detaillierte Debug-Ausgabe.
Dieses Beispiel ist zwar nicht ganz praxisgerecht, jedoch zeigt es die Wirkung der constexpr if-Anweisung. In der Regel wird die constexpr if-Anweisung in Templates eingesetzt, um Bedingungen abzuprüfen. Mehr zu Templates später.
Bedingungsoperator und goto
Eine abgewandelte Form der if-Anweisung stellt der Bedingungsoperator dar, der folgende Syntax besitzt:
erg = (BEDINGUNG) ? AUSDRUCK1 : AUSDRUCK2;
Liefert die Auswertung von BEDINGUNG als Ergebnis true, wird AUSDRUCK1 ausgewertet und das Ergebnis der Variablen erg zugewiesen. Liefert BEDINGUNG dagegen false, wird das Ergebnis von AUSDRUCK2 der Variablen erg zugewiesen.
Das folgende Beispiel zeigt, wie mithilfe dieser Anweisung der Absolutbetrag einer Variablen berechnet werden kann. Außerdem ist eine weitere, etwas unkonventionellere, Anwendung des Bedingungsoperators aufgeführt, die je nach Zustand der Variablen light entweder den Text Das Licht ist an oder Das Licht ist aus ausgibt.
#include <print>
int main()
{
int var1 = -3, var2;
bool light = false;
// Absolutbetrag von var1 in var2 ablegen
var2 = (var1>=0) ? var1 : -var1;
// Alternative Schreibweise:
// if (var1>=0)
// var2 = var1;
// else
// var2 = -var1;
// Weiteres (unkonventionelles) Beispiel:
std::println("Das Licht ist {}",((light)? "an" : "aus"));
}
Das Licht ist aus
Der Vollständigkeit halber sei an dieser Stelle erwähnt, dass es auch eine goto-Anweisung gibt. Sie hat folgende Syntax:
goto label; // Sprung nach label
...
label: // Das Sprungziel
Das Sprungziel muss ein eindeutiger Namen sein und mit einem Doppelpunkt abgeschlossen werden. Für die Position des Sprungziels gibt es eine Reihe von Einschränkungen, die hier nicht weiter betrachtet werden. Ein 'sauberes' Programm kommt ohne goto aus.
Übungen
if_01
Erstellen Sie ein Programm, das Zufallszahlen erzeugt und dabei zählt, wie viele dieser erzeugten Zahlen gerade bzw. ungerade sind.
Bei ungeraden Zahlen ist das Bit 0 gesetzt (1=b00000001, 3=b00000011, 5= b00000101, ...) und bei geraden Zahlen nicht.
Die Anzahl der zu erzeugenden Zufallszahlen ist über eine benannte Konstante festzulegen. Starten Sie mit 1000 Zufallszahlen. Da bisher keine Schleifen behandelt wurden, dürfen Sie ausnahmsweise die goto-Anweisung verwenden, um die Zufallszahlen zu erzeugen.
Für die Erzeugung der Zufallszahlen werden 3 neue Funktionen benötigt.
int std::rand();
time_t std::time(time_t *timer);
void std::srand(unsigned int seed);
rand() liefert eine Integer-Zufallszahl zwischen 0 und RAND_MAX. RAND_MAX ist eine compilerabhängige Konstante, deren Wert z.B. beim MinGW-Compiler 0x7FFFFFFF beträgt.
Da rand() keine echten Zufallszahlen liefert, sondern nach einem Algorithmus verteilte Zahlen, ist zuerst mittels time() die aktuelle Uhrzeit auszulesen. time() liefert die seit dem 01.01.1970, 00:00 Uhr vergangene Anzahl von Sekunden zurück. Für den Parameter timer ist in der Übung der nullptr einzusetzen. Der von time() zurückgelieferte Wert ist in einen unsigned int-Wert umzuwandeln.
Anschließend ist die Funktion srand() aufzurufen, die den Zufallszahlen-Algorithmus initialisiert. Wird srand() immer mit dem gleichen Wert für seed aufgerufen, werden immer die gleichen Zufallszahlenreihen durch rand() generiert. Übergeben Sie innerhalb der Parameterklammer an srand() den von time() zurückgelieferten konvertierten Wert.
Wenn Sie die Funktionen rand() und srand() verwenden, ist die Header-Datei cstdlib einzubinden und für die Funktion time() die Header-Datei ctime. Alle Funktionen liegen ebenfalls im Namensraum std!
Es gibt für die Erzeugung von Zufallszahlen in der Standardbibliothek mehrere alternative Zufallszahlen-Generatoren und verschiedene Klassen, um eine definierte Verteilung der Zufallszahlen zu erreichen. Wenn Sie mehr darüber erfahren wollen, suchen im Internet nach dem Stichwort "C++ random".
Anzahl der geraden Zahlen: 490
Anzahl der ungeraden Zahlen: 510
if_02
Es ist ein Taschenrechner-Programm zu erstellen, das zwei Zahlen und einen Operator nach folgender Syntax einliest:
Operand1 Operator Operand2
Als Operator sind nur +, -, * und / erlaubt. Wird ein davon abweichender Operator eingegeben, ist eine Fehlermeldung auszugeben. Die Operanden sind als short-Werte einzulesen.
Bei korrekter Eingabe ist das Ergebnis der eingegebenen Formel als Integer-Datum zu berechnen und auszugeben.
Formel nach folgender Syntax eingeben:
Operand1 Operator Operand2
Operator kann sein: + - * /
Formel ? 10 / 3
Ergebnis: 3