Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński Paweł Boiński PDF by tommy@tommy.ltd.pl Kurs języka C++ http://www.kurs-cpp.prv.pl/ 1 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński Język C++ jest jednym z najbardziej popularnych języków używanych przez programistów na całym świecie. O jego uniwersalności świadczy przede wszystkim zróżnicowanie pisanych w nim programów. Mimo dość zaawansowanego już wieku języka C jego nowa wersja czyli C++ nadal się rozwija. Niepodważalną zaletą tego języka jest jego prostota oraz obiektowość rozumiana w szerokim sensie. Nie przez przypadek to języki obiektowo zorientowane zawojowały i podbiły rynek programistyczny. Wszystkich zapraszam do przeczytania tego kursu i zapewniam, że pomoże on wam w pisaniu efektownych i efektywnych programów. Kurs podzielony jest na rozdziały. Każdy z nich dotyczy nowego zagadnienia. Uwaga!!! Nie rezygnuj z kontynuowania nauki po przeczytaniu pierwszych kilku rozdziałów!!! Być może wydadzą Ci się one trochę nudne, są jednak koniecznym wprowadzeniem do pisania programów. Dotyczą one przede wszystkim podstaw języka C i C++. Jeżeli pisałeś już programy w C (lub C++) to możesz je pominąć. Zachęcam jednak do przejrzenia ich - być może znajdziesz coś o czym zapomniałeś, a z pewnością odświeżysz sobie pamięć. Moja przygoda z programowaniem zaczęła się od języka BASIC, którego możecie nie pamiętać. Były to czasy gdy światem komputerowym "rządziły" takie maszyny jak Commodore 64, Atari XT, ZX Spectrum. Moim kolejnym krokiem było zapoznanie się z językiem Pascal, potem Turbo Pascal, a następnie z Object Pascalem. Stąd już prosta droga prowadzi do języka C++. 2 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński KURS JZYKA C++............................................................................................1 ROZDZIAA 1 PIERWSZY PROGRAM..............................................................4 ROZDZIAA 2 ZMIENNE .................................................................................7 ROZDZIAA 3 ZAKRES WIDOCZNOŚCI (WAŻNOŚCI) I ZASAANIANIE NAZW 10 ROZDZIAA 4 INSTRUKCJE STERUJCE CZ.1...............................................14 ROZDZIAA 5 INSTRUKCJE STERUJCE CZ.2...............................................18 ROZDZIAA 6 INSTRUKCJE STERUJCE CZ.3...............................................22 ROZDZIAA 7 COUT CZY PRINTF ?...............................................................26 Printf..............................................................................................................26 Cout...............................................................................................................28 ROZDZIAA 8 MANIPULATORY ....................................................................30 ROZDZIAA 9 FUNKCJE................................................................................34 DODATEK A ..........................................................................................................37 3 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński ozdział 1 Pierwszy program W tym rozdziale opisane są elementarne podstawy języka C: -konstrukcja programu -konstrukcja funkcji -importowane bibliotek Najprostszym programem, który robi cokolwiek jest aplikacja typu "hello world". Jej zadaniem jest wyświetlenie napisu na ekranie monitora. #include void main(void) { printf("hello world"); } Zacznijmy od ogólnej konstrukcji. W każdym programie w C++ musimy wyróżnić główną funkcję o nazwie main. To właśnie ona jest uruchamiana gdy chcemy wykonać program. Część void main(void) nazywamy nagłówkiem funkcji. Składa się on z nazwy typu zwracanego przez funkcję, nazwy funkcji i listy argumentów jakie przyjmuje funkcja. Typ void tak naprawdę oznacza brak typu - nasza funkcja ma wypisywać na ekranie tylko napis "hello world", nie musi więc zwracać żadnej wartości i nie potrzebuje żadnych argumentów. Po nagłówku następuje definicja funkcji którą ma postać { //.. //instrukcje //.. } Dla ścisłości dodam, że dwa ukośniki (//) oznaczają komentarz - wszystko to co znajduje się po nich aż do końca linii jest ignorowane przez kompilator. W naszym programie jest tylko jedna instrukcja printf() służąca do wypisywania różnych rzeczy na ekranie - opis tej funkcji można znalezć w pomocy do kompilatora, a użytkownicy linuksa mogą przeczytać opis każdej instrukcji w manualu (polecenie man 4 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński np. man printf ). W najprostszej postaci wywołanie funkcji printf wymaga podania jednego parametru - łańcuha znaków (string) albo zmiennej niekoniecznie typu łańcuchowego. Zauważmy, że po każdej instrukci stawiamy znak ; (średnik). Taka konwencja zapisu przyjęła się w bardzo wielu językach np. pascal, java. Po kompilacji i wykonaniu programu na ekranie wyświetlony zostanie napis hello world (bez cudzysłowów). Co by się stało gdybyśmy dodali jeszcze jedna linijkę printf("hello world") ? Otrzymalibyśmy na ekranie napis hello worldhello world. Dlaczego? Wynika to ze specyfikacji funkcji printf. Po wykonaniu tej funkcji znak kursora nie jest przenoszony automatycznie do następnej linii. Aby uzyskać pożądany efekt stosujemy tzw. znaki specjalne. Jednym z nich jest znak łamania linii \n. Otrzymujemy zatem instrukcję o postaci printf("hello world\n"); która spełni nasze oczekiwania. Ważnym elementem, o którym do tej pory nie wspomniałem są biblioteki języka C++. Są to jakby gotowe zestawy funkcji, które możemy wykorzystać w naszych programach. Jedną z takich bibliotek jest stdio.h, która zawiera funkcję printf. Importowanie biblioteki polega na zasygnalizowaniu kompilatorowi, że chcemy z niej skorzystać. Istnieją dwa sposoby zapisy dodania biblioteki do programu: #include lub #include"nazwa_biblioteki" Na razie wystarczy, że zapamiętasz jeden ze sposobów (o różnicy napiszę przy innej okazji) i będziesz go używał. 5 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński 6 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński ozdział 2 Zmienne Bez zmiennych trudno sobie wyobrazić działanie jakiegokolwiek programu komputerowego. Istnieje wiele rodzajów typów zmiennych. Co to jest typ zmiennej ? Ogólnie mówiąc jest to definicja dotycząca zawartości danej zmiennej. Wiadomo przecież, że liczby całkowite są przechowywane inaczej w pamięci komputera niż np. liczby rzeczywiste, inne też są dopuszczalne operacje na tych typach zmiennych. Programista musi poinformować kompilator ze zmienną jakiego typu ma do czynienia. Typy można podzielić na: -podstawowe(fundamentalne) -pochodne lub -wbudowane -zdefiniowane przez programistę Najważniejsze typy zmiennych podstawowych to: a)do reprezentacji liczb całkowitych Short int, int, long int (różnią się zakresami) b)do reprezentacji liczb rzeczywistych float, double, long double (różne dokładności) c)do reprezentacji znaków char, wide char Sposób deklaracji: Jest on bardzo prosty - składa się z nazwy typu i nazwy zmiennej. Int I; // deklaracja zmiennej całkowitej i , czytamy i jest zmienną typu int Double x; // x jest zmienną typu double, Char z; // z jest zmienną typu char. Mając takie zmienne możemy je wykorzystać w dalszych instrukcjach np. I = 5; // przypisz zmiennej i wartość 5 I = I + 2; // można tak, gdyż kompilator najpierw oblicza wartość wyrażenia stojącego po prawej stronie operatora = a następnie przypisuje tę wartość zmiennej stojącej po lewej stronie; w tym przypadku zwiększamy zmienną I o 2. z = a ; przypisanie zmiennej z znaku a 7 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński Oprócz typów podstawowych możemy także tworzyć typy pochodne(w rzeczywistości nie tworzymy typów pochodnych a tylko definiujemy obiekty pochodne od typów podstawowych - na razie zapamiętaj tylko, że każda zmienna jest obiektem) . Często początkujący programiści zadają pytanie czy są one konieczne. Odpowiedz jest prosta - są niezbędne. Nie tylko ułatwiają pracę, ale również są w niektórych sytuacjach niezastąpione. Przed wymienieniem tych typów chcę Ci powiedzieć, że na razie zajmiemy się tylko jednym (pierwszym) z nich a resztę zostawimy sobie na pózniej. Typy pochodne: -tablica -referencja -wskaznik -funkcja Tablica jest to uporządkowany zbiór zmiennych o tym samym typie. Wyobrazmy sobie, że potrzebujemy 200 zmiennych typu int. Deklarowanie takiej liczby zmiennych byłoby samobójstwem nie wspominając o szukaniu nazw dla nich. To samo możemy załatwić jedną linijką Int t[200]; // jest to deklaracja tablicy 200 obiektów typu int A jak się odwoływać do takich obiektów?? W ten sposób: t[20] = 30; // do 21 elementu tablicy przypisz wartość 30 Nie, nie pomyliłem się, do 21 a nie 20 - wyjaśnia to fakt, że elementy tablicy są numerowane od 0 a nie od 1. Zatem w naszej tablicy możemy posługiwać się numerami pól (czyli elementów tablicy) od 0 do 199. Może początkowo być to przyczyną błędów, ale po pewnym czasie można się do tego przyzwyczaić. 8 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński 9 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński ozdział 3 Zakres widoczności (ważności) i zasłanianie nazw Skoro umiesz już deklarować obiekty (zmienne) nie sposób pominąć tematu zasłaniania (zwanego czasem przesłanianiem) nazw. Aby wyjaśnić co to takiego jest konieczne jest zdefiniowanie następujących pojęć: - czas życia obiektu - jest to czas od momentu powstania obiektu (powołania go do życia aż do czasu jego zlikwidowania - zakres widoczności obiektu - jest to zakres programu, w którym możemy odwołać- się do tego obiektu (inaczej mówiąc jest to zakres programu, w którym kompilator widzi dany obiekt) Mając dany obiekt musimy zadbać o to aby był on widoczny we wszystkich miejscach, w których będzie wykorzystywany. Możemy wyróżnić kilka zakresów ważności: - zakres lokalny - jeżeli jest ograniczony do pewnego fragmentu programu. Przykładem może być- blok instrukcji { //... } Każda zmienna(obiekt), która jest zadeklarowana wewnątrz takiego bloku jest znana tylko i wyłącznie w nim. Czas życia obiektu kończy się w momencie końca bloku instrukcji. Np. { //... { int a = 15; cout << a; #1 } 10 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński cout << a; #2 } W #1 zostanie wypisana nazwa, ale w #2 jest błąd (taki program się nie skompiluje). Obiekt a jest widoczny i istnieje tylko wewnątrz tego bloku instrukcji, w którym został stworzony. Poza tym blokiem nie ma żadnego obiektu a. - zakres globalny (pliku) - na razie omawiane programy mieszczą się w jednym pliku, więc wystarczy zapamiętać- , że obiekt zadeklarowany poza obszarem bloku instrukcji (również bloku funkcji - patrz następny podpunkt) jest widziany w całym programie (o ile nie zostanie przesłonięty), mówimy, że jest to obiekt globalny Np. int a; main (void) { #1 } #2 Obiekt a jest obiektem globalnym - jest widziany zarówno w #1 jak i w #2 - zakres funkcji taki zakres ważności ma etykieta (wykorzystywana przez instrukcję goto), o której może wspomnę pózniej, choć jak się przekonasz nie jest ona niezbędna. Wymieniam ją tutaj tylko ze względu na kompletność informacji - zakres klasy - nazwa widoczna jest w całej klasie brak przykładu - będzie gdy już dowiesz się co to jest klasa Zasłanianie nazw: Możemy zadeklarować dwa obiekty o tej samej nazwie - jedyny warunek - muszą mieć inny zakres ważności. Zasłanianie nazw jest bardzo intuicyjne. Jeżeli mamy obiekt globalny X to zadeklarowanie w pewnym bloku instrukcji obiektu o nazwie X przesłoni obiekt globalny X. Oczywiście będzie on cały czas istniał, jednak odwołanie się w tym bloku instrukcji do X spowoduje odwołanie się do obiektu X zadeklarowanego w tym bloku. Można także odwołać się do obiektu globalnego - z pomocą przychodzi nam operator zakresu ::, który umieszcamy przed interesującą nas zmienną. Zastanów się nad wynikiem działania tego programu: Wskazówka: instrukcja cout wyrzuca napisy na ekran, zapis cout << x << endl; jest 11 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński równoważny następującemu: cout << x; cout << endl; gdzie endl do znak końca linii (END Line). Przykład: #include int x = 5; void main(void) { cout << x << endl; int x = 10; { int x =15; cout << x <} cout << x << endl; cout << ::x << endl; } Program wypisz na ekranie: 5 15 10 5 Jeżeli zgadza się to z twoimi przewidywaniami to gratuluję - zrozumiałeś ten rozdział. 12 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński 13 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński ozdział 4 Instrukcje sterujące cz.1 Przejdę teraz do opisu tzw. instrukcji sterujących bez których nie ma mowy o napisaniu jakiegokolwiek bardziej złożonego programu. Na początku mogą się one wydawać nieco skomplikowane ale po pewnym czasie nabierzesz takiej wprawy, że będą ci się one wydawały zupełnie naturalne i nie będziesz na nie zwracał uwagi(co często prowadzi do trudnych do wykrycia błędów). Instrukcja if ... Instrukcja if ... służy do sprawdzenia warunku, a następnie wykonania, bądz niewykonania kolejnych instrukcji. Jej postać jest następująca: if (wyrażenie) { //instrukcja/e } Jeżeli wyrażenie jest spełnione to instrukcje w zamknięte w klamrach są wykonywane. Czym jest wyrażenie? Tutaj wiele zależy od nas samych. W skrajnym przypadku może to być jedna zmienna i to niekoniecznie typu bool. Otóż w C++ za prawdę uważa się wszystko co jest różne od zera. Zatem liczba int o wartosci 1 jest w tym wypadku traktowana jako prawda. Nas zapis wyglądałby np. tak: int liczba_int=1; if (liczba_int) printf("prawda"); po wykonaniu tych instrukcji zobaczylibyśmy na ekranie napis "prawda" Podobnie jest w przypadku następującego programu int liczba_int; //... if (liczba_int>0) printf("prawda") Napis prawda ukaże się nam gdy liczba_int jest większa od zera. A co zrobić gdy chcemy sprawdzić czy liczba znajduje się w danym zakresie? np. czy jest 14 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński większa od 5 ale mniejsza od 10? Można to zrobić tak: if (liczba_int>5) if (liczba_int<10) printf("liczba nalezy do przedziału (5,10)"); Jest to jednak mało eleganckie i bardzo niepraktyczne rozwiązanie. Aatwo sobie wyobrazić co by było gdybyśmy mieli do sprawdzenia np. 10 warunków... Z pomocą przychodzą nam wyrażenia złożone. Jak sama nazwa wskazuje składają się one z kilku części. Przykład : if ( (liczba_int>5) && (liczba_int<10) ) printf("liczba nalezy do przedziału (5,10)"); Tutaj widzimy, że sprawdzane są dwa warunki. Połączeniem jest symbol && zwany operatorem koniunkcji. Aby wyrażenie było prawdziwe obie jego części muszą być prawdziwe. Innym często stosowanym operatorem jest alternatywa ||. Aby takie wyrażenie było spełnione wystarczy, że jedna ze stron jest spełniona. Pełny opis operatorów logicznych znajduję się w dodatku B. Pętle Instrukcja for Czy nie zastanawiałeś się np. jak wypełnić tablicę, powiedzmy, kolejnymi liczbami naturalnymi począwszy od jeden. Załóżmy, że naszą tablicą jest tablica o nazwie Liczby o następującej deklaracji int Liczby[10]; Przypominam, że elementy są numerowane od zera. Można nasze zadanie wykonać tak: Liczby[0]=1; Liczby[1]=2; .... Liczby[9]=10; No tak, powiesz, że proste. Wyobraz sobie teraz tablicę o 100 tysiącach elementów. Trudne ?? Oczywiście, że nie. Stosujemy instrukcję for. Nasz programik wyglądałby następująco: for (int i=0; i<100000; i=i+1) { Liczby[i]=i+1; 15 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński } A teraz komentarz: Instrukcja for ma postać : for (zmienna sterująca=stan początkowy ; warunek wykonywania ; operacja sterująca) { //instrukcje } Naszą zmienną sterującą jest w tym przypadku zmienna i. Początkowo ma wartość równą 0. Warunkiem wykonywania jest wyrażenie i<100000. Należy to rozumieć w następujący sposób. Dopóki zmienna i jest mniejsza od 100000 wykonuj zadanie. W momencie gdy zmienna i jest większa lub równa 100000 przestań wykonywać ciało pętli (czyli instukcje w niej zawarte). Ostatnim polem jest operacja sterująca. Mówi ona co po każdym wykonaniu pętli ma być wykonane ze zmienną sterującą. W naszym przypadku jest to zwiększenie o 1. UWAGA!!! Podkreślam, że operacja(instrukcja) sterująca jest wykonywana na koniec każdego wykonania pętli. Przytoczony programik jest najprostszym przykładem użycia pętli for. Uwierz mi już teraz ta pętla jest najczęściej wykorzystywana we wszystkich programach, wkrótce sam się o tym przekonasz. 16 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński 17 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński ozdział 5 Instrukcje sterujące cz.2 Jeżeli już zapoznałeś się z poprzednimi instrukcjami pora przejść do kolejnych. Będą to również pętle. Jak to, pętle już były powiesz. Rzeczywiście, jednak instrukcja for nie zawsze jest najlepszym rozwiązaniem. W niektórych przypadkach znacznie łatwiej jest używać innych instrukcji. Instrukcja while ... Jej postać to while (warunek) { // instrukcje } Instrukcja while działa tak długo, jak spełniony jest warunek. Zauważ, że jeżeli warunek nie jest spełniony na początku pętla nigdy się nie wykona. Jest to bardzo ważna uwaga i radzę Ci byś dobrze ją zapamiętał. Aby lepiej zrozumieć instrukcję while przeanalizujmy następujący program #include iostream.h void main(void) { int wysokosc_trojkata=10; while (wysokosc_trojkata>0) { for (int licznik=0; licznik cout << '*' ; cout << endl; wysokosc_trojkata--; } } Na wstępie już wyjaśniam co robi cout (console out). Jest to instrukcja, która została wprowadzona w C++ w celu ułatwienia wyprowadzania znaków na ekran. Aby ją wykorzystać należy dodać bibliotekę iostream.h . Poprzednio używałem w przykładach 18 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński instrukcji printf, jednak dobrze abyś wiedział, ze nie jest to jedyny sposób wypisywania napisów (ponadto printf pochodzi jeszcze z języka C ). Instrukcję cout wywołujemy z jednym lub więcej parametrami. cout << hello wypisze na ekranie hello cout << endl spowoduje, że zostanie wypisany znak końca linii (czyli nastąpi przejście do nowej linii) Dodam, że endl to skrót od ENd Of Line a w wyświetlanym ciągu można używać również znaków specjalnych. Tyle dygresji na temat cout. Wracając do naszej pętli czy wiesz już co pojawi się na ekranie?? Będzie to trójkąt złożony z gwiazdek, dokładnie taki: ********** ********* ******** ******* ****** ***** **** *** ** * Prześledzmy działanie programu krok po kroku. /* ta linia definiuje i inicjalizuje zmienna przypisując jej wartość 10; */ int wysokosc_trojkata=10; /* dopóki zmienna jest większa od zera wykonujemy ciało pętli */ while (wysokosc_trojkata>0) { /* Wypisujemy tyle gwiazdek ile wynosi zmienna wysokosc_licznika */ for (int licznik=0; licznik cout << '*' ; /* przechodzimy do nowej linii */ cout << endl; /* zmniejszamy wysokość trójkąta o1*/ wysokosc_trojkata--; } Na początku zmienna wysokosc_trojkata ma wartość 10. Jest > 0 czyli wchodzimy do pętli while. Tam wypisujemy za pomocą pętli for 10 gwiazdek. Po zakończeniu pętli for przechodzimy do nowej linii. Zmniejszamy wysokosc_trojkata o 1. ( gdyby tej instrukcji nie było program działałby w nieskończonej pętli). Wracamy do warunku pętli while. Teraz zmienna wysokosc_trojkata ma wartość 9 nadal jest więc większa 0 znowu 19 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński wykonujemy ciało pętli. Widać, że będzie tak się działo dopóki zmienna wysokosc_trojkata nie będzie miała wartości 0. Wówczas pętla while się zakończy. Mam nadzieję, że dobrze wyjaśniłem działanie tego programu. Najważniejszą rzeczą, którą trzeba zapamiętać to to, że warunek pętli while jest sprawdzany na początku. Dlaczego? Otóż jest jeszcze jeden typ pętli, który różni się tylko momentem, w którym sprawdzany jest warunek wykonania. Jest to pętla do ... while. Instrukcja do ... while Jej działanie jest prawie identyczne jak w przypadku instrukcji while... . Najważniejszą różnicą jest to, że warunek sprawdzany jest na końcu. Niesie to za sobą bardzo ważne konsekwencje pętla zostanie ZAWSZE wykonana przynajmniej jeden raz. Jeżeli poprzedni program nieco zmodyfikujemy(zamieniamy while... na do...while) : #include "iostream.h" void main(void) { int wysokosc_trojkata=10; do { for (int licznik=0; licznik cout << '*' ; cout << endl; wysokosc_trojkata--; } while (wysokosc_trojkata>0); } Wynik będzie identyczny. Ale zauważ, że o ile taki program #include iostream.h void main(void) { int wysokosc_trojkata=0; do { for (int licznik=0; licznik20 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński cout << '*' ; cout << endl; wysokosc_trojkata--; } while (wysokosc_trojkata>0) } nie wypisałby na ekranie nic, to taki (z pętla while): wypisałby znak końca linii. Jest to spowodowane tym, że warunek (wysokosc_trojkata>0) jest sprawdzany na końcu, po przejściu pętli. 21 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński ozdział 6 Instrukcje sterujące cz.3 Znowu instrukcje sterujące?! zapytasz. Spokojnie, to już ostatni rozdział na ich temat. Tym razem zajmiemy się instrukcją switch, goto, break, continue. Instrukcja switch Wyobraz sobie następującą sytuację: Masz zrobić menu w trybie tekstowym, które będzie sterowane za pomocą wczytywanych liczb np. 1) Nowa baza 2) Dodaj element 3) Usun element 4) Koniec Program ma pobierać numer komendy z klawiatury i wykonywać odpowiednią akcję. Pomijając kwestię wczytywania z klawiatury, dotychczas omówione instrukcje pozwalają na rozwiązanie tego zadania w następujący sposób: int NumerKomendy;// Deklaracja zmiennej, w której będzie przechowywany numer komendy cout << Podaj numer komendy: ; // Wypisanie komunikatu cin >> NumerKomendy; // Pobranie numeru z klawiatury if ( NumerKomendy == 1 ) { // ... Tutaj odpowiedni kod odpowiadający za utworzenie nowej bazy } if (NumerKomendy == 2 ) { // ... Tutaj odpowiedni kod odpowiadający za dodanie elementu } ...itd. Mało efektywne i dużo trzeba pisać. W takiej sytuacji niezastąpiona jest instrukcja switch. Jak sama nazwa wskazuje pełni ona rolę przełącznika. 22 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński Jej składnia jest następująca: switch (ZmiennaSterujaca) { case wartosc : //instrukcje break; } W naszym przypadku odpowiedni byłby taki kod: int NumerKomendy; cout << Podaj numer komendy: ; cin >> NumerKomendy; switch ( NumerKomendy ) { case 1 : // ... Tutaj odpowiedni kod odpowiadający za utworzenie nowej bazy break; case 2 : // ... Tutaj odpowiedni kod odpowiadający za dodanie elementu break; case 3 : // ... Tutaj odpowiedni kod odpowiadający za usuniecie elementu break; case 4 : // ... Tutaj odpowiedni kod odpowiadający za wyjscie break; default : cout << Zla komenda ; break; } Wydaje się, że jest to bardzo intuicyjne. Jako parametr switch podajemy zmienną, której wartość wpływa na wykonywane akcje. Następnie po case podajemy wartość. Jeżeli jest ona taka sama jak wartość zmiennej sterującej to zostanie wykonana akcja. Ich wykonywanie kończy się po napotkaniu instrukcji break. Jeżeli żadna wartość nie jest taka sama jak wartość zmiennej to wykonana zostanie akcja zdefiniowana jako default (domyślny). UWAGA! Dopasowanie powoduje wykonanie wszystkich akcji następujących po napotkaniu pasującego case a aż do napotkania instrukcji break lub końca instrukcji switch. Np. Wykonanie poniższego programu int Numer = 2; // deklaracja zmiennej Numer i nadanie jej wartości 2 switch(Numer) { case 1: cout << A\n ; brak; case 2: cout << B\n ; case 3: cout << C\n ; 23 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński break; } spowoduje wypisanie na ekranie BC ani samego C. Zauważ, że dedfinicja akcji domyślnej (default) nie jest konieczna. Instrukcje break, continue, goto. Z instrukcją break spotkaliśmy się już w poprzednim paragrafie. Powoduje ona natychmiastowe zakończenie wykonywania instrukcji i można ją stosować również w pętlach for, while, do...while. Jeżeli mamy do czynienia z pętlami zagnieżdżonymi to wywołanie instrukcji break spowoduje zakończenie tej, w której się bezpośrednio znajduje. Instrukcja continue powoduje przerwane wykonywania pętli w danym przebiegu i rozpoczęcie wykonywania następnego przebiegu (nie ma więc sensu stosowanie jej w instrukcji switch tam jest jeden przebieg) np. int Licznik; for (Licznik=1; Licznik<10; Licznik++) { cout << A ; if (Licznik>5) continue; cout << B ; } da w wyniku napis na ekranie: ABABABABAAAAAA Instrukcja goto Wiele osob pomija albo pragnie pominąć tę funkcję. Jej działanie polega na skoku do pewnego określonego miejsca zaznaczonego etykietą. Mówi się, że stosują ją tylko zli programiści ale ja uważam, że są sytuacje gdy użycie goto jest wskazane np. przy natychmiastowym opuszczaniu wielokrotnie zagnieżdżonych pętli. Można sobie bez niej poradzić ale program byłby wtedy znacznie mniej czytelny. Ale pamiętaj : używaj jej w ostateczności. Przykład: cout << poczatek\n ; goto Etykieta1; cout << tego nie wypisze ; Etykieta1: cout << koniec\n ; Wynik to oczywiście: poczatek 24 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński koniec 25 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński ozdział 7 Cout czy printf ? O tych dwóch instrukcjach już wspomniałem wcześniej. Jak już wiesz, służą one do wypisywania napisów na ekranie. Ponieważ jeszcze przez dość długi czas omawiane przykłady będą opierały się na trybie dosowym postanowiłem dokładniej omówić te funkcje. Printf Jest to funkcja znajdująca się w bibliotece stdio.h aby z niej skorzystać musisz dodać na początku kodu: #include stdio.h Jej składnia wygląda następująco: printf(const char *format[, argument, ...]); Wygląda to paskudnie więc już tłumaczę. Parametrem tej funkcji jest zawsze ciąg znaków (może być pusty). Ciągi znaków zawsze zapisujemy w cudzysłowach. Może być zatem następujące wywołanie: printf( To trzeba wypisac ); Na ekranie pojawi się napis: to trzeba wypisac Jak wspomniałem ciąg może być pusty, zatem poprawnie jest także wywołanie printf( ); W tym przypadku nic nie zostanie wypisane. Jest jednak coś, co sprawia, że ta funkcja jest bardzo wygodna w użyciu. Są to tzw. Specyfikatory formatu ( ang. format specifiers). Nie będę tu omawiał wszystkich ponieważ jest ich zbyt dużo a wiele z nich pewnie nigdy nie użyjesz. Warto skupić się jednak na najważniejszych, czyli tych, które najczęściej są używane. Co to jest specyfikator formatu? Jest to wyrażenie, które określa format wyświetlanej informacji. Specyfikatory formatu zawsze są podawane w ciągu znaków i zaczynają się od znaku %. Myślę, że najlepiej będzię wytłumaczyć to na prostym przykładzie. Załóżmy, że mamy jakąś zmienna wynik typu integer i chcemy wyświetlić ją na ekranie. Umożliwia to właśnie funkcja printf a wygląda to tak: int wynik; wynik = 2*4+2; printf( W zmiennej wynik przechowywana jest wartosc = %i ,wynik); 26 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński Na ekranie ukaże się napis: W zmiennej wynik przechowywana jest wartosc = 10 A teraz opis działania. Jak zapewne widzisz w wywołaniu funkcji printf mamy ciąg znaków oraz zmienną wynik ( po przecinku). Tutaj, choć dopiero funkcje zostaną omówione w następnych rozdziałach, muszę już zapowiedzieć, że przy wywołaniu funkcji można użyć od zera do n argumentów. Jeżeli wywołujemy funkcje z więcej niż jednym argumentem to musimy je rozdzielić przecinkami. Właśnie w naszym przypadku jest taka sytuacja. Funkcja printf jest wywoływana z dwoma argumentami zatem wywołanie ma postać printf( argument1, argument 2). Wracając do specyfikatorów formatu zauważ, że pierwszym argumentem jest, tak jak to było do tej pory, ciąg znaków (czyli string). Różni się on tylko tym, że w jego wnętrzu mamy znak % a po nim literkę i . Tutaj tkwi właśnie cała tajemnica. Literka i to skrót od angielskiego integer czyli typu zmiennej, który zadeklarowaliśmy. Taki zapis mówi kompilatorowi, że chcemy aby została wyświetlona dana w postaci integer. Tą daną jest zmienna wynik i dlatego umieszczamy ją jako drugi argument. Oczywiście można użyć większej ilości zmiennych i nie muszą to być zmienne typu integer. Przykład: int zmienna1, zmienna2; // deklarujemy dwie zmienne typu integer zmienna1 = 14; zmienna2 = zmienna1 / 2; // zmienna2 to polowa ze zmiennej1 printf( zmienna 1 = %i \n zmienna 2 = %i , zmienna1, zmienna2); Wynik to: zmienna 1 = 14 zmienna 2 = 7 W powyższym programie mamy trzy parametry w wywołaniu printf. Jest to spowodowane faktem, że zastosowaliśmy dwa specyfikatory formatu musieliśmy dodać do nich zmienne. Zawsze specyfikatory czytamy od lewej do prawej i podstawiamy za nie kolejne argumenty, które są wymienione we funkcji printf. UWAGA!!! Nie możemy podać za małej ilości argumentów. Choć program się skompiluje bez błędów to wynik będzie zły w miejscu niepokrytych specyfikatorów zostaną wstawione dziwne liczby. Możesz sam to sprawdzić. Odwrotna sytuacja tzn. jest więcej argumentów za stringiem niż specyfikatorów w stringu nie spowoduje żadnych błędów wyświetlania nie zostaną wykorzystane wszystkie argumenty. Specyfikatory mają rozmaite właściwości i zastosowanie. Za ich pomocą można np. określić liczbę miejsc po przecinku wyświetlanej liczby albo sposób zaokrąglania liczb itd... 27 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński Pełną listę specyfikatorów możesz znalezć w dodatku B. Cout Jest to funkcja znajdująca się w bibliotece iostream.h aby z niej skorzystać musisz dodać na początku kodu: #include iostream.h Funkcja cout jest jedną z tzw. Funkcji strumieniowych ( ang. stream strumień). Strumień to dane płynące od zródła do celu np. z klawiatury na ekran. Funkcja cout zostałą wprowadzona dopiero w języku C++ ( printf było już w C ). Jej użycie w wielu przypadkach jest znacznie wygodniejsze od zastosowania printf , przede wszystkim wtedy, gdy mamy do wyświetlenia dużą liczbę zmiennych. Jej użycie jest bardzo proste np. cout << Na ekran \n ; Jak widać można w niej używać także symboli specjalnych ( patrz dodatek A), tutaj mamy \n czyli znak nowej linii. Możliwe jest również takie wywołanie: cout << napis1 << napis2 ; Funkcja wypisze na ekranie: napis1napis2 A jak wygląda wyprowadzanie na ekran wartości zmiennych ? Bardzo prosto. Rozważmy przykład omawiany przy funkcji printf. Dla przypomnienia : int zmienna1, zmienna2; // deklarujemy dwie zmienne typu integer zmienna1 = 14; zmienna2 = zmienna1 / 2; // zmienna2 to polowa ze zmiennej1 printf( zmienna 1 = %i \n zmienna 2 = %i , zmienna1, zmienna2); Wynik to: zmienna 1 = 14 zmienna 2 = 7 Napiszmy to samo z zastosowaniem cout. Przykład: int zmienna1, zmienna2; // deklarujemy dwie zmienne typu integer zmienna1 = 14; zmienna2 = zmienna1 / 2; // zmienna2 to polowa ze zmiennej1 cout << zmienna 1 = <Wynik to: 28 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński zmienna 1 = 14 zmienna 2 = 7 Jak widać wyprowadzenie zmiennej na ekran jest bardzo proste. Wystarczy napisać : cout << zmienna1; A co z formatowaniem wyjścia ?? Tutaj NIE możemy zastosować żadnych specyfikatorów typu. Istnieją jednak tzw. manipulatory ale o tym w następnym rozdziale. 29 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński ozdział 8 Manipulatory Manipulatory to specjalne rozkazy, które wrzucamy do strumienia. W łatwy sposób umożliwiają formatowanie strumienia. Przykład. Wiesz już, że możemy wyświetlić tekst w taki sposób: cout << jakiś tekst ; A co gdybyśmy chcieli wyświetlić w postaci heksadecymalnej zmienną? Wystarczy, że napiszemy cout << hex << nazwa_zmiennej; W tym przypadku manipulatorem jest hex, który mówi strumieniowi, że dane mają być wyświetlane w postaci heksadecymalnej. Warto zauważyć, że manipulatory nie są wyświetlane na ekranie. Wyróżniamy manipulatory bezargumentowe i argumentowe czyli, ładnie mówiąc po polsku, parametryzowane. Omówię osobno każdy z manipulatorów. Manipulatory bezargumentowe. 1. Manipulator ws. Skrót pochodzi od angielskiego white spaces czyli białe znaki. Powoduje on przeskoczenie wszystkich tzw. białych znaków takich jak np. tabulatory, spacje itp. 2. Manipulator ends. Powoduje wstawienie znaku końca napisu (NULL) (z ang. end of string koniec napisu). Stosowany przeważnie gdy wypisujemy coś nie na ekran, lecz np. do pliku , czy też do tablicy znaków odpowiednika typu string z Pascala(uwaga dla wtajemniczonych). 3. Manipulator endl. Jest to chyba najczęściej wykorzystywany manipulator. Jak sama nazwa wskazuje (z ang. end of line koniec linii) jego wstawienie powoduje zakończenie linii np. cout << jestem wspaniały << endl << i wielki. ; Da w rezultacie napis: Jestem wspaniały 30 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński i wielki. 4. Manipulatory oct, dec, hex. Te trzy manipulatory mają bardzo podobne działanie. Ich zadaniem, jak zapewne się domyślasz, jest formatowanie liczb. oct ustawia formatowanie na tryb oktalny(ósemkowy), dec - ustawia formatownie na tryb dziesiętny, hex ustawia formatowanie na tryb heksadecymalny. Takie manipulatory ułatwiają do maksimum zmianę formatu wyświetlanych liczb np. cout << dec << nazwa_zmiennej << a ósemkowo = << oct << nazwa_zmiennej << a heksadecymalnie = << hex << nazwa_zmiennej; 5. Manipulator flush. Strumień danych może być buforowany. Oznacza to, że dane nie trafiają natychmiast po wysłaniu do celu, lecz są przechowywane w specjalnej pamięci zwanej buforem, czyli jakby poczekalnią a dopiero potem przesyłane dalej. Manipulator flush stosujemy wówczas, gdy chcemy natychmiastowo opróżnić bufor. Jest to przydatne szczególnie podczas debugowanie programów, gdy chcemy na bieżąco śledzić to co dzieje się w programie. Manipulatory argumentowe (parametryzowane). 1. Manipulator setprecision. Wywołanie tego manipulatora ma postać setprecision(int), gdzie int w nawiasie oznacza liczbę typu całkowitego. Przy pominięciu manipulatora domyślnie zostanie przyjęta szóstka. Manipulator setprecision, jak sama nazwa wskazuje, pozwala na ustalenie precyzji z jaką wyświetlana jest liczba zmiennoprzecinkowa. Przykład: #include iostream.h int main(void) { double x = 2333.123456789; // deklaracja i definicja zmiennej x cout << x << endl; // wykorzystujemy manipulator endl cout << setprecision(3) << x << endl << setprecision(10) << x; return 0; } Wynik: 2333.123456 2333.123 2333.1234567890 2. Manipulator setbase. Jest to jakby odpowiednik manipulatorów bezargumentowych hex, bin, oct. Wywołanie ma postać setbase(int) gdzie wartość zmiennej int określa rodzaj systemu liczenia. 31 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński Przykład: #include iostream.h int main(void) { int x = 134; // deklaracja i definicja zmiennej x cout << x << endl; // wykorzystujemy manipulator endl cout << setbase(2) << x << endl << setbase(8) << x; return 0; } Wynik: 134 10000110 206 Jak widać manipulatory np. hex i setbase(16) są sobie równoważne. Uwaga: Jeżeli ustawimy setbase(0) to dla strumienia wyjściowego zostanie przypisany system dziesiętny a dla strumienia wejściowego nie zostanie przypisany żaden konkretny system. Konwersja będzie się odbywać na podstawie formatu wprowadzanej liczby. (Np. zapis 0x2345 sugeruje, że mamy do czynienia z liczbą heksadecymalną). 3. Manipulator setfill. - cdn 4. Manipulator setw. - cdn UWAGA !!! Aby użyć manipulatorów parametryzowanych musisz dodać bibliotekę iomanip.h . 32 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński 33 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński ozdział 9 Funkcje W poprzednich rozdziałach, w niektórych miejscach, pojawiły się zapisy funkcji. Celowo zwlekałem z wprowadzeniem tego pojęcia aż do tego rozdziału. Wynika to z chęci jednoczesnego wprowadzenia pojęcia funkcji oraz metody i wyjaśnienia różnicy między tymi pojęciami. Do tego celu potrzebne będzie omówienie podstaw obiektowości, która dotyczy nie tylko języka C++. Wracając do pojęcia samej funkcji. Można powiedzieć, że jest to wydzielona część kodu realizująca określone zadanie. Oczywiście ktoś może powiedzieć, że funkcja może nic nie robić, więc nie realizuje też żadnego zadania. To prawda, jednak taki funkcje są rzadkością i bywają wykorzystywane tylko w nielicznych przypadkach i to w sytuacjach bardzo nietypowych. W swoich programach powinieneś/aś unikać takich funkcji, chyba że stanowią one pewien etap przejściowy. Podstawowy format funkcji w języku C++ wygląda następująco: Parametr_zwracany nazwa_funkcji(argumenty funkcji) { ciało funkcji } Parametr zwracany jest to typ zwracanego przez funkcję wyniku. Być może samo sformułowanie zwracanie wyniku jest niezbyt eleganckie ale bardzo często jest wykorzystywane przez programistów. Oznacza ono przekazanie wyliczonego wyniku do miejsca w programie, gdzie ta funkcja została wywołana. Nazwa funkcji funkcję identyfikujemy przez jej nazwę uwaga nie może zaczynać się od cyfr oraz być słowem zastrzeżonym języka C, ważna jest wielkość liter. Argumenty lista oddzielonych przecinkiem argumentów funkcji, czyli tego co chcemy funkcji przekazać. Przykład: int multiple(int a, int b) { int amulb; amulb = a * b; result amulb; 34 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński } Powyższy fragment kodu to funkcja o nazwie multiple, która mnoży przez siebie dwie liczby podane na wejściu i zwraca obliczoną liczbę jako wynik swojego działania. Zwrócenie następuje przez zapis result co_zwrócić. Należy pamiętać, że zwrócić można tylko taką zmienną jaka została zadeklarowana w nagłówku funkcji. Warto też dodać, że powyższą funkcję można znacznie uprościć. int multiple(int a, int b) { result a * b; } Jak widać, nie trzeba specjalnie tworzyć zmiennej, którą chcemy zwrócić, kompilator zadba o to sam. Jak użyć takiej funkcji ? Najlepszą ilustracją będzie kolejny przykład. #include stdio.h int multiple(int a, int b) { result a * b; } void main(void) { int a; int b; a = 5; b = 7; int c; c = multiple(a,b); printf( Obliczona wartośc %i\n ,c); // ten sam efekt printf( Krocej to samo %i\n ,multiple(5,7)); } Wynik: Obliczona wartość 35 Krócej to samo 35 Komentarz: Definicja funkcji znajduje się na początku programu, zaraz po sekcji include. Następnie jest zapis 35 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński void main(void) czy zauważyłeś podobieństwo do funkcji? Tak, jest to funkcja, ale bardzo specyficzna. Praktycznie każdy program musi ją mieć. Jak widać, zamiast argumentów i zwracanego typu widnieje napis void . Najprościej mówiąc jest to nic . Inaczej zapis: main() { //... } będzie działał w większości kompilatorów równie dobrze (Czasami wymagane jest wstawienie void w zależności od używanego kompilatora). Funkcja main to miejsce w którym rozpoczyna się działanie programu. Zaraz po uruchomieniu następuje wywołanie tej funkcji (automatyczne sami nie możemy jej wywołąć!!!) i przetwarzanie kolejnych rozkazów. Pominięte zostają wszelkie wcześniejsze struktury, nawet jeżeli znajdują się przed funkcją main. Kolejno zostają zadeklarowane dwie zmienne typu int, przypisane im wartości, deklaracja kolejnej zmiennej dla przechowania wyniku a następnie wywołanie funkcji. Jako argumentów używamy wcześniej zdefiniowanych zmiennych(a,b) a wynik przypisujemy do zmiennej c. Zapis C = multiple(a,b); oznacza, że to co zostało wyliczone przez multiple (czyli to co zwraca ta metoda) zostaje przypisane do zmiennej c. Pamiętaj, że przetwarzanie rozpoczyna się od prawej strony, zatem najpierw zostaje wyliczona funkcja, potem jest przypisanie. Taki sam efekt działania programu można uzyskać bez deklarowania jakichkolwiek zmiennych. Jest to dobre tylko w przypadku, gdy zmienne te nie byłyby potrzebne w dalszej części programu. Uwaga: deklaracja funkcji powinna być przed miejscem jej wywołania ! Oznacza to, że gdybyśmy definicję multiple wstawili po funkcji main, kompilator wyrzuciłby bład. 36 Kurs języka C++ www.kurs-cpp.prv.pl Paweł Boiński Dodatek A Funkcja Symbol Nazwa C+ Nowy wiersz NL \n Tabulacja pozioma HT \t Tabulacja pionowa VT \v O jeden znak do tyłu BS \b Powrót karetki CR \r Nowa strona FF \f Lewy ukośnik \ \\ Pytajnik ? \? Liczba ósemkowa ooo \ooo Liczba szesnastkowa hhh \xhhh Apostrof \ Cydzysłów \ 37