Kapitel 2 - Bedingte Anweisungen und Integer-Typen

2.1 Eingaben
2.2 Die if -Anweisung
2.3 Die if ... else – Anweisung
2.4 Relationale Operatoren
2.5 Zusammengesetzte Anweisungen
2.6 Schlüsselwörter
2.7 Zusammengesetzte Bedingungen
2.8 Boolsche Ausdrücke
2.9 Verschachtelte bedingte Anweisungen
2.10 Die switch – Anweisung
2.11 Der Bedingungsoperator
2.12 Gültigkeitsbereich (SCOPE)
2.13 Aufzählungstypen
2.14 Integer-Typumwandlungen

Beispiel 2.1: Integer-Eingabe
Beispiel 2.2 Zeicheneingabe
Beispiel 2.3: Mehrere Eingaben in den gleichen Strom
Beispiel 2.4 Prüfung auf Teilbarkeit
Beispiel 2.5 Prüfung auf Teilbarkeit mit else
Beispiel 2.6 Der Integer-Ausdruck (n%d) wird nun selbst als Ausdruck eingesetzt
Beispiel 2.7 Das Maximum zweier Integer-Zahlen ermitteln
Beispiel 2.8 Ermittlung des Maximums dreier Zahlen
Beispiel 2.9 Sortieren
Beispiel 2.10: Noch einmal das Maximum dreier Zahlen
Beispiel 2.11: Benutzerfreundliche Eingabe
Beispiel 2.12 Kurzschluss in einer Bedingung
Beispiel 2.13 Überprüfung auf Integer-Teilbarkeit mit Hilfe von verschachtelten Bedingungen
Beispiel 2.14 Noch einmal das Maximum dreier Zahlen
Beispiel 2.15: Auswertung des amerikanischen Schulsystems
Beispiel 2.16 Noch einmal Schulsystem (switch - case)
Beispiel 2.17: Verschachtelte und parallele Gültigkeitsbereiche
Beispiel 2.18: Integer Umwandlung
Beispiel 2.19: Integer Umwandlung

Die Programme, die Ihnen im Kapitel 1 vorgestellt wurden, werden alle sequentiell ausgeführt:
Anweisungen mit Bedingungen ermöglichen flexiblere Programme, in denen die Ausführung einiger Anweisungen von Bedingungen abhängt, die sich während der Programmausführung ändern.

Dieses Kapitel zeigt auch, wie sich einfache Eingaben in ihr Programm integrieren lassen

2.1 Eingaben

In C++ werden Eingaben anlog wie Ausgaben behandelt.Aber anstelle von Daten, die in den Ausgabestrom cout fliessen, handelt es sich hier nun um Daten, die vom Eingabestrom cin in das Programm einfliessen. Der Name cin steht für “console input“.

Beispiel 2.1: Integer-Eingabe

#include <iostream.h>

int main()
{
int age;

cout << “Wie alt sind Sie: “

cin >> age;

cout << “In 10 Jahren werden Sie “ << age + 10 << “ Jahre alt sein\n“;

return 0;
}



Wie alt sind Sie: 35
In 10 Jahren werden 45 Jahre alt sein


Das Symbol >> ist der Übernahmeoperator (extraction operator), der auch Eingabeoperator genannt wird. Es wird üblicherweise zusammen mit dem cin- Eingabestrom eingesetzt, bei dem es sich in der Regel um die Tastatur des Anwenders handelt.

Entsprechend stoppt das System bei der Ausführung der Anweisung

cin >> age;


Und wartet auf eine Eingabe. Das Eingabeobjekt cin wird analog wie das Ausgabeobjekt cout verwendet. Beide sind C++ Stream-Objekte, die wie eine Röhre arbeiten, durch die Bytes fließen.

Die Bytes fliessen durch das cin- Objekt in das Programm und durch das cout- Objekt hinaus. Beispiel 2.2 Zeicheneingabe

// Programm redet Sie mit Ihren Initialen an.

#include <iostream.h>

int main()
{
char first, last;

cout << “Geben Sie Ihre Initialen ein: \n“;

cout << “\tVorname: “;

cin >> first;

cout << “\tNachname: “;

cin >> last;

cout << “Hallo “ << first << “. “ << last << “. “ endl;

return 0;
}


Geben Sie Ihre Initialen ein:
Vorname: T
Nachname: G
Hallo T. G.

Dieses Beispiel verdeutlicht eine standardisierte Möglichkeit zur Formatierung von Eingaben. Beispiel 2.3 Mehrere Eingaben in den gleichen Strom

Mit ein und derselben Eingabeanweisung lassen sich mehrere Variablen einlesen: // Programm redet Sie mit Ihren Initialen an.

#include <iostream.h>

int main()
{
char first, last;

cout << “Geben Sie Ihre erste und zweite Initiale ein: \n“;

cin >> first >> last;

cout << “Hallo “ << first << “. “ << last << “. “ endl;

return 0;
}


Geben Sie Ihre Initialen ein: T G
Hallo T. G.


