C++-Programmierung/ Einführung in C++/ Auswahl

Aus Wikibooks


Verzweigungen kennen Sie schon, daher sollte es Ihnen nicht schwer fallen, ein Programm zu schreiben, welches abfragt, welche der verschiedenen, in der Überschrift benannten Leckereien, Sie am liebsten mögen. Das ganze könnte etwa so aussehen:

#include <iostream>

using namespace std;

int main(){
    int auswahl;

    cout << "Wählen Sie Ihre Lieblingsleckerei:\n"
            "1 - Käsesahnetorte\n"
            "2 - Streuselkuchen\n"
            "3 - Windbeutel\n";

    cin >> auswahl;

    if(auswahl==1)
        cout << "Sie mögen also Käsesahnetorte!\n";
    else if(auswahl==2)
        cout << "Streuselkuchen ist ja auch lecker...\n";
    else if(auswahl==3)
        cout << "Windbeutel sind so flüchtig wie ihr Name, das können Sie sicher bestätigen?\n";
    else
        cout << "Wollen Sie wirklich behaupten, dass Ihnen nichts davon zusagt?\n";

    return 0;
}
Ausgabe:
Wählen Sie Ihre Lieblingsleckerei:
1 - Käsesahnetorte
2 - Streuselkuchen
3 - Windbeutel
<Eingabe>2</Eingabe>
Streuselkuchen ist ja auch lecker...

Das funktioniert natürlich, aber finden Sie nicht auch, dass der (Schreib-)Aufwand ein wenig zu groß ist? Außerdem ist diese Schreibweise nicht gerade sofort einleuchtend. Für unseren Fall, wäre es schöner, wenn wir die Variable auswahl als zu untersuchendes Objekt festlegen könnten und dann einfach alle Fälle die uns interessieren durchgehen könnten. Praktischerweise bietet C++ ein Schlüsselwort, das genau dies ermöglicht.

switch und break[Bearbeiten]

Eine switch-Anweisung hat die folgende Form:

Syntax:
switch(«Ganzzahlige Variable»){
    case «Ganzzahl»: «Anweisungsblock»
    case «Ganzzahl»: «Anweisungsblock»
    «...»
    default: «Anweisungsblock»
}
«Nicht-C++-Code», »optional«

Auf unser Beispiel angewandt, würde das dann so aussehen:

#include <iostream>

using namespace std;

int main(){
    int auswahl;

    cout << "Wählen Sie Ihre Lieblingsleckerei:\n"
            "1 - Käsesahnetorte\n"
            "2 - Streuselkuchen\n"
            "3 - Windbeutel\n";

    cin >> auswahl;

    switch(auswahl){
        case 1:  cout << "Sie mögen also Käsesahnetorte!";
        case 2:  cout << "Streuselkuchen ist ja auch lecker...";
        case 3:  cout << "Windbeutel sind so flüchtig wie ihr Name, das können Sie sicher bestätigen?";
        default: cout << "Wollen Sie wirklich behaupten, dass Ihnen nichts davon zusagt?";
    }

    return 0;
}
Ausgabe:
Wählen Sie Ihre Lieblingsleckerei:
1 - Käsesahnetorte
2 - Streuselkuchen
3 - Windbeutel
<Eingabe>2</Eingabe>
Streuselkuchen ist ja auch lecker...
Windbeutel sind so flüchtig wie ihr Name, das können Sie sicher bestätigen?
Wollen Sie wirklich behaupten, dass Ihnen nichts davon zusagt?

Nun ja, Sie haben ein neues Schlüsselwort kennen gelernt, setzen es ein und kommen damit auch prompt zum falschen Ergebnis. Sieht so aus, als würde jetzt jeder der Sätze ab dem Ausgewählten ausgegeben. In der Tat handelt switch genau so. Es führt alle Anweisungen, ab dem Punkt aus, an dem das case-Argument mit der übergebenen Variable (in unserem Fall auswahl) übereinstimmt. Um das Ausführen nachfolgender Anweisungen innerhalb von switch zu verhindern, benutzen Sie das Schlüsselwort break. Unser Beispiel sieht dann also folgendermaßen aus:

#include <iostream>

using namespace std;

int main(){
    int auswahl;

    cout << "Wählen Sie Ihre Lieblingsleckerei:\n"
            "1 - Käsesahnetorte\n"
            "2 - Streuselkuchen\n"
            "3 - Windbeutel\n";

    cin >> auswahl;

    switch(auswahl){
        case 1:
            cout << "Sie mögen also Käsesahnetorte!";
            break;
        case 2:
            cout << "Streuselkuchen ist ja auch lecker...";
            break;
        case 3:
            cout << "Windbeutel sind so flüchtig wie ihr Name, das können Sie sicher bestätigen?";
            break;
        default:
            cout << "Wollen Sie wirklich behaupten, dass Ihnen nichts davon zusagt?";
    }

    return 0;
}
Ausgabe:
Wählen Sie Ihre Lieblingsleckerei:
1 - Käsesahnetorte
2 - Streuselkuchen
3 - Windbeutel
<Eingabe>2</Eingabe>
Streuselkuchen ist ja auch lecker...

