Cierpliwości - trawa z czasem zamienia się w mleko.
Kurs C++ - Część V. Instrukcje programowe

Instrukcje warunkowe

Dotychczas nasze programy potrafiły tylko wykonywać instrukcje, które były kolejno umieszczone w funkcji main. Teraz to się zmieni. Nauczymy programy podejmować decyzje. Do tego służą instrukcje warunkowe. Sprawdzają one, czy są spełnione określone warunki i jeśli tak, to wykonują jakieś działanie. Jeśli jednak warunki nie są spełnione, program może wykonać w zamian inne czynności.

Instrukcja warunkowa jest zbudowana w ten sposób:

   if (warunek) instrukcja;

W tej składni warunek to zmienna lub jakiekolwiek inne wyrażenie, którego wynikiem jest wartość logiczna. Jeśli wartość ta różna od 0, instrukcja jest wykonywana. W przeciwnym wypadku program ją pominie i przejdzie do kolejnej instrukcji. Jeśli chcemy, by zamiast tego wykonała się jakaś instrukcja, musimy zapisać to tak:

   if (warunek) instrukcja1;   else instrukcja2;

Gdy warunek będzie prawdą, wykona się instrukcja1. W przeciwnym wypadku wykona się instrukcja2.

Spróbujmy to wykorzystać w praktyce. Zmienimy program wczytujący i wyświetlający liczbę. Po wczytaniu liczby wyświetlimy komunikat czy jest ona parzysta, czy nie:

   #include <iostream.h>
   void main()
   {   int liczba = 123;

       cout << "Podaj jakąś liczbę " << endl;
       cin >> liczba;
       if (liczba % 2 == 0 )  cout << "Podąłeś liczbę parzystą" << endl;
       else cout << "Podąłeś liczbę nieparzystą" << endl;
   }

Jeśli po spełnieniu lub niespełnieniu warunku ma się wykonać więcej niż 1 instrukcja, trzeba taki ciąg instrukcji zamknąć w klamrach. Kilka instrukcji zamknięte w nawiasy klamrowe traktowane jest przez kompilator jako jedna instrukcja:

   if (warunek)
   {   instrukcja1;
       instrukcja2;
       instrukcja3;
   }
   else instrukcja4;

W takim przypadku nie daje się już średnika przed else, bo zamykający nawias klamrowy nie jest instrukcją.

Zdarza się, że do wyboru mamy więcej niż 2 możliwości. Przykładowo robisz menu, z którego użytkownik wybiera opcję podając jej numer. Czy naprawdę trzeba będzie stosować tyle instrukcji if? Jest inna instrukcja warunkowa, która wybiera jedną z kilku instrukcji, zależnie od wartości warunku. Popatrz na przykładowy program:

   switch (warunek)
   {   case 1:    instrukcja1;     break;
       case 5:    instrukcja2;     break;
       case 8:    instrukcja3;     break;
       default:   instrukcja4;
   }

Gdy zmienna lub wyrażenie warunek przyjmie wartość 1, wykonają się wszystkie instrukcje od dwukropka do najbliższej instrukcji break. Gdy zmienna lub wyrażenie warunek przyjmie wartość 5, wykona się instrukcja2. Gdy zmienna lub wyrażenie warunek przyjmie wartość 8, wykona się instrukcja3. Jeżeli zmienna warunek nie będzie równa żadnej z wymienionych wartości, wykonają się instrukcje umieszczone po słówku default. Jeśli byś nie dał instrukcji break, program będzie wykonywał wszystkie instrukcje po kolei dopóki nie napotka instrukcji break gdzie indziej, albo dopóki nie skończy się instrukcja warunkowa switch. Zazwyczaj jest to efekt niepożądany.

Zrobimy teraz program Kalkulator. Trzeba podać dwie liczby i działanie, które ma być na nich wykonane. Na koniec program obliczy i wyświetli wynik. Oto listing programu:

   #include <iostream.h>

   void main()
   {   float x, y; //liczby
       char dz;    // działanie

       cout << "Podaj pierwsza liczbe:"; cin >> x;
       cout << "\nPodaj druga liczbe:"; cin >> y;
       cout << "\nPodaj dzialanie [+ - * /]:\n";
       cin >> dz;
       cout << "\n\nWynik dzialania: ";

       switch (dz)
       {   case '+':   cout << x+y;    break;
           case '-':   cout << x-y;    break;
           case '*':   cout << x*y;    break;
           case '/':
                       if (y!=0) cout << x/y;
                       else cout << "Dzielnik jest 0 - działanie niewykonalne !\n";
                       break;
           default:    cout << "Podałeś błędny znak działania !\n";
       }
   }

Omówimy program wiersz po wierszu. Najpierw deklarujemy 2 zmienne typu float, ponieważ będziemy też dzielić i wartości mogą wyjść ułamkowe. Kolejna zmienna będzie przechowywać znak działania, który użytkownik wprowadzi. Program prosi o podanie pierwszej i drugiej liczby, a następnie znaku działania. Teraz wkracza instrukcja warunkowa. Zwróć uwagę, że pojedynczy znak przypisany do zmiennej dz ujmujemy w apostrofy. Jeśli użytkownik wybrał dodawanie, program wyświetla sumę. Jeśli wybrał odejmowanie - różnicę. Jeśli użytkownik wybrał mnożenie - iloczyn. Jeśli wybrał dzielenie, trzeba jeszcze sprawdzić czy druga liczba nie jest przypadkiem zerem (program wywołałby błąd). Jeśli nie jest zerem, wyświetla iloraz. No i wreszcie, jeżeli użytkownik podał nieprawidłowy znak działania, to program wyświetla stosowną informację.