Hier wird gezeigt, dass der Eingabestrom cin die Objekte von links nach rechts einliest, so dass die Variable ganz links zuerst eingelesen wird.

Da es sich beim Typ char um einen Integer-Typ handelt, ignoriert cin beim Lesen der Eingabe alle führenden Whitespaces ( alle nicht druckenden Zeichen). Daher könnte die Eingabe bei diesem Beispiel auch so aussehen:

Geben Sie Ihre erste und zweite Initiale ein:      T G
Hallo T. G.



Beachten Sie bitte, dass dadurch die Eingabe von Leerzeichen bei der Verwendung des Eingabeoperators >> unmöglich ist.

2.2 Die if -Anweisung

Die if -Anweisung ermöglicht die bedingende Ausführung.

Ihre Syntax lautet:
if ( bedingung ) anweisung;

Was verbirgt sich hinter bedingung und anweisung ?

Dabei ist bedingung ein Integer-Ausdruck und anweisung eine beliebig auszuführende Anweisung.anweisung wird immer nur dann ausgeführt, wenn bedingung einen Wert ungleich null hat. (Immer wenn ein Integer- Ausdruck als Bedingung ausgewertet wird, werden Werte ungleich null als wahr bzw. als true und einen Wert von null als falsch bzw. false interpretiert) Beachten Sie die Klammern, die um die Bedingung herum gesetzt werden müssen.

Beispiel 2.4 Prüfung auf Teilbarkeit

// Prüfung auf Teilbarkeit mit Hilfe der Modulo-Funktion

#include <iostream.h>

int main()
{
int n, d;

cout << “Geben Sie zwei Integer-Werte ein: \n“;

cin >> n >> d;

if (n%d == 0) cout << n << “ ist teilbar durch “ << d << endl;

return 0;
}


Geben Sie zwei Integer-Werte ein: 24 6
24 ist teilbar durch 6


Dieses Programm liest zwei Integer-Werte ein und prüft dann den Wert des Restes n%d. Bei diesem Programmlauf ist der Wert von 24 % 6 gleich 0, was bedeutet, dass 24 durch 6 teilbar ist.

Welchen Nachteil hat das letzte Beispielprogramm ?

Geben Sie zwei Integer-Werte ein: 24 5


Zur Ausführung einer alternativen Anweisung – wenn die Bedingung null ergibt - brauchen wir die if ... else Anweisung

2.3 Die if ... else – Anweisung

Die if ... else – Anweisung führt eine von zwei alternativen Anweisungen Ihre Syntax lautet:
if (bedingung) anweisung1;


else anweisung2;


Dabei ist bedingung ein Integer-Ausdruck und anweisung1 und anweisung2 sind beliebig auszuführende Anweisung.anweisung1 wird immer nur dann ausgeführt, wenn bedingung einen Wert ungleich null ergibt, und anweisung2 wird ausgeführt, wenn die bedingung den Wert null hat.

Beispiel 2.5 Prüfung auf Teilbarkeit mit else

// Erweiterung des Beispieles 2.4 mit einer else-Klausel

#include <iostream.h>

int main()
{
int n, d;

cout << “Geben Sie zwei Integer-Werte ein: \n“;

cin >> n >> d;

if (n%d == 0) cout << n << “ ist teilbar durch “ << d << endl;

else cout << n << “ ist nicht teilbar durch “ << d << endl;

return 0;
}


Geben Sie zwei Integer-Werte ein: 24 5
24 ist nicht teilbar durch 5


Da 24 % 5 = = 4 ist, ist die Bedingung ( n%d= = 0) falsch (false) und die else-Klausel wird ausgeführt.

Eine Bedingung wie (n%d = = 0) ist ein Ausdruck, dessen Wert entweder als falsch oder als wahr interpretiert wird. In C++ handelt es sich bei diesen beiden Werten um Integer – Zahlen: Aufgrund dieser Entsprechung können gewöhnlich Integer-Ausdrücke Bedingungen darstellen. Insbesondere kann der Integer-Ausdruck (n%d) selbst als Bedingung eingesetzt werden. Er ist genau dann ungleich null (also “wahr“), wenn n nicht durch d teilbar ist, so dass wir bei seinem Einsatz die beiden Ausgabenanweisungen vertauschen müssen, damit das vorherige Beispiel sinnvolle Ergebnisse liefert.

Beispiel 2.6 Der Integer-Ausdruck (n%d) wird nun selbst als Ausdruck eingesetzt

// Erweiterung des Beispieles 2.5 mit einer else-Klausel

#include <iostream.h>

int main()
{
int n, d;

cout << “Geben Sie zwei Integer-Werte ein: \n“;

cin >> n >> d;

// Es folgt die Auswertung mittels if-Anweisung

if (n%d) cout << n << “ ist nicht teilbar durch “ << d << endl;

else cout << n << “ ist teilbar durch “ << d << endl;

return 0;
}


Geben Sie zwei Integer-Werte ein: 8 3
8 ist nicht teilbar durch 3


