Instrukcje sterujące
Instrukcje sterujące to specjalne polecenia, dzięki którym można niejako kierować wykonaniem programu :-/ Dwie pierwsze będą to instrukcje warunkowe. Zaczniemy od najbardziej rozpowszechnionej w programowaniu. Chodzi o instrukcję if.
instrukcja if
Jeżeli znasz jakiś język programowania to na pewno zetknąłeś się z instrukcją if. Jest ona tak podstawowa, że każdy język ją posiada. Pomimo tego jednak radzę przeczytać ten rozdział. Co prawda zasada działania jest jednakowa niezależnie od języka, lecz mogą wystąpić pewne różnice składniowe. Żeby było łatwiej zrozumieć zaczniemy od tłumaczenia. If oznacza jeśli, jeżeli, gdyby. Najbardziej tutaj pasują dwa pierwsze określenia. Zatem będziemy się tego trzymać. Instrukcję if stosuje się w sytuacji, gdy wykonanie pewnych czynności jest zależne postawionego warunku lub wyrażenia.
1 |
if(warunek) instrukcja; |
Powyższy zapis oznacza tyle co jeśli warunek jest spełniony wykonaj instrukcję. Zauważ, że nie ma tutaj nic o sytuacji, gdy nie został spełniony. Wtedy po prostu instrukcja umieszczona za if zostanie pominięta i nastąpi przejście do następnej linii kodu. Jeszcze jedno. Jeżeli warunek zostanie spełniony zostanie wykonana tylko jedna instrukcja znajdująca się bezpośrednio za if. Nawet, gdy napiszesz tam kilka instrukcji. Zatem w poniższym zapisie wykona się tylko instrukcja_1.
1 |
if(warunek) instrukcja_1; instrukcja_2; instrukcja_3; |
Pamiętasz jeszcze o średniku? On właśnie stanowi zakończenie instrukcji. Tak więc instrukcja_2 i instrukcja_3 są niezależne od if. Zawsze zostaną wykonane. Teraz przedstawię jak można zapakować do jednego if kilka instrukcji. Może już się domyślasz, co? Małe naprowadzenie – zakres ważności. Teraz już chyba świta 🙂
1 2 3 4 5 6 7 8 9 10 11 12 13 |
if(warunek) { instrukcja1; instrukcja2; instrukcja3; instrukcja4; } |
Od teraz jeśli warunek zostanie spełniony zostaną wykonane wszystkie instrukcje będące między klamrami. W klamrach możesz umieścić dowolną ilość instrukcji. Możesz także umieścić tam inne instrukcję if! Tylko pamiętaj o zamykaniu klamer. Za pomocą klamer utworzyliśmy blok if. Tak się fajnie składa, że można powiązać kilka bloków if w logiczny związek. Tutaj również wszystko zależy od wartości wyrażenia. Może zostać wykonany jeden blok bądź więcej. Oczywiście jeśli warunek nie został spełniony w żadnym z bloków to nic się nie stanie. Po prostu nic nie zostanie wykonane. Tworzenie kilku bloków wygląda tak:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
if(zmienna == 0) { instrukcja1; instrukcja2; } else if(zmienna == 1) { instrukcja3; instrukcja4; } else if(zmienna >= 2) instrukcja5; |
Tutaj posłużyliśmy się poznanymi wcześniej operatorami. To za ich pomocą można dokonać sprawdzenia i odpowiednio zareagować. W przykładzie doszło nowe słówko else. Oznacza ono tyle co w przeciwnym wypadku. Zatem jeżeli zmienna jest równa zero wykonane zostaną dwie pierwsze instrukcje. W momencie, gdy zmienna będzie miała wartość 1 wykona się instrukcja trzecia i czwarta. Natomiast jeśli zmienna będzie większa lub równa dwa wykona się instrukcja piąta. Zauważ, że w trzecim przypadku nie użyłem klamer. Byłoby to zbędne, gdyż jest jedna instrukcja. Aczkolwiek można tam umieścić klamry. Pomyśl co by się stały, gdyby wartość była ujemna? Takiej możliwości nie przewidzieliśmy. Oczywiście wtedy wszystkie bloki ifzostaną pominięte. Czasami to nam odpowiada. Jednak nie zawsze. Załóżmy, że sprawdzamy, czy akcja odczytu powiodła się. Wartość jeden oznacza sukces, natomiast każda inna niepowodzenie. Tym razem jest nieco inna sytuacja. Jeżeli wartość jest równa jeden wykona się instrukcja informująca o udanej akcji. W każdym innym przypadku zostanie wyświetlony komunikat o porażce. Można to zrobić korzystając z kombinacji if i else if. Wtedy kod wyglądałby tak:
1 2 3 |
if(zmienna == 1) instrukcja1; else if(zmienna != 1) instrukcja2; |
Jeżeli wartość zmiennej jest równa jeden zostanie wykonana instrukcja pierwsza. W przeciwnym wypadku jeśli zmienna jest różna od jeden wykona się instrukcja druga. Oczywiście taki zapis jest jak najbardziej legalny. Jednak można go trochę uprościć. Wystarczy zapisać to w taki sposób:
1 2 3 |
if(zmienna == 1) instrukcja1; else instrukcja2; |
Tutaj również ruszy instrukcja pierwsza, gdy zmienna wynosi jeden. Jak mówiłem else oznacza 'w przeciwnym wypadku’. Tak właśnie jest w przykładzie. Instrukcja druga wystartuje w momencie, gdy wcześniejsze warunki nie zostały spełnione. Czyli w przypadku, gdy zmienna jest różna od jeden. To dokładnie jak we wcześniejszym przykładzie. Tylko nieco krócej.
instrukcja switch
Instrukcja switch jest nieco zbliżona do instrukcji if. switch jest jakby uproszczeniem kilku bloków if. Tradycyjnie wyjdziemy od tłumaczenia. switch to z angielskiego przełącznik. Dzięki tej instrukcji można w sposób zbliżony do if podejmować decyzje dotyczące dalszego działania. Zresztą pokażę to na przykładzie:
1 2 3 4 5 6 7 8 9 10 11 |
switch(zmienna) { case 1: instrukcja_1; case 2: instrukcja_2; case 3: instrukcja_3; } |
Podczas wchodzenia do bloku switch sprawdzana jest wartość zmiennej. Następuje próba dopasowania zmiennej do każdego z wariantów. Zatem najpierw porównywana jest zmienna z jedynką. Jeśli zmienna faktycznie wynosi jeden wykonane zostaną instrukcje będące za pasującym wariantem oraz wszystkie następne :-O. Zatem w naszym przypadku wykonają się wszystkie instrukcje z całego bloku. Gdyby zmienna była równa dwa wykonana zostałaby instrukcja druga i trzecia. Jest to trochę niezręczne, ale czasem się przydaje. Z reguły jednak chodzi nam o nieco inną sytuację. Lepiej byłoby, aby w przypadku wartości jeden wykonana została instrukcja pierwsza i żadna inna. Można tak zrobić i to całkiem prosto:
1 2 3 4 5 6 7 8 9 10 11 |
switch(zmienna) { case 1: instrukcja_1; break; case 2: instrukcja_2; break; case 3: instrukcja_3; break; } |
Widzisz dodatkowe słówko break. Znaczy ono tyle co przełamywać, więc doskonale odzwierciedla istotę działania. Od tej pory gdy wartość wynosi jeden wykona się tylko instrukcja pierwsza. Analogicznie jest w przypadku innych wartości. Oczywiście można nakazać wykonanie kilku instrukcji przy jednym przypadku. Robi się to w taki sposób:
1 2 3 4 5 6 7 8 9 10 11 |
switch(zmienna) { case 1: instrukcja_1; instrukcja_2; break; case 2: instrukcja_3; instrukcja_4; break; case 3: instrukcja_3; break; } |
Teraz instrukcja pierwsza i druga będą wykonywane zawsze, gdy zmienna będzie równa jeden. Jeśli wartośc zmiennej będzie wynosić dwa ruszy instrukcja trzecia i czwarta. W ostatnim przypadku wystartuje instrukcja piąta. Jak myślisz co się stanie, gdy wartość zmiennej będzie równa cztery? Wtedy oczywiście nic się nie stanie. Jednak takie sytuacje można wykryć i odpowiednio zareagować. Wystarczy dodać linijkę kodu:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
switch(zmienna) { case 1: instrukcja_1; instrukcja_2; break; case 2: instrukcja_3; instrukcja_4; break; case 3: instrukcja_3; break; default: instrukcja_6; break; } |
Słowo default oznacza uchybienie, zaniedbanie lub po prostu brak. To ostatnie najlepiej pasuje do sytuacji. Jeżeli wartości zmiennej nie można dopasować do żadnego z wariantów zostanie wykonana instrukcja umieszczona za słowem default. Nie koniecznie musi to być jedna instrukcja. Tutaj obowiązują takie same zasady jak wcześniej. W związku z tym możesz tam umieścić więcej instrukcji.
instrukcja goto
Instrukcja goto służy do bezwarunkowego skoku w inne miejsce programu. Nazwa oznacza idź do. Po napisaniu instrukcji należy jeszcze określić dokąd ma nastąpić wyskok. Określa się to za pomocą etykiety. Zerknij sobie:
1 2 3 4 5 6 7 8 9 10 11 |
etykietka_1: //definicja etykiety goto etykietka_1; koniec: instrukcja_1; instrukcja_2; |
Etykieta może mieć dowolną nazwę. Przy dobieraniu nazwy obowiązują te same zasady jak przy zmiennych. Zatem unikanie słów kluczowych oraz niektórych znaków. Mówiłem już o tym przy omawianiu zmiennych. Jak powiedziałem goto powoduje bezwarunkowy skok do wybranej etykiety. Bezwarunkowy oznacza, że skok nastąpi zawsze przy jej napotkaniu. Zastanów się chwilę nad powyższym przykładem. Jak myślisz kiedy wykonają się instrukcje znajdujące się za etykietą koniec? Problem w tym, że nigdy nie zostaną one wykonane :-O Nasuwa się prosty wniosek. Skoro instrukcje kończące program nie wystartują to.. program nigdy się nie zakończy! W przypadku instrukcji if lub switch można było określić kiedy i jaką akcję podjąć. goto takiego wyboru nie daje. Wyskok następuje zawsze i w dodatku w to samo miejsce. Widzisz jak łatwo można tutaj popełnić błąd. Kompilator nie jest w stanie tego wykryć i program będzie działał wadliwie. Jest to główny powód, dla którego nie należy stosować tej instrukcji. Oczywiście można ją umieścić w jakimś bloku if. Wówczas skok staje się uzależniony od pewnych warunków. Jednak to też nie jest eleganckie. Stanowczo odradzam korzystanie z tej instrukcji. Zresztą sam się przekonasz, że istnieją o wiele lepsze i bezpieczniejsze sposoby na wykonanie takiego skoku. Teraz tylko zdradzę, że chodzi mi o funkcje. Jeśli jednak uparcie chcesz stosować goto pamiętaj o jednym. Wyskok nie może nastąpić do etykiety będącej w innym zakresie ważności.
Mała dygresja by Iskar:
Instrukcja goto jest bardzo przydatna w jednej sytuacji. Otóż, jeżeli mam kilka zagnieżdzonych pętli, pojawia się problem:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include int main() { for (int i = 0 ; i < 10 ; i++) for (int j = 0 ; j < 10 ; j++) { std::cout << i * j ; if (i * j == 90) // i co? ;) jak stad wyskoczyć poza obie pętle? } return 0 ; } |
Przyznam, że przykład nie jest najciekawszy, ale co tam. W tym przypadku z pomocą przychodzi właśnie instrukcja goto:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include int main() { for (int i = 0 ; i < 10 ; i++) for (int j = 0 ; j < 10 ; j++) { std::cout << i * j ; if (i * j == 90) goto poza_oboma_petlami ; } poza_oboma_petlami : return 0 ; } |
Autor: Kesay
[Artykuł pochodzi ze strony guidecpp.prv.pl, autor wyraził zgodę na publikację]