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

Aus Wikibooks
Zur Navigation springen Zur Suche springen

Abschnitt "Hintergrundwissen" ist fehlerhaft[Bearbeiten]

Aus dem Kapitel:

Sie sollten wissen, das die case- und der default-Zweig in genau der Reihenfolge ausgeführt werden, in der Sie in der switch-Anweisung stehen und das nachdem der Vergleich mit einem case-Zweig erfolgreich war (der mit einem default-Zweig ist immer erfolgreich), die nachfolgenden Zweige nicht mehr beachtet werden. Der Code wird dann bis zum Ende der switch-Anweisung oder bist zum Auffinden eines break-Befehls ausgeführt.
Dies ist auch logisch, denn sonst währen Konstrukte wie das vorige Beispiel natürlich nicht möglich, denn (nach ASCII) ist ja bekanntlich 'A' (=65) kleiner als Beispielsweise 'a' (=97). Deshalb würden die Großbuchstaben bei einer Auswertung nach Größe des Wertes, vor den Kleinbuchstaben ausgewertet werden. Die Reihenfolge würde also nicht mehr (wie im Code steht) 'K' – 'k' – 'S' – 's' – 'W' – 'w' – default lauten, sondern 'K' – 'S' – 'W' – 'k' – 's' – 'w' – default. Deshalb währe es dem Kompieler nicht mehr ohne weiteres möglich, mehreren case-Zweigen den gleichen Code zuzuordnen.
Lange Rede, kurzer Sinn: Schreiben Sie einen default-Zweig immer als letzten Zweig in die switch-Anweisung und legen Sie jeden case-Zweig nur einmal an. Ein default-Zeig wird immer ausgeführt und nachfolgende case-Zweige dementsprechend nie überprüft. Ein doppelter case-Zweig (2 mal der gleiche Wert für case) würde bewirken, das die Einsprungmarke immer der erste Zweig ist, entsprechend würde der zweiten Zweig nie ausgeführt. Wahrscheinlich würde Ihr Kompieler ohne hin, keines von beiden Übersetzen ohne sich nicht mindestens mit einer Warnung zu beschweren und für Sie ist es nie sinnvoll so etwas zu tun, also versuchen Sie es gar nicht erst!

Das ist so nicht richtig:

  • Mehrere case-Zweige mit gleichem Wert ergeben nicht etwa einen Sprung zum ersten case-Label, sondern ein fehlerhaftes Programm, das gar nicht erst durch den Compiler gehen sollte.
  • Das default-Label kann an beliebiger Stelle stehen. Es wird nur dann angesprungen, wenn keines der anderen Labels passt.
  • Was das Ganze damit zu tun haben soll, welche Reihenfolge die verschiedenen Zeichen im ASCII-Zeichensatz haben, erschließt sich mir nicht.

Ich habe leider nicht den aktuellen Standard, aber hier ist ein Zitat aus einem Draft für die nächste Version des C++-Standards (Dokument n2009):

6.4.2 The switch statement [stmt.switch]
[...]
2 [...] No two of the case constants in the same switch shall have the same value after conversion to the promoted type of the switch condition.
[...]
5 When the switch statement is executed, is condition is evaluated and compared with each case constant. If one of the case constants is equal to the value of the condition, control is passed to the statement following the matched case label. If no case constant matches the condition, and there is a default label, control passes to the statement labeled by the default label. If no case matches and there is no default then none of the statements in the switch is executed.

Genau derselbe Text findet sich auch im letzten öffentlichen Draft des geltenden C++-Standards, deshalb ist anzunehmen, dass er auch so im aktuellen Standard selbst steht.

Das switch-Statement im Text ist also äquivalent zu folgendem Code:

{
  int tmp = auswahl;
  if (tmp == 'k') goto labelkK;
  if (tmp == 'K') goto labelkK;
  if (tmp == 's') goto labelsS;
  if (tmp == 'S') goto labelsS;
  if (tmp == 'w') goto labelwW;
  if (tmp == 'W') goto labelwW;
  goto labeldefault; // immer am Schluss der "goto-Kette!"
  {
  labelkK:
    cout << "Sie mögen also Käsesahnetorte!";
    break;
  labelsS:
    cout << "Streuselkuchen ist ja auch lecker...";
    break;
  labelwW:
    cout << "Windbeutel sind so flüchtig wie ihr Name, das können Sie sicher bestätigen?";
    break;
  labeldefault:
    cout << "Können Sie sich nicht entscheiden? Oder wollen Sie wirklich behaupten, das Ihnen nichts davon zusagt?";
  }
}

Hier erkennt man ganz klar, dass labeldefault im inneren Block auch ganz oben stehen könnte, ohne dass das etwas ausmachen würde.

Eine Nebenbemerkung: Die Ausgaben sollten auch immer ein Zeilenende (\n) mit ausgeben. Während DOS/Windows vor der nächsten Eingabeaufforderung der Shell noch ein extra Zeilenende ausgeben, ist dies unter Unix-artigen Systemen (z.B. Linux) nicht üblich. Wenn man dann am Ende der Programmausgabe kein Zeilenende hat, dann landet die nächste Shell-Eingabe auf derselben Zeile, und das ist äußerst unschön. --Ce 21:46, 22. Sep. 2007 (CEST)Beantworten[Beantworten]

Danke, hab den Abschnitt rausgenommen. Da hatte ich offenbar irgendwann mal was gelesen, dass sich auf alte Compiler bezog und nicht auf den Standard. --Prog 14:35, 23. Sep. 2007 (CEST)Beantworten[Beantworten]

Letzter Abschnitt, Vergleich Switch mit Bedingungen[Bearbeiten]