2.4 Relationale Operatoren

Das nächste Beispiel verwendet eine Bedingung der intuitiveren Form:

Beispiel 2.7 Das Maximum zweier Integer-Zahlen ermitteln

// Dieses Programm gibt die größere der beiden eingegebenen Integer Zahlen aus

#include <iostream.h>

int main()
{
int m, n;

cout << “Geben Sie zwei Integer-Werte ein: \n“;

cin >> m >> n;

// Es folgt die Auswertung mittels if-Anweisung

if (m > n) cout << m endl;

else cout << n << endl;

return 0;
}


Geben Sie zwei Integer-Werte ein: 22 55
55


In diesem Programm ist (m>n) die Bedingung.


Daher wird n genau dann ausgegeben, wenn es größer als n ist.

Das Symbol > ist einer der relationalen Operatoren.

Dieser Operator wird relational genannt, weil er auswertet, wie die beiden Seiten zueinander in Relation stehen, so dass die Relation 55 < 22 falsch ist. Das Symbol wird Operator genannt, weil es in Kombination mit Ausdrücken einen Wert erzeugt. Wenn > zum Beispiel mit 22 und 55 in der Form 22 > 55 kombiniert wird, erzeugt es den Integer-Wert 0, der “falsch“ bedeutet.

Es gibt sechs relationale Operatoren:
< ist kleiner als
<= ist kleiner oder gleich mit
= = ist gleich mit
> ist grösser als
>= ist grösser oder gleich mit
!= ist ungleich mit


Beachten Sie bitte, dass für die Prüfung auf Gleichheit das doppelte Gleichheitszeichen eingesetzt werden muss. Ein verbreiteter Fehler unter unerfahrenen C++ Programmierern ist die Verwendung des einfachen Gleichheitszeichens =. Dieser Fehler ist schwer zu entdecken, weil er die Syntaxregeln von C++ nicht verletzt.

Beispiel 2.8 Ermittlung des Maximums dreier Zahlen

// Dieses Programm gibt die größte der drei eingegebenen Integer Zahlen aus

#include <iostream.h>

int main()
{
int m, n, o;

cout << “Geben Sie drei Integer-Werte ein: \n“;

cin >> m >> n >> o;

int max = m;

// Es folgt die Auswertung mittels if-Anweisung

if (n > max) max = n;

if (o > max) max = o;

cout << “Das Maximum der drei Zahlen ist “ << max << endl;

return 0;
}


Geben Sie drei Integer-Werte ein: 22 55 77
Das Maximum der drei Zahlen ist: 77


2.5 Zusammengesetzte Anweisungen

Eine zusammengesetzte Anweisung ist eine Folge von Anweisungen, die wie eine einzelne Anweisung behandelt werden. C++ erkennt zusammengesetzte Anweisungen dadurch, dass sie in geschweiften Klammern eingeschlossen werden.

Das nächste Beispiel enthält eine solche zusammengesetzte Anweisung:

{

int temp = x ;

x = y ;

y = temp;

}


Die Klammern um diese drei Anweisungen bilden einen Block. Als zusammengesetzte Anweisung stellt dieser wieder selbst eine Anweisung dar, die sich überall dort verwenden lässt, wo beliebige andere Anweisungen stehen dürfen.

Beachten Sie, dass das gesamte C++ Programm, - alles was auf main() folgt – eine zusammengesetzte Anweisung bildet.

Beispiel 2.9 Sortieren

// Dieses Programm liest zwei Integer-Werte ein und gibt sie dann in aufsteigender Reihenfolge aus

#include <iostream.h>

int main()
{
int x, y;

cout << “Geben Sie zwei Integer-Werte ein: \n“;

cin >> x >> y ;

// Es folgt die Auswertung mittels if-Anweisung

if (x > y) {

int temp = x;

x = y;

y = temp;

}

cout << x << “ist kleiner als “ << y << endl;

return 0;
}


Geben Sie zwei Integer-Zahlen ein: 4 7
4 ist kleiner als 7

Die Folge einer derartigen Verwendung der zusammengesetzten Anweisung in der if – Anweisung ist, dass alle drei Anweisungen innerhalb des Blockes ausgeführt werden, wenn die Bedingung wahr ist.

Diese drei speziellen Anweisungen bilden einen

swap

d. h. sie vertauschen die Werte von x und y.

Dieses Konstrukt wird häufig in Programmen zum Sortieren von Daten verwendet. Ein solcher Tausch erfordert drei einzelne Schritte, sowie einen temporären Speicherplatz, der im Beispiel temp genannt wird.

Beachten Sie, dass die Variable temp im Block deklariert wird. Dadurch ist sie lokal zum Block, so dass sie nur während der Ausführung des Blockes existiert. Wenn x <= y und die Bedingung falsch ist, wird temp überhaupt nicht erzeugt. Dies ist ein gutes Beispiel für die Verwendung lokaler Objekte, die nur bei Bedarf erzeugt werden.