Nun haben Sie wieder das ursprüngliche, gewünschte Verhalten. Was Sie noch nicht haben, ist eine Erklärung, warum extra ein break aufgerufen werden muss, um das Ausführen folgender case-Zweige zu unterbinden. Aber das werden Sie gleich erfahren.

Nur Ganzzahlen[Bearbeiten]

Wie bereits aus der oben stehenden Syntaxangabe hervorgeht, kann switch nur mit Ganzzahlen benutzt werden. Dies hängt damit zusammen, dass switch ausschließlich auf Gleichheit mit einem der case-Zweige vergleicht. Bei int-Werten (mit der üblichen Größe von 4 Byte) ist das noch eine „überschaubare“ Menge von maximal 4.294.967.296 () case-Zweigen. Ein float kann die gleiche Menge unterschiedlicher Zahlen darstellen, sofern er ebenfalls 4 Byte groß ist. Aber versuchen Sie mal einen genauen float-Wert aufzuschreiben. Sie arbeiten also immer mit Näherungen, wenn Sie Gleitkommazahlen in Ihrem Code benutzen. Ihr Compiler regelt das für Sie, er weist der Gleitkommazahl den zu Ihrem Wert am nächsten liegenden, darstellbaren Wert zu. Deshalb ist es so gut wie nie sinnvoll (aber natürlich trotzdem möglich), einen Test auf Gleichheit für Gleitkommazahlen durchzuführen. Bei switch wurde das jedoch unterbunden.

Zeichen und mehrere case-Zweige[Bearbeiten]

Eine if-Anweisung trifft Ihre Entscheidung hingegen, anhand der Tatsache ob eine Bedingung erfüllt ist, oder nicht. Für die if-Anweisung gibt es also nur zwei Möglichkeiten. Allerdings gibt es eine ganze Menge von Möglichkeiten, wie der Zustand true, oder false erreicht werden kann. Die Rede ist von Vergleichen und Verknüpfungen ( wie && (= und) oder || (= oder) ) und der Umwandlung von anderen Datentypen nach true, oder false. Für ganzzahlige Datentypen gilt etwa, dass jeder Wert ungleich 0 true ergibt, aber 0 hingegen wird als false ausgewertet. Für eine genaue Beschreibung dessen, was hier noch mal kurz umrissen wurde, sehen Sie sich das Kapitel über Verzweigungen an.

Also gut, switch kann nur auf Gleichheit testen und erlaubt auch keine Verknüpfungen. Oder sagen wir besser: fast keine. Denn genau deshalb gibt es diese scheinbar aufwendige Regelung mit dem break. Das folgende Beispiel demonstriert die Verwendung von Zeichen und die Anwendung von mehreren case-Zweigen, die den gleichen Code ausführen (was einer Verknüpfung mit || zwischen mehreren Vergleichen mittels == gleichkommt):

#include <iostream>

using namespace std;

int main(){
    char auswahl;

    cout << "Wählen Sie Ihre Lieblingsleckerei:\n"
            "K - Käsesahnetorte\n"
            "S - Streuselkuchen\n"
            "W - Windbeutel\n";

    cin >> auswahl;

    switch(auswahl){
        case 'k':
        case 'K':
            cout << "Sie mögen also Käsesahnetorte!";
            break;
        case 's':
        case 'S':
            cout << "Streuselkuchen ist ja auch lecker...";
            break;
        case 'w':
        case 'W':
            cout << "Windbeutel sind so flüchtig wie ihr Name, das können Sie sicher bestätigen?";
            break;
        default:
            cout << "Wollen Sie wirklich behaupten, dass Ihnen nichts davon zusagt?";
    }

    return 0;
}
Ausgabe:
Wählen Sie Ihre Lieblingsleckerei:
K - Käsesahnetorte
S - Streuselkuchen
W - Windbeutel
<Eingabe>s</Eingabe>
Streuselkuchen ist ja auch lecker...

Dieses Programm benutzt die Anfangsbuchstaben anstatt der bisherigen Durchnummerierung für die Auswahl. Außerdem ist es möglich sowohl den großen, als auch den kleinen Buchstaben einzugeben. Beides führt den gleichen Code aus.

Missing 'break'[Bearbeiten]

Da switch „von oben nach unten“ abgearbeitet wird, benötigt der letzte Fall kein 'break' - dort endet die Switch-Struktur sowieso. Es ist jedoch erlaubt, den 'default'-Fall auch vor einem oder mehreren 'case'-Fällen aufzuführen - dann sollte er ebenso mit einer 'break'-Anweisung enden, wie jeder andere Fall.

Der letzte Fall darf ebenso mit 'break' enden, wie alle anderen - es schadet nicht ;-)