Operator warunkowy i instrukcja switch. Podejmowanie decyzji w języku C++

Wprowadzenie

Podejmowanie decyzji w programach jest bardzo ważną kwestią. Niewątpliwie, gdyby nie możliwość podejmowania decyzji, tak naprawdę żadne programy by nie istniały, bowiem wówczas niemożliwe by było sprawdzenie, co użytkownik nacisnął albo jaką opcję wybrał.

Ty oczywiście znasz już sposób podejmowania decyzji w języku C++ - służy do tego instrukcja warunkowa if. Mimo to, warto poznać jeszcze 2 inne mechanizmy, które również pozwalają na dokonywanie decyzji w sposób często identyczny jak instrukcja warunkowa if.

Operator warunkowy

Jak łatwo można się domyśleć z samej nazwy, operator warunkowy pełni podobne zadanie jak instrukcja warunkowa if - umożliwia podejmowanie pewnych decyzji w zależności od pewnego warunku.

Chcę jednak zwrócić uwagę na poprawne nazewnictwo - to jest operator warunkowy a nie instrukcja warunkowa. Jedyną instrukcją warunkową w języku C++ jest instrukcja if.

Schematyczna postać operatora warunkowego wygląda następująco:

wyrazenie1 ? wyrazenie2 : wyrazenie3;

Najpierw jest sprawdzane czy wyrazenie1 jest prawdziwe czy nie. Jeśli jest ono prawdziwe, to obliczana jest wartość wyrazenie2 i jest ona zwracana. Jeśli natomiast wyrazenie1 było fałszywe, to obliczana jest wartość wyrazenie3 i ta wartość jest zwracana.

To, że wartość jest zwracana oznacza, że wynik operacji może zostać przypisany do jakiejś zmiennej, czyli przykładowo możemy napisać tak:

zmienna = wyrazenie1 ? wyrazenie2 : wyrazenie3;

W takiej sytuacji, jeśli wyrazenie1 będzie prawdą to zmienna będzie miała wartość wyrazenie2, natomiast jeśli wyrazenie1 będzie fałszywe, to zmienna będzie miała wartość wyrazenie3.

W rzeczywistości najczęściej w ten właśnie sposób jest wykorzystywany operator warunkowy - wynik działania jest przypisywany do jakiejś konkretnej zmiennej.

Operator warunkowy - przykłady

Poniżej przedstawię programy z wykorzystaniem operatora warunkowego. Jednocześnie przedstawię te same programy w użyciem instrukcji warunkowej if, aby udowodnić Ci, że za pomocą instrukcji if można uzyskać to samo.

Kod 1 z użyciem operatora warunkowego:

#include <iostream>

using namespace std;

int main()
{
  int a=3, b=2;
  (a<b) ? cout <<"a jest mniejsze" : cout <<"b jest mniejsze";
 
  cout <<endl<<"Nacisnij ENTER aby zakonczyc..."<<endl;
  getchar();
  return 0;  
}
program nr 19.1

Kod 1 z użyciem instrukcji warunkowej if:

#include <iostream>

using namespace std;

int main()
{
  int a=3, b=2;
  if (a<b)
     cout <<"a jest mniejsze";
  else
     cout <<"b jest mniejsze";
 
  cout <<endl<<"Nacisnij ENTER aby zakonczyc..."<<endl;
  getchar();
  return 0;  
}
program nr 19.2

Zwróć uwagę, że oba programy działają oczywiście tak samo. Ponadto zauważ, że w pierwszym programie po pierwszej instrukcji wypisania komunikatu na ekran nie ma średnika (nie może go tam być).

Kod 2 z użyciem operatora warunkowego:

#include <iostream>

using namespace std;

int main()
{
  int a=3, b=2, mniejsza;
  mniejsza = (a<b) ? a : b;
  cout <<"Wartosc mniejszej liczby wynosi "<<mniejsza<<endl;
 
  cout <<endl<<"Nacisnij ENTER aby zakonczyc..."<<endl;
  getchar();
  return 0;  
}
program nr 19.3