Bei dem Beispiel 2.9 handelt es sich nicht um die effizienteste Möglichkeit zur Lösung des Problems.
{

if (x < y) cout << x << “ ist kleiner als “ << y <<< endl;

else cout << y << “ ist kleiner als “ << x << endl ;

}


Der Zweck des Beispiels ist es, zusammengesetzte Anweisungen und lokale Variablendeklarationen zu verdeutlichen.

2.6 Schlüsselwörter

Ein Schlüsselwort in einer Programmiersprache ist ein Wort, C++ verfügt über 48 Schlüsselwörter

asmcontinuefloatnewsignettry
autodefaultforoperatorsizeoftypedef
breakdeletefriendprivatestateunion
casedo gotoprotectedstructunsigned
catchdoubleifpublicswitchvirtuell
charelseinlineregistertemplatevoid
classenumintreturnthisvolatile
constexternlongshortthrowwhile


Schlüsselwörtern wie if und else begegnet man in fast jeder Programmiersprache. Andere Schlüsselwörter wie z. B. catch und friend gibt es nur in C++.

Die 48 Schlüsselwörter von C++ umfassen alle 32 Schlüsselwörter der Sprache C.

Es gibt zwei Arten von Schlüsselwörtern:
In einigen Sprachen werden die Strukturkennzeichner reservierte Wörter und die vordefinierten Namen Standardbezeichner genannt.

2.7 Zusammengesetzte Bedingungen

Bedingungen wie n%d und x>y lassen sich zu zusammengesetzten Bedingungen kombinieren.

Die drei für diesen Zweck verwendeten Operatoren sind && (und bzw. and), || (oder bzw. or) und ! (nicht bzw. not). Sie sind definiert durch:

&& q && q liefert dann 1, wenn sowohl p als auch q den Wert 1 ergeben.
|| p || q liefert dann den Wert 1, wenn q oder p oder beide den Wert 1 ergeben
!p !p liefert 1, wenn p den Wert 0 ergibt


(n % d | | x > y) ist zum Beispiel dann “wahr“, wenn entweder n % d nicht null oder die Bedingung x > y wahr ist (oder beides gilt).

(x > y) ist gleichbedeutend mit x <= y

Die Definition der drei logischen Operatoren erfolgt üblicherweise über die folgenden Wahrheitstabellen:

p q p && q
0 0 0
0 1 0
1 0 0
1 1 1


p q p || q
0 0 0
0 1 1
1 0 1
1 1 1


p !p
0 1
1 0


Beispiel 2.10: Noch einmal das Maximum dreier Zahlen

// Ermittlung des Maximums dreier Zahlen

#include <iostream.h>

int main()
{
int a, b, c;

cout << “Geben Sie drei Integer-Werte ein: \n“;

cin >> a >> b >> c;

// Es folgt die Auswertung mittels if-Anweisung

if (a >= b && a >=b) cout << a << endl;

if (b >= a && b >=c) cout << b << endl;

if (c >= a && c >=b) cout << c << endl;

return 0;
}


Geben Sie drei Integer-Zahlen ein: 4 9 5
9


Das Programm prüft einfach für alle drei Zahlen, welche größer oder gleich als die anderen ist.

Beachten Sie, dass Beispiel 2.10 im Vergleich mit Beispiel 2.8 keine Verbesserung darstellt. Es dient lediglich zur Verdeutlichung des Einsatzes von zusammengesetzten Bedingungen.

Beispiel 2.11: Benutzerfreundliche Eingabe

// Programmablauf hängt von der Eingabe ab.

#include <iostream.h>

int main()
{
char ant;

cout << “Geht es Ihnen gut ? (j/n)“ << endl;

cin >> ant;

if (ant =='J' || ant == 'j')

cout << "Es geht Ihnen gut.\n“;
else

cout << “Es geht Ihnen nicht gut.\n“;
return 0;
}


Geht es Ihnen gut ? (j/n) J
Es geht Ihnen gut.


Hier wird der Anwender zur Antwort aufgefordert und schlägt dabei die Alternativen y und n vor. Dann akzeptiert es aber alle Zeichen und geht davon aus, dass der Anwender immer “nein“ meint, solange nicht “j“ oder “J“ eingegeben wird.

Kurzschluss

Zusammengesetzte Bedingungen, die && und || benutzen, werten den zweiten Teil der Bedingung nicht einmal aus, solange es nicht notwendig ist. Die wird Kurzschluss genannt.

Der Wert des Kurzschlussverfahrens lässt sich am folgenden Beispiel erkennen.

Beispiel 2.12 Kurzschluss in einer Bedingung

// Programm prüft auf Integer-Teilbarkeit

#include <iostream.h>

int main()
{
int n, d;

cout << “Geben Sie zwei positive Integer-Werte ein: \n“;

cin >> n >> d;

// Es folgt die Auswertung mittels if-Anweisung

if ( d > 0 && n%d ==0)

cout << n << “ ist durch “ << d << “ teilbar!“ << endl;

else

cout << n << “ ist nicht durch “ << d << “ teilbar!“ << endl;

return 0;
}