Pętla iteracyjna

W programach często zdarza się, że jakieś działanie musimy powtarzać wielokrotnie, np. sumować liczby z jakiegoś przedziału czy wczytywać wiele wartości z klawiatury. Pisanie kodu, który wykonywałby to krok po kroku jest zajęciem pracochłonnym, a tak napisany program zaczyna gwałtownie "puchnąć". Czy da się tego uniknąć? Owszem, możemy skorzystać z instrukcji programowej, która nazywa się pętlą. W programach można korzystać z dwóch rodzajów pętli: pętli iteracyjnej i pętli warunkowej (o której nieco później).

Składnia pętli iteracyjnej wygląda tak:

   for (wyrażenie1 ; wyrażenie2 ; wyrażenie3) instrukcja;

Wszystkie wyrażenia są opcjonalne. Wyrażenie1 jest obliczane przed wejściem do pętli (tylko raz!). Następnie oblicza się wyrażenie2 i sprawdza czy jest ono prawdziwe (różne od 0). Jeśli tak, wykonywana jest instrukcja i obliczane jest wyrażenie3. Następnie sprawdzana jest wartość wyrażenia2. Pętla jest wykonywana do momentu, gdy wartość wyrażenia2 będzie fałszywa (równa 0). Wyrażenie3 jest obliczane każdorazowo po wykonaniu instrukcji. Jeśli wszystkie trzy wyrażenia w pętli for są puste (pętla postaci: for(;;) instrukcja), to jest to pętla nieskończona. Instrukcja w pętli for może nie wykonać się ani raz, jeśli wyrażenie2 będzie od razu fałszywe (równe 0). Pętla for może być pętlą nieskończoną, jeśli wyrażenie2 nigdy nie przyjmie wartości fałsz (0). Wyrażenie pierwsze będzie zawsze obliczone (dokładnie 1 raz). Pętla for umożliwia zgrupowanie instrukcji inicjującej pętlę, warunku kontynuacji i instrukcji po wykonaniu pętli w jednym miejscu w programie.

Napiszmy program, który będzie sumował liczby naturalne od 1 do 100:

   #include <iostream.h>
   void main()
   {   int suma, x;

       for (suma=0 , x=1 ; x<=100 ; x++) suma += x;
       cout << "Suma liczb od 1 do 100 wynosi: " << suma;
   }

Jak to zadziała? Przed wejściem w pętlę do zmiennej suma program przypisze wartość 0, a do zmiennej x - 1 (operacja wykonana jednorazowo). Następnie zostanie sprawdzone, czy x jest mniejsze lub równe 100. Ponieważ 1 jest mniejsze od 100, to do zmiennej suma dodana zostanie aktualna wartość x, a następnie wartość x zostanie powiększona o 1. Znowu nastąpi sprawdzenie czy x jest mniejsze lub równe 100... itd. Do następnej instrukcji po pętli for przejdziemy, gdy x będzie większy od 100, czyli gdy x osiągnie wartość 101.

Pętle warunkowe

W odróżnieniu od pętli iteracyjnych, pętle warunkowe wykorzystujemy w sytuacjach, gdy z góry nie wiemy ile razy pętla ma być wykonana, np.: wczytujemy dane z klawiatury aż do wprowadzenia przez użytkownika określonej wartości. Nie jesteśmy w stanie przewidzieć, która to a kolei będzie wartość. Pętla warunkowa ma 2 składnie:

   while (warunek) instrukcja;

lub

   do instrukcja while (warunek);

Obie pętle wykonują instrukcję tak długo, jak długo prawdziwy jest warunek. Różnica między nimi polega na miejscu sprawdzania warunku: pętla while sprawdza warunek przed wykonaniem instrukcji, a pętla do-while - po jej wykonaniu. Konsekwencja tego jest taka, że pętla do-while zawsze wykona się przynajmniej 1 raz niezależnie od prawdziwości warunku (jest on sprawdzany dopiero po wykonaniu instrukcji), natomiast jeżeli warunek jest fałszywy, to pętla while nie wykona się ani razu.

Żeby zobaczyć, jak to działa w praktyce napiszmy program, który będzie wczytywał liczby z klawiatury aż do wprowadzenia 0, a następnie wyświetli sumę wszystkich wprowadzonych liczb:

   #include <iostream.h>

   void main()
   {   int suma = 0, x;

       do
       {   cout << "Podaj liczbę do sumowania (0 - koniec)";
           cin >> x;
           suma += x;
       } while (x != 0);
       cout << "Suma wprowadzonych liczb wynosi: " << suma;
   }

Pętla w naszym programie będzie wykonywana tak długo, aż użytkownik poda liczbę 0. Użyliśmy tutaj pętli do-while, gdyż najpierw musimy wczytać liczbę, a dopiero potem możemy sprawdzić, czy użytkownik nie podał wartości 0. Wykonanie tego sprawdzianu na początku nie miałoby najmniejszego sensu.

« wstecz   dalej »