Kod 2 z użyciem instrukcji warunkowej if:

#include <iostream>

using namespace std;

int main()
{
  int a=3, b=2, mniejsza;
  if (a<b)
     mniejsza=a;
  else
     mniejsza=b;
  cout <<"Wartosc mniejszej liczby wynosi "<<mniejsza<<endl;
 
  cout <<endl<<"Nacisnij ENTER aby zakonczyc..."<<endl;
  getchar();
  return 0;  
}
program nr 19.4

Również tym razem w obu przypadkach otrzymujemy dokładnie ten sam rezultat. Oczywiście za pomocą instrukcji warunkowej można tworzyć zagnieżdżone warunki, myślę jednak, że taki zapis nie będzie ani zbyt łatwy do zrozumienia ani zbyt przydatny.

Przyznam się szczerze, że prywatnie nie stosuję prawie w ogóle operatora warunkowego - zamiast niego stosuję zawsze instrukcję warunkową, bowiem jest ona znacznie bardziej uniwersalna (da się więcej osiągnąć), a ponadto zapis jest znacznie łatwiejszy, również do rozbudowy.

Operator warunkowy - podsumowanie

Jak udało Ci się zauważyć, za pomocą operatora warunkowego można często osiągnąć te same rezultaty, co za pomocą instrukcji warunkowej if. To, czy zdecydujesz się używać operatora warunkowego, zależy tylko od Ciebie. Nawet jeśli się na to zdecydujesz, to i tak używanie instrukcji warunkowej if będzie dla Ciebie koniecznością.

Instrukcja switch

Instrukcja switch służy do podejmowania decyzji warunkowych. Tak naprawdę bez tej instrukcji można się obejść, bowiem instrukcja ta niejako ułatwia nam tylko zapis w przypadku wielu warunków (pisania jest tak samo dużo jak w przypadku instrukcji if, jednak w wielu przypadkach kod jest znacznie czytelniejszy).

Nie ma sztywnej zasady kiedy należy stosować instrukcję switch, a kiedy kilka instrukcji if - else. Wszystko zależy od indywidualnych upodobań, jednak intuicyjnie warto zastosować instrukcję switch kiedy mamy więcej niż 3 warunki.

Instrukcja switch - schematy

Schematyczna postać instrukcji switch wygląda następująco:

switch (wyrazenie)
{
  case wartosc1:
        listaInstrukcji1;
  case wartosc2:
        listaInstrukcji2;
 
  ...
 
  case wartoscN:
        listaInstrukcjiN;
  default:
        listaInstrukcjiDomyslna;
}

Przede wszystkim każda wartość znajdująca się po słowie case musi być wyrażeniem typu całkowitego (czyli int lub char) i musi to być stała liczba, tzn. nie można tutaj zapisać zmiennej.

Dodatkowo, sekcji case może być tyle ile chcemy, ale żadne z wartości nie mogą się powtarzać. Jeśli żadna z wybranych przez nas wartości się nie pojawi, wówczas zostanie wykonana lista instrukcji po słowie default.

Co prawda sekcja default nie jest w ogóle obowiązkowa, to jednak zawsze warto ją dodać, aby mieć kontrolę nad programem i przewidzieć nawet najdziwniejsze błędy programu.

Zasada działania jest taka, że jest wykonywana lista instrukcji począwszy od listy instrukcji znajdującej się w sekcji case, dla której wyrażenie ma daną wartość. Przykładowo, jeśli w powyższym schemacie wyrazenie ma wartość wartosc2, to wówczas wykona się lista instrukcji począwszy od listaInstrukcji2. Wykona się zatem nie tylko listaInstrukcji2, ale również listaInstrukcji3, ..., listaInstrukcjiN i listaInstrukcjiDomyslna.

Oczywiście o takie działanie rzadko kiedy nam chodzi (naprawdę bardzo rzadko) i taka postać instrukcji switch by nam się prawie w ogóle nie przydała.