Geben Sie zwei positive Integer-Zahlen ein: 8 2
8 ist durch 2 teilbar


Geben Sie zwei positive Integer-Zahlen ein: 4 -2
4 ist nicht durch -2 teilbar


2.8 Boolsche Ausdrücke

Ein Boolscher Ausdruck ist eine Bedingung, die entweder wahr (true) oder falsch (false) sein kann.

Im vorherigen Beispiel sind d > 0 und n%d ==0 Boolsche Ausdrücke. Wie wir gesehen haben, erzeugt die Auswertung Boolscher Ausdrücke Integer-Werte.

Der Wert “0“ bedeutet falsch und jeder andere Wert ungleich null bedeutet “wahr“.

Weil alle Werte ungleich Null als “wahr“ interpretiert werden, werden Boolsche Ausdrücke häufig versteckt angewendet. Die Anweisung


if (n) cout << “ n ist nicht Null“;


gibt nur dann n ist nicht Null aus, wenn n ungleich Null ist, weil dann der Boolsche Ausdruck (n) als “wahr“ interpretiert wird.

Hier ein etwas realistischeres Beispiel:

if (n%d) cout << “ n ist nicht ein Vielfaches von d“;


Die Ausgabeanweisung wird genau dann erfüllt, wenn n%d nicht Null ist, und das ist genau dann der Fall, wenn d die Variable n nicht ohne Rest teilt, weil es sich bei n%d um den Rest der Integer-Division handelt.

Die Tatsache, dass Boolsche Ausdrücke in C++ Integer-Werte haben, kann zu einigen überraschenden Anomalien führen. Ein Neuling in der C++ Programmierung könnte zum Beispiel die folgende Zeile schreiben:


if (x >= y >=z) cout << “ max = x“;   // FEHLER


Offensichtlich wollte der Programmierer eigentlich folgendes schreiben:


if (x >= y && y >=z) cout << “ max = x“;   // OK


Das Problem liegt darin ,dass die fehlerhafte Zeile syntaktisch korrekt ist, so dass der Compiler den Fehler nicht abfangen kann. Tatsächlich kann das Programm sogar ablaufen, ohne dass ein Fehler auftritt. Hier handelt es sich um einen Laufzeitfehler der schlimmsten Sorte, weil es keine deutlichen Anzeichen dafür gibt, dass überhaupt irgendetwas falsch ist.

Die Tatsache, dass Boolsche Ausdrücke numerische Werte haben, stellt die Quelle der hier beschriebenen Schwierigkeiten dar.

Nehmen wir an, dass sowohl x als auch y den Wert 0 haben und z den Wert 1 hat.

Der Ausdruck (x >= y >=z) wird von links nach rechts ausgewertet.

Die Moral von der Geschicht’ lautet:

Denken Sie daran, dass Boolsche Ausdrücke numerische Werte haben und dass zusammengesetzte Bedingung knifflig sein können.

Ein weiterer Fehler, der Programmier-Neulingen in C++ häufig unterläuft, ist die versehentliche Verwendung des Gleichheitszeichens = anstelle des beabsichtigten doppelten Gleichheitszeichens = = zum Beispiel:

if ( x = 0) cout << “x = 0“;   // Fehler


Offensichtlich wollte der Programmierer folgendes schreiben:

if ( x == 0) cout << “x = 0“;   // OK


Die fehlerhafte Anweisung weist x zuerst 0 zu. Die Zuweisung hat dann den Wert 0, der falsch bedeutet, so dass die cout -Anweisung nicht ausgeführt wird. Selbst wenn x ursprünglich 0 war, wird nichts ausgegeben.

Schlimmer noch: Wenn x ursprünglich nicht 0 war, wird es versehentlich in 0 geändert!

Wie im vorhergehenden Fehler handelt es sich hier um einen Laufzeitfehler der übelsten Sorte, weil er so schwer aufzuspüren ist.

2.9 Verschachtelte bedingte Anweisungen

Wie zusammengesetzte Anweisung lassen sich auch bedingte Anweisungen anstelle beliebiger anderer Anweisungen verwenden. Daher lassen sich auch bedingte Anweisungen innerhalb anderer Anweisungen einsetzen.

Dies nennt man verschachtelte bedingte Anweisungen.


Die Bedingung aus dem letzten Beispiel ließe sich folgendermaßen gleichbedeutend formulieren:

Beispiel 2.13 Überprüfung auf Integer-Teilbarkeit mit Hilfe von verschachtelten Bedingungen

// Programm prüft auf Integer-Teilbarkeit

#include <iostream.h>

int main()
{
int n, d;

cout << “Geben Sie zwei positive Integer-Werte ein: \n“;

cin >> n >> d;

// Es folgt die Auswertung mittels if-Anweisung

if ( d > 0 )

if ( n % d == 0 )

cout << n << “ ist durch “ << d << “ teilbar!“ << endl;

else

cout << n << “ ist nicht durch “ << d << “ teilbar!“ << endl;

else

cout << n << “ ist nicht durch “ << d << “ teilbar!“ << endl;

return 0;
}


