Verzweigungen |
>>Wenn ein Mädchen unter 21 ist, wird sie vom Gesetz geschützt. Wenn sie erst
über 60 ist, wird sie von der Natur geschützt. Und alles, was dazwischen ist,
ist zur Jagd freigegeben.<<
Cary Grant in >>Unternehmen Petticoat<<.
Es gibt diverse Gründe, warum ein Programm in Abhängigkeit von Variablen bestimmte Operationen nicht ausführen soll. Hier sind ein paar typische Beispiele zusammengestellt:
Mit dem Befehl if ist es möglich, eine Befehlssequenz unter einer Bedingung auszuführen. Das Schlüsselwort if kommt aus dem Englischen und bedeutet >>falls<< oder >>wenn<<. Die Syntax der if-Anweisung ist in Abbildung dargestellt.
Grafik nur im Buch vorhanden
Dem Schlüsselwort if folgt eine Klammer, in der die Bedingung formuliert wird, unter der der nachfolgende Anweisungsblock ausgeführt wird. Ein Anweisungsblock ist entweder eine einzelne Anweisung oder mehrere Anweisungen, die durch geschweifte Klammern zusammengefasst werden.
Grafik nur im Buch vorhanden
if (Divisor != 0)
Ergebnis = Dividend / Divisor;
Die Division wird nur durchgeführt, wenn die Bedingung zutrifft, also der
Divisor ungleich 0 ist.
c=2;
if (a==0)
if (b==0)
c=0;
cout << c << endl;
Die Abfrage, ob die Variable b 0 enthält, wird nur gestellt, wenn
die Variable a den Inhalt 0 hat. Nur wenn beide Variablen 0 sind,
wird die Variable c auf 0 gesetzt. Ansonsten enthält sie weiterhin
2.
if (Divisor != 0)
Ergebnis = Dividend / Divisor;
if (Divisor == 0)
cout << "Divisor ist 0! Keine Berechnung!";
Da solche Konstruktionen immer wieder gebraucht werden, bietet C++ einen eigenen Befehl an, um den gegenteiligen Fall der Bedingung abzudecken. Das Schlüsselwort dazu heißt else.
if (Divisor != 0)
Ergebnis = Dividend / Divisor;
else
cout << "Divisor ist 0! Keine Berechnung!";
Abbildung {grafifelse} zeigt den vollständigen Syntaxgraph für if mit else.
Grafik nur im Buch vorhanden
Ein Nassi-Schneidermann Diagramm stellt ein Programm oder ein Teilprogramm als großes Rechteck dar. Jeder Programmteil wird oben gestartet und endet immer unten. Seitenausstiege gibt es nicht. Ein Programm, das keine Abfragen oder andere Kontrollstrukturen hat, sieht aus wie ein Stapel Ziegelsteine von der Seite.
Grafik nur im Buch vorhanden
Grafik nur im Buch vorhanden
Betrachten wir das Struktogramm im Zusammenhang mit einem Programmbeispiel aus dem Bankbereich. Ein Kunde bekommt 3% Zinsen auf seine Spareinlagen. Legt er Geld drei Jahre oder länger fest, bekommt er 4% und bei Festlegung von 6 Jahren oder mehr sogar 5%.
Grafik nur im Buch vorhanden
Das Diagramm kann direkt in ein Programm umgesetzt werden.
if (AnlageDauer<3)
{
ZinsSatz=3;
}
else
{
if (AnlageDauer<6)
{
ZinsSatz=4;
}
else
{
ZinsSatz=5;
}
}
if (a == 0)
if (b == 0)
c=5;
else
cout << "Wohin gehöre ich?";
Sie werden vielleicht spontan denken, dass das else zu der Abfrage auf die
Variable a gehört. Das liegt aber nur an der etwas boshaften
Einrückung. Da das else auf der gleichen Ebene steht wie die
Abfrage nach a,
wird suggeriert, dass es auch zu dieser Abfrage gehört. Das ist aber falsch.
Die Sprache C++ definiert in diesem Fall, dass das else das letzte
if bedient und damit zur inneren Abfrage der Variablen b
gehört.
if (a == 0) if (a == 0)
{ {
if (b == 0) if (b == 0)
{ {
c=5; c=5;
} }
} else
else cout << "Wohin?";
cout << "Wohin?"; }
Durch das Einfügen der Blockgrenzen wird die Situation sofort klar.
Sobald Sie den Einrückungsregeln folgen, wird auch aus der Einrückungstiefe
sofort klar, wohin das else gehört.
Sie sehen an diesem Beispiel sehr gut, dass das Verwenden von geschweiften
Klammern die Zugehörigkeit der Anweisungen verdeutlicht. Schon aus diesem
Grund würde ich Ihnen empfehlen, beim if nicht an den
geschweiften Klammern zu sparen.
Diese Konstruktion lässt sich durch die Fallunterscheidung vereinfachen.
In Abbildung {grafswitch}
ist der Syntaxgraph der Fallunterscheidung dargestellt.
Grafik nur im Buch vorhanden
Der Case-Block wird in einem separaten Syntaxgraph
in Abbildung {grafcase} dargestellt.
Grafik nur im Buch vorhanden
In einer Hinsicht ist der Syntaxgraph nicht ganz korrekt: Danach wäre es
erlaubt, default mehrfach in einem Case-Block zu verwenden.
Sinnvollerweise darf aber nur ein default-Zweig in einem Case-Block
auftreten. Dies ließe sich durch einen etwas komplexeren Syntaxgraphen noch
darstellen. Spätestens die Regel, dass jede Konstante nur einmal verwendet
werden darf, ist durch den Syntaxgraph nicht mehr darstellbar.
Um der Übersicht willen bleibe ich bei dieser etwas vereinfachten Darstellung.
Die Syntaxgraphen haben hier den Zweck, die Syntax zu veranschaulichen und
sind nicht dafür gedacht, als Basis für die Entwicklung eines Compilers dienen.
In der Praxis kommt die Fallunterscheidung besonders bei der Reaktion auf
Kommandos oder Ereignisse zum Zuge. In der Programmierung grafischer Oberflächen
sind solche Fallunterscheidungen häufig zu finden. Grafische Applikationen
warten auf ein Ereignis, das durch Tastatur, Maus oder andere Quellen
ausgelöst wird, unterscheiden anhand einer Nachricht vom System, was der
Benutzer ausgelöst hat, und reagieren entsprechend. Die Nachrichten sind
üblicherweise ganzzahlige Werte.
Im folgenden Beispiel wird davon ausgegangen, dass in der Variablen
Zeichen ein Buchstabe steht.
% der vielleicht direkt von der Tastatur eingegeben wurde.
Die Fallunterscheidung interessiert sich für die
Buchstaben '3' bis '6' und '9'.
Der einfachste Fall ist der, wenn eine '6' in Zeichen vorliegt. Dann wird
die Variable e mit 1 belegt. Auch die Ziffer '5' ist noch recht
einfach. Hier wird der Variablen d eine 2 zugewiesen.
Befindet sich '3', '4' oder '9' in der Variablen Zeichen, so wird
zuerst die Variable a auf 4 gesetzt.
Da danach kein break erfolgt, wird auch d mit 2 belegt.
Erst dann stoppt ein break den weiteren Ablauf.
Da es zulässig ist, break wegzulassen, erhalten Sie auch keine
Fehlermeldung, wenn es fehlt. Solche Fehler sind schwer zu finden, da man
dazu neigt, den Befehl case auch als Ende des vorigen Falles
anzusehen.
An dem Beispiel ist auch zu erkennen, dass ein default nicht
zwingend erforderlich ist. Alle nicht explizit genannten Fälle werden dann
einfach nicht behandelt.
Ein typisches Beispiel ist die Berechnung der Betragsfunktion. Die
Betragsfunktion liefert immer den positiven Betrag eines Wertes. Ist der
Eingabewert negativ, muss er mit --1 multipliziert werden.
Mit einer if-Anweisung würde das so formuliert werden:
Grafik nur im Buch vorhanden
Der Fragezeichen-Ausdruck ist für viele Programmierer sehr irritierend, die
andere Sprachen gewohnt sind, die sich nicht von C herleiten,
weil es dort nichts Vergleichbares gibt.
Fall für Fall: switch case
Die Abfrage mit if ermöglicht die Unterscheidung zweier Fälle.
Wenn auf Grund verschiedener Werte unterschiedliche Anweisungen ausgeführt
werden sollen, können mehrere verschachtelte if-Anweisungen
hintereinander gesetzt werden oder es kann eine spezielle Fallunterscheidung
verwendet werden.
Ein schönes Beispiel ist ein Fahrstuhl in einem Kaufhaus,
in dem eine Vielzahl von Stockwerken zur Auswahl stehen und in jedem
Stockwerk andere Waren angeboten werden.
Zunächst wird die Aufgabe durch kaskadierende if-Anweisungen gelöst:
if (Stockwerk == 1)
{
cout << "Süssigkeiten, Bücher" << endl;
}
else if (Stockwerk == 2)
{
cout << "Bekleidung" << endl;
}
else if (Stockwerk == 3)
{
cout << "Bekleidung" << endl;
}
else if (Stockwerk == 4)
{
cout << "Spielzeug" << endl;
}
else if (Stockwerk == 5)
{
cout << "Unterhaltungselektronik" << endl;
}
else
{
cout << "Garage" << endl;
}
Wenn Sie es genau nehmen, habe ich etwas bei der Einrückung geschummelt.
Eigentlich hätte der Quelltext nach jedem else und jedem
if ein Stück eingerückt werden müssen. Dadurch wäre das Listing
aber in diesem besonderen Fall auch nicht übersichtlicher geworden.
Sie finden diese abgewandelte Form der Einrückung häufiger in Listings, wenn
ein if direkt auf ein
else folgt.
switch (Stockwerk)
{
case 1:
cout << "Süssigkeiten, Bücher" << endl;
break;
case 2:
case 3:
cout << "Bekleidung" << endl;
break;
case 4:
cout << "Spielzeug" << endl;
break;
case 5:
cout << "Unterhaltungselektronik" << endl;
break;
default:
cout << "Garage" << endl;
break;
}
Ganzzahliger Ausdruck
Die Fallunterscheidung beginnt mit dem Schlüsselwort switch.
In der darauf folgenden Klammer steht der ganzzahlige Ausdruck,
dessen Ergebnis die Verzweigung steuert.
Ein Ausdruck kann eine Variable sein, wie im Beispiel die Variable
Stockwerk. Hier könnte
aber auch eine Berechnung stehen, die zu einem ganzzahligen
Ergebnis führt. Es können auch Buchstaben verwendet
werden, da Buchstaben aus Sicht von C++ letztlich nichts anderes als
getarnte Zahlen sind.
Im Beispiel wird die Variable Stockwerk ausgewertet, die
offensichtlich eine ganze Zahl aufnehmen kann.
Sprungziele
In dem auf das Schlüsselwort switch folgenden Block gibt es
Ansprungpunkte, die mit dem
Schlüsselwort case gekennzeichnet sind. Darauf folgt eine Konstante,
die für den Wert steht, der hier behandelt wird.
Zum Abschluss des Ansprungpunktes steht ein Doppelpunkt.
Stimmt der Wert des ganzzahligen Ausdrucks mit der Konstante überein, setzt
das Programm seine Ausführung an dieser Stelle fort,
bis es auf ein break-Kommando stößt. Dann wird der Block verlassen.
Eine weitere case-Anweisung mit einer anderen Konstante stoppt das
Programm keineswegs. Erscheint kein break, läuft das Programm
unaufhaltsam bis zum Ende des Blocks.
Verzweiflungsfall
Findet sich kein passender case-Zweig, setzt das Programm beim
Schlüsselwort default seinen Ablauf fort.
Es empfiehlt sich, immer einen default-Zweig einzurichten.
Zwingend ist dies aber nicht.
Reihenfolge
Das Stockwerk-Beispiel könnte den Eindruck erwecken, dass alle Fälle
lückenlos behandelt werden müssten. Das ist keineswegs erforderlich.
Es ist auch nicht notwendig, dass die Fälle in aufsteigender Reihenfolge
sortiert sind. Auch muss der default-Zweig nicht zwingend als
letzter Fall angeführt werden.
switch (Zeichen)
{
case '3':
case '4':
case '9':
a = 4;
case '5':
d = 2;
break;
case '6':
e = 1;
break;
}
Kurzabfrage mit dem Fragezeichen
Mit Hilfe des Fragezeichens können if-Abfragen verkürzt werden,
die lediglich den Wert einer Berechnung beeinflussen.
Wenn Sie also einen Ausdruck benötigen, der sich in Abhängigkeit von einer
Bedingung verändert, kann er mit dem Fragezeichen extrem kurz formuliert
werden.
if (Wert >= 0)
{
Betrag = Wert;
}
else
{
Betrag = -Wert;
}
Mit Hilfe eines Fragezeichens können Sie das wesentlich kürzer ausdrücken.
Zunächst formulieren Sie die Bedingung (hier: Wert>=0).
Dann folgt das Fragezeichen. Als Nächstes wird der Ausdruck genannt, der
verwendet werden soll, wenn die Bedingung zutrifft
(hier: Betrag=Wert). Durch einen Doppelpunkt abgetrennt, wird der
Ausdruck ausgeführt, der verwendet werden soll, wenn die Bedingung nicht
zutrifft (hier: Betrag=-Wert).
Betrag = Wert>=0 ? Wert : -Wert;
Grundsätzlich kann der Fragezeichen-Ausdruck an jeder Stelle stehen, die
einen Ausdruck, also eine Auswertung, erwartet. Der Fragezeichen-Ausdruck
hat folgenden Aufbau:
Minimum
Das folgende Beispiel berechnet das Minimum aus den Variablen a
und b und zeigt, wie der Fragezeichen-Operator Programme verkürzen
kann.
Minimum = a < b ? a : b;
Vor dem Fragezeichen wird geprüft, ob a
kleiner als b ist. Ist das der Fall, dann steht in der Variablen
a der kleinere Wert, und deren Wert liefert der Ausdruck zwischen
dem Fragezeichen und dem Doppelpunkt. Im anderen Fall muss b den
kleineren Wert enthalten, und darum steht b auch hinter dem
Doppelpunkt.
Diese Seite basiert auf Inhalten aus dem Buch
Arnold Willemer: Einstieg in C++
Mit freundlicher Genehmigung und Unterstützung des Verlags galileo computing
| Informatik-Ecke Einstieg in C++ |
(C) Copyright 2005 Arnold Willemer
|