Dlatego też każdą listę instrukcji należy zakończyć poznaną już przez Ciebie instrukcją break - wówczas instrukcja switch będzie się zachowywała tak jak grupa instrukcji warunkowych if. Instrukcja break w takim przypadku nie jest jedynie konieczna w sekcji default, bowiem nic się już za nią nie znajduje.

Zatem schemat, jakiego oczekujemy i jakiego będziesz używać prawie zawsze w przypadku instrukcji switch wygląda następująco:

switch (wyrazenie)
{
  case wartosc1:
        listaInstrukcji1;
        break;
  case wartosc2:
        listaInstrukcji1;
        break;  
  ...
 
  case wartoscN:
        listaInstrukcjiN;
        break;
  default:
        listaInstrukcjiDomyslna;
}

Warto dodać, że listy instrukcji nie muszą w tym przypadku być brane w nawiasy klamrowe, nawet gdy instrukcji jest kilka, bowiem kompilator łatwo się domyśla gdzie jest koniec listy instrukcji - jest on tam, gdzie pojawia się kolejne słowo case.

W powyższym schemacie, wszystko wykona się dokładnie tak, jak tego byśmy oczekiwali. Jeśli wyrazenie ma wartość wartosc2, to zostanie wykonana jedynie listaInstrukcji2 i nic więcej.

Żeby nie było żadnych niedomówień, oba przedstawione schematy instrukcji switch są zupełnie poprawne z punktu widzenie składni języka C++ - pierwszy schemat jest tylko po prostu zazwyczaj mniej przydatny i w 99% stosuje się schemat z wykorzystaniem instrukcji break.

Instrukcja switch - przykład użycia

Poniżej przedstawię jeden przykład użycia instrukcji switch. Program będzie bardzo prosty i zostanie wykorzystany oczywiście drugi, ten bardziej przydatny schemat postaci instrukcji switch. Oto program ilustrujący działanie instrukcji switch:

#include <iostream>

using namespace std;

int main()
{
  int liczba;
  cout <<"Podaj liczbe calkowita: ";
  cin >>liczba;
  cin.ignore();
 
  switch (liczba)
  {
     case 48: // jak widzisz jest to stala calkowita a nie zadna zmienna
        cout <<"Liczba wynosi 48";
        break;
     case 60:
        cout <<"Liczba wynosi 60"<<endl;
        cout <<"Liczba nie wynosi 48";
        break;
     case 78:
        cout <<"Liczba wynosi 78";
        break;
     default:
        cout <<"Podana liczba jest rozna od 48, 60 i 78"<<endl;
        cout <<"Liczba wynosi "<<liczba<<endl;
  }
 
  cout <<endl<<endl<<"Nacisnij ENTER aby zakonczyc..."<<endl;
  getchar();
  return 0;  
}
program nr 19.5

Jak widzisz program działa zgodnie z oczekiwaniami. Spróbuj zmienić typ zmiennej liczba np. na float i program się nie skompiluje, bo w instrukcji switch musimy mieć liczby całkowite (wcześniej juz o tym wspomniałem). Podobnie, jeśli utworzysz dodatkową zmienną i napiszesz case nowaZmienna, to program również się nie skompiluje, bowiem to nie jest stała.

Mam nadzieję, że ten jeden przykład wystarczył Ci do zrozumienia instrukcji switch, bo tak naprawdę nie ma tu nic trudnego. Oczywiście instrukcje switch można w sobie zagnieżdżać, jednak niezbyt często stosuje się taki zapis, a jeśli Ci naprawdę na tym zależy, to spróbuj na własną rękę napisać taki program.

Podsumowanie

W tej lekcji udało Ci się poznać operator warunkowy i instrukcję switch. Po raz kolejny, bez tych konstrukcji (zwłaszcza tej pierwszej) można się obyć, warto jednak znać tak podstawowe mechanizmy języka C++.

powrót