Geben Sie zwei positive Integer-Zahlen ein: 4 -2
4 ist nicht durch -2 teilbar


Hier wird die komplexe Logik durch zusätzliche Einrückungen verdeutlicht. Natürlich ignoriert der Compiler alle Einrückungen und Whitespaces. Beim Parsen der Anweisungen benutzt er die folgende else -Zuordnungsregel:

Ordne das jeweilige else dem letzten allein stehenden if zu.

Beispiel 2.14 Noch einmal das Maximum dreier Zahlen

// Programm prüft auf Integer-Teilbarkeit

#include <iostream.h>

int main()
{
int a, b, c, max;

cout << “Geben Sie drei Integer-Zahlen ein: \n“;

cin >> a >> b >> c;

// Es folgt die Auswertung mittels verschachtelter if-Anweisungen

if ( a > b )

if ( a > c ) max = a;

else max = c;

else

if ( b > c ) max = b;

else max = c;

cout << “ Das Maximum ist “ << endl;

return 0;
}


Geben Sie drei Integer-Zahlen ein: 22 44 66
Das Maximum ist 66


Das Programm ist effizienter als jenes in Beispiel 2.10, weil es nur zwei einfache Bedingungen anstelle dreier zusammengesetzter Bedingungen auswertet. Dem sollte man jedoch geringere Bedeutung beimessen, weil seine Logik komplizierter ist. Hinsichtlich der Wechselwirkung zwischen Effizienz und Einfachheit sollte man der Einfachheit Vorrang einräumen.

Verschachtelte Bedingungen sind von Natur aus kompliziert. Daher ist es besser, sie zu vermeiden. Eine Ausnahme von dieser Regel stellt eine spezielle Variante verschachtelter Bedingungen dar, bei dem jedem außer möglicherweise dem letzten else sofort ein weiteres if folgt.

Dies ist eine beliebte logische Struktur, weil sich auf einfache Weise eine Folge einander ausschließender Alternativen betreibt. Zur Verdeutlichung des logischen Ablaufs richten Programmierer üblicherweise die verschiedenen else if – Ausdrücke – wie im folgenden Beispiel untereinander aus.

Beispiel 2.15: Auswertung des amerikanischen Schulsystems

// Programm prüft auf Integer-Teilbarkeit

#include <iostream.h>

int main()
{
int score;

cout << “Geben Sie Ihr Testergebnis ein: \n“;

cin >> score;

// Es folgt die Auswertung mittels verschachtelter if-Anweisungen

if (score > 100) cout << “Die Punktezahl liegt ausserhalb des Bereichs !“ << endl;

else if (score >= 90) cout << “A“ << endl;

else if (score >= 80) cout << “B“ << endl;

else if (score >= 70) cout << “C“ << endl;

else if (score >= 60) cout << “D“ << endl;

else if (score >= 0) cout << “F“ << endl;

else cout << “Die Punktezahl liegt ausserhalb des Bereichs !“ << endl;

return 0;
}


Geben Sie Ihr Testergebnis ein: 45
F


Geben Sie Ihr Testergebnis ein: 83
B


Geben Sie Ihr Testergebnis ein: -9
Die Punktezahl liegt ausserhalb des Bereichs !


Die Variable score wird, ähnlich wie bei einem Wasserfall, durch eine Reihe von Bedingungen geprüft, bis sich eine Bedingung als wahr erweist oder bis – wie beim letzten Durchlauf – das letzte else erreicht wird.

2.10 Die switch – Anweisung

Folgen sich gegenseitig ausschließende Alternativen, die durch mehrere else – if – Konstrukte dargestellt werden, lassen sich auch mit Hilfe einer switch – Anweisung kodieren.

Ihre Syntax lautet:

switch (ausdruck)

{

case konstante1 : anweisungsFolge1;

case konstante2 : anweisungsFolge2;

..

..

case konstanteN : anweisungsFolgeN;

default: anweisungsfolge;

}


Die switch – Anweisung wertet den Ausdruck aus und sucht dann unter den case – Konstanten nach dessen Wert. Wenn sich dieser Wert unter den aufgeführten konstanten (konstante1 bis konstanteN) wiederfindet, werden die Anweisungen der entsprechenden Anweisungsfolge ausgeführt.

Andernfalls verzweigt das Programm zu default. (Diese Vorgabe ist optional) und der zugehörigen Anweisungsfolge.

Beachten Sie, dass der Wert von Ausdruck einem Integer-Wert angehören muss und dass es sich bei den Konstanten (konstante1 bis konstanteN) um Integer-Konstanten (zu denen auch der char zählt) handeln muss.

Beispiel 2.16 Noch einmal Schulsystem (switch - case)

Das Programm liefert (fast) die selben Ergebnisse wie jenes aus Beispiel 2.16

#include <iostream.h>

