8.8 Instrukcja wyboru (switch)

Instrukcja wyboru (ang. switch statement) w zasadzie zawsze może być zastąpiona instrukcjami warunkowymi, ale czasem czytelniej jest użyć właśnie instrukcji wyboru. Jej najbardziej ogólna postać to:

       switch (wyr_calk) {
           case stala1: lista1
           case stala2: lista2
           // ...
           dafault: lista
       }
gdzie wyr_calk jest wyrażeniem o wartości całkowitej, stala1, stala2, ..., są wyrażeniami stałymi o wartości całkowitej, a  lista1, lista2, ..., są listami instrukcji (być może pustymi). Wyrażeniem stałym całkowitym może być tu liczba podana w postaci literału, nazwa całkowitej zmiennej ustalonej lub wyrażenie całkowite składające się z tego typu podwyrażeń. Liczba fraz case może być dowolna. Stałe występujące w każdej z fraz case muszą być różne. Listy instrukcji mogą też być puste. Fraza default jest opcjonalna: jeśli występuje, to może wystąpić tylko raz, choć niekoniecznie na końcu.

Najpierw obliczane jest wyr_calk. Następnie, jeśli obliczona wartość jest równa wartości którejś ze stałych stala1, stala2, ..., to wykonywane są instrukcje ze wszystkich list instrukcji, poczynając od listy we frazie case odpowiadającej tej stałej. A więc wykonywane są nie tylko instrukcje z listy w znalezionej frazie case, ale również ze wszystkich dalszych list!

Jeśli żadna ze stałych stala1, stala2, ..., nie jest równa wartości wyr_calk, a fraza default istnieje, to wykonywane są wszystkie instrukcje poczynając od tych we frazie default. Jeśli natomiast żadna ze stałych stala1, stala2, ..., nie jest równa wyr_calk, a fraza default nie istnieje, to wykonanie całej instrukcji wyboru uznaje się za zakończone.

Dowolną z instrukcji może być instrukcja zaniechania break. Jeśli sterowanie przejdzie przez tę instrukcję, to wykonanie całej instrukcji wyboru kończy się.


Instrukcję wyboru zilustrowano w poniższym programie; funkcja sw powoduje wypisanie różnej liczby gwiazdek w zależności od wartości argumentu: cztery gwiazdki dla argumentu 1, dwie dla argumentu 5, zero dla argumentu 2 lub 3 i trzy gwiazdki dla każdej innej wartości argumentu.


P45: switch.cpp     Instrukcja wyboru 1

      1.  #include <iostream>
      2.  using namespace std;
      3.  
      4.  void g( ) {
      5.      cout << '*';
      6.  }
      7.  
      8.  void sw(int k) {
      9.      cout << k << ": ";
     10.      switch ( k ) {
     11.          default: g( );                    
     12.          case  5: g( ); g( );              
     13.          case  3:
     14.          case  2: break;                   
     15.          case  1: g( ); g( ); g( ); g( );
     16.      }
     17.      cout << endl;
     18.  }
     19.  
     20.  int main() {
     21.      sw(9);
     22.      sw(5);
     23.      sw(4);
     24.      sw(3);
     25.      sw(2);
     26.      sw(1);
     27.      sw(0);
     28.  }

Działanie programu widać z wyników

    9: ***
    5: **
    4: ***
    3:
    2:
    1: ****
    0: ***
Zauważmy, że dla argumentów różnych od 1, 2, 3, 5 sterowanie przechodzi do instrukcji występującej we frazie default (linia ) i przechodzi następnie do instrukcji we frazach case odpowiadających wartościom 5, 3 i 2. Dopiero w linii  napotykana jest instrukcja break, która kończy wykonywanie całej instrukcji wyboru. Dlatego drukowane są wtedy trzy gwiazdki: jedna w linii  i dwie w linii  programu.

Fraza default wcale nie musi, jak widać z programu, występować na końcu.

Jeśli jedną z instrukcji jest instrukcja return, to przejście przez nią sterowania spowoduje oczywiście również zakończenie wykonywania instrukcji wyboru i zakończenie wykonywania funkcji w której występuje. Funkcja hexVal w poniższym programie wyznacza wartość liczbową odpowiadającą cyfrze szesnastkowej podanej w postaci znaku lub dostarcza -1, jeśli podany znak nie odpowiada żadnej cyfrze szesnastkowej:


P46: hex.cpp     Instrukacja wyboru 2

      1.  #include <iostream>
      2.  using namespace std;
      3.  
      4.  int hexVal(char c) {
      5.      switch ( c ) {
      6.          case '0': case '1': case '2':   
      7.          case '3': case '4': case '5':
      8.          case '6': case '7': case '8':
      9.          case '9':
     10.              return c - '0';             
     11.  
     12.          case 'a': case 'b': case 'c':
     13.          case 'd': case 'e':
     14.          case 'f':
     15.              return 10 + c - 'a';        
     16.  
     17.          case 'A': case 'B': case 'C':
     18.          case 'D': case 'E':
     19.          case 'F':
     20.              return 10 + c - 'A';        
     21.  
     22.          default: return -1;             
     23.      }
     24.  }
     25.  
     26.  int main() {
     27.      cout << "A = " << hexVal('A') << endl
     28.           << "f = " << hexVal('f') << endl
     29.           << "9 = " << hexVal('9') << endl
     30.           << "b = " << hexVal('b') << endl
     31.           << "Z = " << hexVal('Z') << endl;
     32.  }

W linii i trzech następnych zgrupowanych jest wiele fraz case pustych, z wyjątkiem ostatniej, która zawiera instrukcję return. Dzięki temu zawsze, gdy argumentem funkcji jest znak odpowiadający którejś z cyfr, sterowanie dojdzie do linii  zwracając właściwą wartość (bo liczbowo zmienna c ma wartość kodu ASCII odpowiedniej cyfry; odejmując kod ASCII znaku '0' otrzymamy wartość liczbową znaku c). Podobnie dla dowolnej małej litery odpowiadającej którejś z cyfr szesnastkowych sterowanie dojdzie do linii , a dla dużej litery — do linii . Jeśli znak nie odpowiada żadnej cyfrze szesnastkowej, wejdziemy do frazy default i zwrócona zostanie w linii wartość -1. Wynik tego programu:

    A = 10
    f = 15
    9 = 9
    b = 11
    Z = -1

T.R. Werner, 25 lutego 2017; 22:31