Im letzten Abschnitt, beim Vergleich zwischen switch und verknüpften Bedingungen, das muss doch eine Oder-Verknüpfung sein. Würde es eine Und-Verknüpfung sein, so würden die einzelnen Fälle nicht ausgeführt werden, denn ein Buchstabe ist entweder ein klines k oder ein großes K, aber er kann nicht gleichuzeitig groß und klein sein.

if (letter == 'k' && letter == 'K') {
    Anweisungen;
}

Ein guter Compiler sollte sich dazu äußern, und zwar mit der Aussage, dass diese Abfrage immer falsch ist...

Übrigens würde ein Korrekturlesen nicht schaden, hier sind viele kleine Rechtschreibfehler im Buch zu finden...

(23.3.2008, 13:49 Zulu)

Danke, hab's verbessert. :) Was die Rechtschreibung angeht, kann ich nur jedem ein großes Dankeschön sagen der sie verbessert, denn das ist zweifellos eine meiner größten Schwächen als Autor. Viele Grüße --Prog 19:29, 23. Mär. 2008 (CET)Beantworten[Beantworten]

Was genau bewirkt break in einem case-Bereich?[Bearbeiten]

Im Abschnitt "switch und break" ist im ersten code kein break in den case-Zeilen. Werden da wirklich weitere Vergleiche von 'auswahl' mit den case-Werten ignoriert (denn nur so könnte die angezeigte Ausgabe gemacht werden)? oder werden im switch-Bereich die weiteren case-Werte mit 'auswahl' verglichen, was eine Mehrfachauswahl in switch zuließe (dann müsste bei der angezeigten Ausgabe die Zeile 7 wegfallen, da auswahl ungleich 3 ist) --Axel Prignitz 00:18, 25. Jun. 2017 (CEST)Beantworten[Beantworten]

1. Annahme ist richtig. Ab dem erfüllten case-Ausdruck (wenn keiner erfüllt, ab default) werden alle Anweisungen bis zum ersten darauf folgenden break ausgeführt, oder, wenn kein break mehr kommt, bis zum Ende des Switch-Blocks. (Buchfreund) 92.196.92.165 01:09, 25. Jun. 2017 (CEST)Beantworten[Beantworten]

Zum Absatz 'Nur Ganzzahlen'[Bearbeiten]

In Blitzbasic gibt es 'Select' das ähnlich funktioniert wie 'switch'

Select <Variable>
  Case <Ganzzahl> <Anweisungen>
  Case <Ganzzahl> <Anweisungen>
  Default <Anweisungen>
End Select

Eine 'break'-ähnliche Anweisung ist nicht erforderlich, da in 'Select' immer nur die Anweisungen hinter dem ersten passenden case ausgeführt werden. Jedoch gibt es einen Trick, mit dem in case Bedingungen verwendet werden können:

Select True
  Case <Bedingung> <Anweisungen>
  Case <Bedingung> <Anweisungen>
  Default <Anweisungen>
End Select

Ist so etwas auch in C++ möglich?--Axel Prignitz 00:40, 25. Jun. 2017 (CEST)Beantworten[Beantworten]

Nein, hinterm case sind nur konstante Ausdrücke erlaubt, Ganzzahlwerte oder Enumerationstypen. (Buchfreund) 92.196.92.165 01:14, 25. Jun. 2017 (CEST)Beantworten[Beantworten]
Na toll, also ist switch tatsächlich nur für Ganzzahl-Vergleiche geeignet. Wenn man dagegen etwas komplexere Vergleiche machen will, (wie ich es HIER zur Berechnung des Seitenverhältnisse eines Screen in Blitzbasic gemacht habe) muss man wohl wieder mehrere If-Blöcke verschachteln? (was leicht unübersichtlich werden kann)--Axel Prignitz 01:38, 25. Jun. 2017 (CEST)Beantworten[Beantworten]
Verschachteln wäre das ja nicht. die if/else if befänden sich ja alle auf einer Ebene:
   if(!(breit % 2 | hoch % 2))      teiler = 2;
   else if(!(breit % 3 | hoch % 3)) teiler = 3;
   else if(!(breit % 5 | hoch % 5)) teiler = 5;
   else if(!(breit % 7 | hoch % 7)) teiler = 7;
Oder du erstellst eine Liste mit den Werten w[] = {2,3,5,7} und machst eine Schleife, die abbricht, wenn !(breit % w[i] | hoch % w[i]) erfüllt ist. 92.196.122.129 13:28, 25. Jun. 2017 (CEST)Beantworten[Beantworten]
Ich programmiere nur BlitzBasic, kein C++, bin nur zufällig auf diese Seite gekommen und wollte einfach nur wissen, ob man „switch“ in C++ ebenso verwenden kann, wie „Select“ in BlitzBasic. Ansonsten ist es mir nie peinlich, etwas nicht zu wissen und irgend jemand kann mir das gut und verständlich erklären. --Axel Prignitz 21:38, 26. Jun. 2017 (CEST)Beantworten[Beantworten]
Ach so, ich dachte, du planst konkret die Anwendung von C++, zumal ich bei Rumstöbern sah, dass blitzbasic.com wohl die Tage dicht macht. Lebt das trotzdem noch irgendwie weiter (weil du hier am Buch arbeitest)?
Edit: Jetzt verstehe ich dein "peinlich" erst. Mein "peinlich" bezog sich auf meinen eigenen Fehler (siehe Versionsgeschichte), nicht drauf, dass du was nicht weist. Buchfreund 92.196.80.232 23:18, 26. Jun. 2017 (CEST)Beantworten[Beantworten]