int main()
{
int score;

cout << “Geben Sie Ihr Testergebnis ein: \n“;

cin >> score;

// Es folgt die Auswertung mittels verschachtelter if-Anweisungen

switch (score/10)

{

case 10:

case 9 : cout << “A“ << endl; break;

case 8 : cout << “B“ << endl; break;

case 7 : cout << “C“ << endl; break;

case 6 : cout << “D“ << endl; break;

case 5:

case 4:

case 3:

case 2:

case 1:

case 0: cout << “F“ << endl; break;

default: cout << "Die Punktezahl liegt ausserhalb des Bereichs !" << endl;

}

return 0;
}


Geben Sie Ihr Testergebnis ein: 45
F


Geben Sie Ihr Testergebnis ein: 83
B


Geben Sie Ihr Testergebnis ein: -9
Die Punktezahl liegt ausserhalb des Bereichs !


Dazu zählen alle case – Label bis hinab zu 0 bis zur nächsten break – Anweisung.

Dieses Phänomen nennt man Durchfallen (fall through)

2.11 Der Bedingungsoperator

C++ stellt eine abkürzende Form für eine spezielle Variante der if .. else Anweisung zur Verfügung.

Man nennt sie den Bedingungsoperator und verwendet das ? und die : - Symbole in einem speziellen ternären Format:

Bedingung ? ausdruck1 : ausdruck2

Wie bei allen anderen Operatoren werden auch hier die angegebenen Ausdrücke kombiniert, um einen Wert zu erzeugen. Der erzeugte Wert ist entweder jener vom ausdruck1 oder jener vom ausdruck2, je nachdem, ob die Bedingung wahr oder falsch ist.

Die Zuweisung

min = x < y ? x : y

weist zum Beispiel min den Wert von x zu, wenn x < y ; andernfalls weist es min den Wert von y zu.

Der Bedingungsoperator wird im Allgemeinen nur dann verwendet, wenn sowohl die Bedingung als auch die beiden Ausdrücke sehr einfach sind.

2.12 Gültigkeitsbereich (SCOPE)

Bei Gültigkeitsbereich eines Identifiers handelt es sich um jenen Teil des Programms, in dem er sich verwenden lässt.

Variablen können zum Beispiel nicht vor ihrer Deklaration benutzt werden, so dass ihr Gültigkeitsbereich mit ihrer Deklaration beginnt.

Beispiel 2.17: Verschachtelte und parallele Gültigkeitsbereiche

// Programm prüft Gültigkeitsbereiche von Variablen

#include <iostream.h>

int x = 11;

int main()
{


int x = 22;

{
int x = 33;

cout << “ Die Variable x hat im inneren Block von main() den Wert “ << x << endl;

}

cout << “ Die Variable x hat in main() den Wert “ << x << endl;

cout << “ Die Variable x hat im bei aufgelöstem Gültigkeitsbereich den Wert “ << ::x << endl;

return 0;
}


Die Variable x hat im inneren Block von main() den Wert: 33
Die Variable x hat in main() den Wert: 22
Die Variable x hat im bei aufgelöstem Gültigkeitsbereich den Wert: 11


Das Programm enthält drei verschiedene Objekte mit dem Namen x. Die letzte Zeile des Programms benutzt den
Gültigkeitsbereichs-Auflösungsoperator ::

für den Zugriff auf das globale x, das ansonsten in main() überlagert wird.

2.13 Aufzählungstypen

Über die vordefinierten Typen wie int und char hinaus erlaubt C++ die Definition eigener, spezieller Datentypen. Dafür gibt es mehrere Methoden.

Hier betrachten wir eine wesentlich einfachere Variante von benutzerdefinierten Typen. Bei einem Aufzählungstyp handelt es sich um einen Typ, der als einheitlich Ganzes behandelt wird und der vom Programmierer über die folgende Syntax definiert wird:

enum typname { mitgliedsliste }

Dabei ist enum ein C++ Schlüsselwort, typname steht für einen Identifier, der den Namen des definierten Typs festlegt, und mitgliedsliste steht für eine Folge von Identifiern, die Integer-Konstanten definieren.

Im Folgenden wird der Aufzählungstyp Semester mit drei möglichen Werten definiert, die Variablen dieses Typs annehmen können.

enum Semester { herbst, fruehling, sommer };

Anschließend lassen sich Variablen dieses Typs deklarieren:

Semester s1, s2;

Diese Variablen lassen sich dann wie vordefinierte Type einsetzen:

s1 = fruehling;

s2 = herbst;

if ( s1 = = s2 ) cout << “Dasselbe Semester.\n“;

Die eigentlichen in der mitgliedsliste definierten Werte werden Enumerator genannt. Tatsächlich handelt es sich um gewöhnlich Integer-Werte. Die für den obigen Semester-Typ definierten Werte herbst, fruehling und sommer hätten auch wie folgt definiert werden können:

const int herbst = 0;

const int fruehling = 0;

const int sommer = 0;


