2. Wstęp do programowania w języku C + + #include <iostream> #include <cstdio> using namespace std; Gdy już wskaza eś zmienne, których wartości chcesz śledzić, uruchom wykonywanie programu w trybie krokowym - wystarczy z menu Run wybrać funkcję Step Over lub po prostu nacisnąć klawisz skrótu F8. Każda linia programu będzie teraz interpretowana i wykonywana, a w celu wykonania następnej linii należy ponownie nacisnąć klawisz F8. Wartości obserwowanych zmiennych są aktualizowane po każdym wykonaniu kolejnej linii. Narzędzia debugera są szczególnie przydatne w skomplikowanych programach zawierających pętle (o pętlach dowiesz się w dalszej części tego rozdzia u). 2.5. Instrukcje sterujące Instrukcje sterujące kierują przebiegiem wykonywania programu. Pozwalają one na zmianę kolejności wykonywania innych instrukcji zależnie od otrzymywanych wyników. Bez instrukcji sterujących moglibyśmy pisać tylko programy liniowe, czyli realizujące algorytmy liniowe. Dzięki instrukcjom sterującym możemy pisać programy realizujące algorytmy rozga ęzione i iteracyjne. 2.5.1. Instrukcja warunkowa if... else Same operacje wejścia i wyjścia to jeszcze zbyt ma o, aby napisać program wykonujący z ożone zadanie. Zapoznajmy się z zapisem w języku C + + instrukcji, które poznaliśmy przy omawianiu algorytmów. Zanim przedstawimy formalną sk adnię instrukcji, omówimy przyk adowe programy i ich poszczególne elementy. Zacznijmy od instrukcji warunkowej: int main() { int liczba; cout «"Podaj liczbę "; cin» liczba; if (liczba>0) cout «"Liczba jest dodatnia"; else cout «"Liczba nie jest dodatnia"; cin.ignore(); getchar(); return 0; } // deklaracja zmiennej // przypisanie wartości z klawiatury // instrukcja warunkowa Program ten sprawdza, czy liczba jest dodatnia (algorytm tego problemu zamieściliśmy w poprzednim rozdziale). Znajduje się w nim instruk- 50 www.operon.pll
2.5. Instrukcje sterujące Zapamiętaj Skończoną liczbę instrukcji pojedynczych ujętych w klamry { i } nazywamy instrukcją z ożoną lub inaczej blokiem instrukcji. *. ) Zobaczmy, jak bardzo różnić się będą efekty dzia ania dwóch programów, których kody różnią się tylko jedną parą nawiasów klamrowych. w w w. o p e r o n. p l 51
2. Wstęp do programowania w języku C+ + #include <iostream> #include <cstdio> using namespace std; Jako pierwszy rozważmy program zawierający nawiasy klamrowe: int main() { int dlugosc; cout «"Podaj liczbę ca kowita "; cin» dlugosc; if (dlugosoo) { cout «endl; cout «"Poda eś dodatnia liczbę" «endl; cout «"Dobrze, bo to ma byc dlugosc odcinka" «endl; cout «"Narysuje wiec odcinek o d ugości " «dlugosc; } cout «"\n\ndziekuje, koncze dzia anie..."; cin.ignore( ) ; getchar(); return 0; } Program prosi użytkownika o podanie liczby ca kowitej. Jeśli podana liczba jest dodatnia, to wykonają się wszystkie instrukcje bloku otwartego w linii oznaczonej (4), a zamkniętego w linii (9). Klamry są jakby spoiwem ca ości instrukcji z ożonej, która ma zostać wykonana, jeśli jest spe niony warunek z linii (3). Przyk adowo, jeśli podamy liczbę dodatnią, na ekranie monitora po zakończeniu dzia ania programu będzie wyświetlony napis: Podaj liczbę ca kowita 9 Poda eś dodatnia licabe Dobrze, bo to ma byc dlugosc odcinka Narysuje wiec odcinek o d ugości 9 Dziękuje, koncze dzia anie... O to w aśnie nam chodzi o. Program ma nas poinformować, że podana liczba będzie mu przydatna, bo narysuje odcinek o takiej d ugości. W wypadku wpisania liczby, która nie jest dodatnia, na ekranie możemy zobaczyć: Podaj liczbę ca kowita -8 Dziękuje, koncze dzia anie... Gdy podaliśmy liczbę ujemną, dzia anie programu kończy się tylko podziękowaniem, nic ponadto nie zostanie wykonane w programie - wszak d ugość odcinka nie może być liczbą ujemną. 52 w w w. o p e r o n. p l
2.5. Instrukcje sterujące Co się zmieni, jeśli usuniemy klamry wiążące kilka instrukcji w jeden blok instrukcji? Sprawdźmy dzia anie programu po wykonaniu tej modyfikacji: #include <iostream> #include <cstdio> using namespace std; int main() { int dlugosc; cout «"Podaj liczbę ca kowita "; // (1) cin» dlugosc; // (2) if (dlugosoo) // (3) // tu usunęliśmy klamrę otwierającą! (4) cout «endl; // (5) cout «"Poda eś dodatnia liczbę" «endl; // (6) cout «"Dobrze, bo to ma byc dlugosc odcinka" «endl; // (7) cout «"Narysuje wiec odcinek o d ugości " «dlugosc; // (8) // tu usunęliśmy klamrę zamykającą! (9) cout «"\n\ndziekuje, koncze dzia anie..."; cin.ignore(); getchar(); return 0; } Uruchomimy teraz program dla tych samych wartości. Najpierw podamy tak samo jak poprzednio liczbę dodatnią: Podaj liczbę ca kowita 9 Poda eś dodatnia liczbę Dobrze, bo to na byc dlugosc odcinka Narysuje wiec odcinek o d ugości 9 Dziękuje, koncze dzia anie... Nic się nie zmieni o. Podajmy więc liczbę -8: Podaj liczbę ca kowita -8 Poda eś dodatnia liczbę Dobrze, bo to na byc dlugosc odcinka Narysuje wiec odcinek o d ugości 8 Dziękuje, koncze dzia anie... Skoro ciąg instrukcji nie by ujęty w klamry, instrukcja, która ma się wykonać w wypadku spe nienia warunku z linii (3), jest instrukcją pojedynczą, czyli wyprowadzeniem na ekran monitora nowej linii określonej w linii (5), pozosta e zaś nie dotyczą już instrukcji warunkowej. Dlatego też pozosta e instrukcje zostaną wykonane za każdym razem, jako nieodnoszące się do instrukcji warunkowej. W przyk adach prostych, jak nasz powyżej, szybko zauważysz pomy kę, ale b ąd tego samego ro-
2. Wstęp do programowania w języku C+ + dzaju w programach bardziej z ożonych może być czasem trudny do znalezienia. W unikaniu tego typu b ędów bardzo pomocne jest stosowanie wcięć w pisanym kodzie. Przejrzystość zapisu i grupowanie instrukcji pomaga w analizie kodu, a w razie nieprawid owego dzia ania programu - w znalezieniu b ędu. Zasady robienia wcięć atwo poznasz, śledząc sposób formatowania tekstów w programach, które zamieściliśmy w podręczniku. Możesz również wypracować w asny sposób formatowania treści programu, ważne jest, aby konsekwentnie się go trzymać. Zagnieżdżanie : Instrukcje warunkowe mogą być zagnieżdżane wewnątrz siebie. Przenstrukcji warunkowej analizuj przyk ad wzięty z życia: Jeśli do jutra wyzdrowieję, to #include <iostream> #include <cstdio> using namespace std; jeśli będzie adna pogoda, pójdę na spacer, w przeciwnym wypadku będę czyta książkę; w przeciwnym wypadku // czyli jeśli nie wyzdrowieję jeśli będę się czu bardzo źle, będę leża w óżku, w przeciwnym wypadku zaproszę kolegę do domu Oczywiście, moglibyśmy tę wypowiedź jeszcze bardziej rozbudować (np.: Jeśli będzie adna pogoda, to jeśli kolega pożyczy mi rower, pojadę nad nekę, w przeciwnym wypadku pójdę na spacer), tworząc kolejne poziomy zagnieżdżenia instrukcji warunkowych. Liczba zagnieżdżeń powinna być jednak niezbyt duża, gdyż wraz z kolejnymi zagnieżdżeniami kod źród owy robi się coraz mniej czytelny. Jeśli już je stosujesz, nie zapomnij o wcięciach w zapisie i komentarzach, które pomogą ci później analizować kod w asnego programu. Napiszemy teraz program, który wykorzystuje zagnieżdżoną instrukcję warunkową. Przyk ad Program wyprowadza na ekran monitora najmniejszą z trzech podanych przez użytkownika wartości ca kowitych. W programie za ożyliśmy, że podawane przez użytkownika liczby będą ca kowite, a zmienne nazwiemy a, b, c. int main() { int a,b,c; cout «"Podaj pierwsza liczbę "; cin» a; cout «"Podaj druga liczbę "; 5 4 www.operon.pl
2.5. Instrukcje sterujące.analiza kodu programu nie powinna ci sprawić trudności; dla u atwienia przedstawiamy schemat blokowy algorytmu (ryc. 2.2), który jest realizowany w programie. Wskaż na nim warunki, które są zagnieżdżone, i warunek zewnętrzny. Ryc. 2.2. Schemat blokowy algorytmu wyświetlającego na ekranie najmniejszą liczbę z trzech podanych na wejściu * w w. o p e r o n. p l 55
2. Wstęp do programowania w języku C+ + #include <iostream> #include <cstdio> using namespace std; 2.5.2. Instrukcja wyboru switch W programie może się zdarzyć, że należy wybrać jeden z wielu sposobów postępowania, zależnie od wartości zmiennej. Spytajmy na przyk ad ucznia, która godzina lekcyjna w aśnie się zaczę a, i na podstawie odpowiedzi wypiszmy informację o aktualnie odbywającym się przedmiocie (używać tu będziemy operatora relacji ==, który zosta zasygnalizowany w rozdziale pierwszym). Oto stosowny program: int main() { int lekcja; cout «"Która godzina lekcyjna sie zaczę a? cin» lekcja; if (lekcja == 1) cout «"Masz teraz matematykę"; if (lekcja == 2) cout «"Masz teraz fizykę"; if (lekcja == 3) cout «"Masz teraz j. polski"; if (lekcja == 4) cout «"Masz teraz historie"; if (lekcja == 5) cout «"Masz teraz geografie"; if (lekcja == 6) cout «"Masz teraz informatykę"; if (lekcja > 6) cout «"Jesteś juz po lekcjach"; cin.ignore(); getchar() ; return 0; Program prosty i czytelny, ale jego dzia anie jest nieoptymalne. Za óżmy, iż użytkownik poda, że w aśnie zaczę a się pierwsza lekcja. Już przy pierwszej instrukcji warunkowej zachodzi prawdziwość określonego warunku, zostanie więc wypisany komunikat, że jest to lekcja matematyki. Teraz wykona się kolejna instrukq'a programu, a zatem będzie sprawdzany warunek, czy zmienna lekcja ma wartość 2. Oczywiście nie ma tej wartości, a więc wykona się sprawdzanie kolejnego warunku, czyjej wartość wynosi 3, aż do sprawdzenia, czy jest większa od 6. Można teraz zapytać, po co sprawdzać kolejne warunki, skoro już pierwszy z nich jest prawdziwy. Ponieważ warunki określone w kolejnych instrukcjach wykluczają się wzajemnie, to spe nienie jednego z nich powinno zablokować sprawdzanie kolejnych, których zajście jest już i tak niemożliwe. Masz raq'ę, ale do zadań procesora należy wykonywanie wszystkich instrukcji po kolei. Jak zatem skonstruować kod, aby uniknąć badania warunków, które i tak nie zajdą, jeśli jeden z wcześniejszych zosta spe niony? Problem ten rozwiązuje dodanie po każdym warunku if instrukcji e l s e - możesz samodzielnie zapisać taki kod programu. Z pewnością zauważysz, że takie postępowanie wymaga wiele pisania i jest ma o czytelne. Zawi ą konstrukcję warunków zagnieżdżonych możemy zastąpić instrukcją switch. 56 www.operon.pl
2.5. Instrukcje sterujące ww.operon.pl 57
2. Wstęp do programowania w języku C+ + Ryc. 2.3. Schemat blokowy instrukcji switch Jeśli skonstruujesz swój program w ten sposób, zmniejszysz liczbę porównań zmiennej z wartościami, które mog a przyjąć, a przy tym twój kod źród owy stanie się bardziej czytelny. Instrukcję s w i t c h można również wykorzystać bez używania instrukcji break. Robimy tak w sytuacjach, gdy chcemy, aby wykona y się instrukcje zarówno występujące po etykiecie znalezionej wartości, jak i wszystkie występujące po kolejnych etykietach. Dla przyk adu popatrz na efekt dzia ania programu, umieszczony bezpośrednio po jego kodzie: 58 w w w. o p e r o n. p l
2.5. Instrukcje sterujące
2. Wstęp do programowania w języku C+ + która ma być powtarzana w pętli. Można w tym miejscu umieścić blok instrukcji, wtedy wszystkie one będą się wykonywa y w pętli. Chociaż w naszym przyk adzie w pętli wykonuje się tylko jedna instrukcja, ujęliśmy ją w klamry, nie jest to jednak konieczne. Sk adnia pętli for for (instrukcja początkowa; warunek sterujący; instrukcja kroku) instrukcja; gdzie: instrukcja początkowa - instrukcja wykonana przed pierwszym obiegiem pętli, zwana również inicjującą warunek sterujący - wyrażenie, którego logiczna wartość jest badana przed każdym obiegiem pętli -jeśli jego wartość jest t r u e (czyli jest różna od zera), to pętla wykona się kolejny raz, w przeciwnym wypadku następuje wyjście z pętli instrukcja kroku - instrukcja wykonana po każdym przebiegu pętli, najczęściej modyfikuje tak zwany licznik pętli Rozważmy teraz prosty przyk ad wyświetlający w kolumnie liczby od 0 do 20. Przy liczbach niepodzielnych przez 3 znajduje się odpowiedni komentarz. Oto program: Instrukcja kroku postaci i++ jest instrukcją inkrementacji zmiennej i odpowiada wyrażeniu i = i + 1. Ten bardzo wygodny skrót bywa używany nie tylko w pętlach. instrukcja inkrementacji w c++ i++ odpowiada i = i+1 instrukcja dekrementacji w c++ i - - odpowiada i = i-1 60 www.operon.pl
2.5. Instrukcje sterujące Pętla for w C+ + jest bardzo elastyczna. Możemy na przyk ad w tej retli pominąć dowolną instrukcję występującą w nawiasie, musimy jednak zachować średnik. Pętla ta może wyglądać tak: for ( ; ; ), co oznacza pętlę nieskończoną. Brak warunku sterującego oznacza, że jest on zawsze prawdziwy. Pętla ta nie wymaga żadnego licznika, dzięki czemu można ją upodobnić w dzia aniu do pętli, które omawiamy w dalszej części rozdzia u. Kolejną pętlą w C++ jest pętla while. Pętla ta wykonuje się kolejny raz, gdy wyrażenie jest prawdziwe (czyli ma wartość różną od zera). Sk adnia pętli while while (wyrażenie) instrukcja; gdzie: wyrażenie -wyrażenie przyjmujące wartość logiczną prawda" albo fa sz" instrukcja - istrukcja wykonywana w pętli Napiszmy prosty program wyświetlający na ekranie znaki podane z klawiatury do momentu, aż podamy znak k". Jeśli w tym programie użytkownik poda na początku znak k", pętla w h i l e nie wykona się nawet jeden raz. Przedstawimy teraz nieco bardziej skomplikowany przyk ad z zastosowaniem pętli while: Program oblicza wynik dzielenia ca kowitego dwóch liczb podanych z klawiatury. Algorytm polega na wielokrotnym odejmowaniu dzielnika od dzielnej i liczeniu wykonanych powtórzeń w pętli while.»w.operon.pr 61
2. Wstęp do programowania w języku C+ + Pętla while sprawdza warunek przed wykonaniem instrukcji wewnątrz pętli, instrukcja ta zatem może nie wykonać się wcale. 2.5.5. Instrukcja pętli do... while Poznasz teraz pętlę do... while. Pętla ta wykonuje się kolejny raz, gdy wyrażenie jest prawdziwe (czyli ma wartość różną od zera). Sk adnia pętli do... while do instrukcja while (wyrażenie); gdzie: instrukcja - instrukcja wykonywana w pętli wyrażenie - wyrażenie przyjmujące jedną z dwóch wartości logicznych: prawda albo fa sz Zacznijmy od prostego programu rysującego na ekranie 4 gwiazdki: 62 www.operon.pl
2.5. Instrukcje sterujące Program będzie dzia a tak samo, jeśli zamiast warunku, którego prawdziwość jest sprawdzana, umieścimy w ostatniej linii wyrażenie, którego wartość będzie sprawdzana. Zgodnie z semantyką pętli, czyli opisem jej dzia ania, dopóki wyrażenie nie ma wartości 0, będzie się wykonywa kolejny przebieg tej pętli. Zadanie, które zostanie wykonane (narysowanie 4 gwiazdek), pokazuje mechanizm dzia ania pętli do... while, ale równie dobrze modo być zrealizowane za pomocą pętli for. Z góry za ożyliśmy, że chcemy otrzymać 4 gwiazdki na ekranie monitora. Przyjrzyjmy się następnemu przyk adowi, który ilustruje bardzo częsty sposób użycia pętli do... while: www.operon.p! 63
2. Wstęp do programowania w języku C+ + Przyk ad Napiszmy program obliczający pole kwadratu o podanej d ugości boku W wypadku podania przez użytkownika niew aściwej wartości, to jest: ujemnej lub zero, program powinien prosić o podanie w aściwej wartości Przeanalizuj poniższy kod programu: Warunek pętli do... while jest sprawdzany po jej wykonaniu, a więc bez względu na to, jaką wartość podamy, pętla wykona się chociaż raz. Pętla wykona się jednokrotnie, gdy za pierwszym razem podamy wartość dodatnią. W wypadku podania wartości, która nie może być bokien kwadratu, pojawi się komunikat o b ędnej wartości i ponownie wykona się pętla. Tak będzie aż do momentu, gdy podamy dodatnią d ugość boku. Pętla do... while wykonuje się co najmniej jeden raz w programie, ponieważ warunek wyjścia jest sprawdzany na końcu. Warto wiedzieć, że w C+ + każdą pętlę można zastąpić inną. Twórcy języka przewidzieli trzy rodzaje pętli, ponieważ pewne zagadnienia atwiej i przejrzyściej można zapisać jednym rodzajem pętli, natomiast w innych wypadkach bardziej użyteczne mogą być pozosta e pętle. 2.5.6. Instrukcje break i continue sterujące wykonaniem pętli Instrukcje wymienione w tym rozdziale nie powinny się pojawić w twoich programach. Używanie tych instrukcji nie jest zgodne z kanonem dc 64 www.operon.i
2.5. Instrukcje sterujące brego programisty i sprawia, że program staje się ma o czytelny. Podajemy je jednak dla lepszego zrozumienia innych programów napisanych z ich użyciem. Przy okazji instrukcji s w i t c h przedstawiliśmy typowe użycie instrukcji break. Teoretycznie, instrukcja ta może być zastosowana we wszystkich wymienionych wcześniej pętlach w celu ich natychmiastowego przerwania, jednak odradzamy takie jej użycie. Spójrz na przyk ad programu, który wyświetla liczby parzyste, dopóki ich suma nie przekroczy 20: =include <iostream> =include <cstdio> using namespace std; W pierwszej linii znajdującej się wewnątrz pętli for wyprowadzana jest na ekran monitora podwojona wartość zmiennej i. Drugą instrukcją w pętli jest obliczanie sumy liczb już wyprowadzonych na ekran monitora. Następnie sprawdzany jest warunek, czy suma ta przekroczy a wartość 20. Jeśli tak, występuje wyjście z pętli, realizowane za pomocą instrukcji break, czyli przerwana zostaje instrukcja iteracji. Na ekran monitora zostaną wyprowadzone liczby: 0, 2, 4, 6, 8, 10. Przy szóstym przebiegu pętli warunek określający wyjście z pętli zosta spe niony, a więc nie będzie już kolejnej iteracji. Wyświetlony zostanie napis: Jestem poza p ę t l a i wykonywać się będą pozosta e instrukcje, których już w przyk adzie nie ujęliśmy. Liczbę instrukcji wykonanych w pojedynczym przebiegu pętli można modyfikować za pomocą instrukcji c o n t i n u e - po jej napotkaniu nie zostaje przerwane dzia anie ca ej pętli, a jedynie tego konkretnego przebiegu, który jest realizowany, i następuje przejście do kolejnego. Zatem w przebiegu pętli część instrukcji zostaje pominiętych. Instrukcje sterujące pętlą: break i continue www.operon.pl
2. Wstęp do programowania w języku C+ + Oto przyk ad programu: Dla liczb O i 3 spe niony by warunek zerowania się reszty z dzielenia liczb przez 3 (% jest operatorem reszty z dzielenia), a więc wykona a się instrukcja c o n t i n u e - ignorujemy dalsze instrukcje określone w pętli (czyli wyprowadzenie na ekran monitora napisu: n i e j e s t p o d z i e l - ne przez 3) i przechodzimy do jej następnego obiegu. Dlatego dla tych w aśnie liczb nie zosta wyświetlony tekst. Pamiętaj, że to jest tylko przyk ad na zastosowanie instrukcji c o n t i n u e. Gdybyśmy jednak rzeczywiście chcieli programowo rozwiązać to zadanie, czytelniej wygląda aby implementacja w sposób przedstawiony poniżej: 66 www.operon.pl