Die Werte 0, 1, ... werden bei der Typdefinition automatisch zugeordnet. Diese Vorgabewerte lassen sich in der mitgliedsliste überschreiben:

enum Coin {penny = 1, nickel = 5, dime = 10, quarter = 25};

Wenn nur einigen der Enumeratoren Integer-Werte zugewiesen werden, wird den nachfolgenden der nächste aufsteigende Wert zugeteilt.

enum Month { jan = 1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec};

In diesem Beispiel werden den zwölf Monaten die Zahlen 1 bis 12 zugeordnet. Weil es sich bei Enumeratoren einfach um Integer-Konstanten handelt, kann es durchaus mehrere verschiedene Enumeratoren mit demselben Wert geben:

enum Antwort { nein = 0, falsch = 0, ja = 1, wahr = 1, ok = 1};

Dadurch wird der folgende Quelltext möglich:

Antwort ant;

:

:

:

if (ant = = ja) cout << “ Sie haben gesagt, das sei O.K.\n“;

Er arbeitet wie erwartet. Wenn ja, wahr oder ok (diese sind alle gleich 1) der Wert der Variable ant sind, dann ist die Bedingung wahr, so dass die Ausgabe erfolgt.

Beachten Sie, dass sich diese Bedingung auch wie folgt schreiben lässt, da der Wert immer “wahr“ bedeutet:

if (ant) cout << “ Sie haben gesagt, das sei O.K.\n“;

Aufzählungstypen werden üblicherweise definiert, um Quelltexte selbst dokumentierend zu machen, so dass sie leichter verständlich werden. Hier einige typische Beispiele

Durch derartige Definitionen kann ihr Quelltext lesbarer werden. Aber Aufzählungstypen sollten nicht übermäßig genutzt werden. Jeder Enumerator in einer mitgliedsliste definiert einen neuen Identifier. Die obige Definition der Wochentage Tag definiert 7 Identifier, so dass sich diese Buchstaben innerhalb ihres Gültigkeitsbereiches nicht für andere Zwecke verwenden lassen.

Beachten Sie, dass es sich bei den einzelnen Namen der Aufzählungstypen um gültige Identifier handeln muss.

Die Deklaration:
enum Grade { F, D, C-, C, C+};   // Fehler

wäre so nicht gültig, weil die Zeichen + und – in Identifiern nicht verwendet werden dürfen.

Auch

enum Month { jan = 1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec};   // Fehler

enum Base {binary = 2, oct = 8, decimal = 10, hexadecimal = 16};   // Fehler

wäre nicht zulässig, weil die konstante oct redefiniert wird.

2.14 Integer-Typumwandlungen

In vielen Fällen erlaubt C++ die Verwendung von Objekten auch dann, wenn gelegentlich ein anderer Typ erwartet wird.

Dies nennt man Typumwandlung.

Die gebräuchlichsten Beispiel der Typumwandlung wandeln entweder einen Integer-Typ in einen anderen Integer-Typ oder einen Integer-Typ in einen Gleitkommatyp um.

Der allgemeine Ansatz ist der, dass ein Integer-Typ (einer von neun integralen Typen) verwendet werden kann, wenn ein anderer Integer-Typ erwartet wird, sofern der erwartete Typ einen “höheren Rang“, d. h. einen größeren Wertebereich hat. Ein char lässt sich zum Beispiel verwenden, wenn ein int erwartet wird, weil int einen höheren Rang als char hat.

Beispiel 2.18: Integer Umwandlung

#include <iostream.h>

int main()
{


char c = ‘A‘;

short m = 22;

int n = c + m;

cout << “ n = “ << n << endl;

}

return 0;
}


n = 87


Integer-Umwandlungen wie diese sind recht gebräuchlich und spielen sich üblicherweise unbemerkt ab. Die allgemeine Regel lautet, dass alle Integer-Typen nach int umgewandelt werden, wenn eine Integer-Umwandlung wie diese notwendig wird. Eine Ausnahme von dieser Regel betrifft Computer, bei denen die Implementation von int nicht alle Werte des umzuwandelnden Typs abdeckt.

In diesem Fall wird der Integer-Typ statt dessen in einen unsigned int umgewandelt. In Borland C++ liegt der Wertebereich des Typs unsigned short zwischen 0 und 65.536 und geht damit über den Wertebereich von int (-32.768 bis 32767) hinaus, so dass bei diesem Compiler unsigned short in unsigned int statt in int umgewandelt wird.

Da es sich bei Aufzählungstypen auch um Integer-Typen handelt, sind dies ebenfalls von der Integer-Typumwandlung betroffen, wie das nächste Beipiel zeigt.

Beispiel 2.19: Integer Umwandlung

#include <iostream.h>

enum farbe {rot, orange, gelb, blau, violett};

int main()
{


farbe x = blau;

cout << “ x = “ << x << endl;

}

return 0;
}


x = 3


In der letzten Zeile wird der Wert von x vom Aufzählungstyp farbe in den Typ int umgewandelt, bevor er dem Ausgabestrom übergeben wird.