Józef Zieliński
Podstawy programowania w języku C++
Kraków
red.indd 1
06.03.2013 08:18
© Copyright by Józef Zieliński,
Recenzent: dr inż. Robert Dąbrowski
Korekta: Joanna Kosturek
Opracowanie typogra iczne: Józef Zieliński
Projekt okładki: Andrzej Augustyński
ISBN
-
-
-
-
O icyna Wydawnicza „Impuls” Kraków, ul. Turniejowa / tel./fax: ( ) , , www.impulso icyna.com.pl, e-mail: impuls@impulso icyna.com.pl Wydanie I, Kraków
red.indd 2
06.03.2013 08:18
Spis treści Rozdział 1. Elementy języka C++ Rozdział 2. Proste obliczenia 2.1. Wprowadzenie . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2. Ćwiczenia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Rozdział 3. Instrukcja warunkowa if 3.1. Wprowadzenie . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2. Przykładowe programy . . . . . . . . . . . . . . . . . . . . . . . 3.3. Ćwiczenia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Rozdział 4. Instrukcje iteracyjne 4.1. Wprowadzenie . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2. Przykładowe programy . . . . . . . . . . . . . . . . . . . . . . . 4.3. Ćwiczenia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Rozdział 5. Instrukcja iteracyjna for 5.1. Wprowadzenie . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2. Przykładowe programy . . . . . . . . . . . . . . . . . . . . . . . 5.3. Ćwiczenia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Rozdział 6. Instrukcja wyboru switch 6.1. Wprowadzenie . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2. Przykładowe programy . . . . . . . . . . . . . . . . . . . . . . . 6.3. Ćwiczenia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Rozdział 7. Funkcje 7.1. Wprowadzenie . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2. Przykładowe programy . . . . . . . . . . . . . . . . . . . . . . . 7.3. Ćwiczenia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7 17 17 24 25 25 27 32 33 33 34 38 39 39 41 46 47 47 50 52 53 53 56 60
4
Spis treści
Rozdział 8. Tablice 8.1. Wprowadzenie . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2. Przykładowe programy . . . . . . . . . . . . . . . . . . . . . . . 8.3. Ćwiczenia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Rozdział 9. Funkcje i tablice 9.1. Wprowadzenie . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.2. Przykładowe programy . . . . . . . . . . . . . . . . . . . . . . . 9.3. Ćwiczenia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Rozdział 10. Wskaźniki 10.1. Wprowadzenie . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.2. Przykładowe programy . . . . . . . . . . . . . . . . . . . . . . . 10.3. Ćwiczenia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Rozdział 11. Referencja, tablice znakowe 11.1. Wprowadzenie . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2. Przykładowe programy . . . . . . . . . . . . . . . . . . . . . . . 11.3. Ćwiczenia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Rozdział 12. Operacje wejścia i wyjścia
61 61 62 64 65 65 66 68 69 69 76 78 79 79 87 94 95
12.1. Wprowadzenie . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 12.2. Przykładowe programy . . . . . . . . . . . . . . . . . . . . . . . 106 12.3. Ćwiczenia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 Rozdział 13. Struktury
113
13.1. Wprowadzenie . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 13.2. Przykładowe programy . . . . . . . . . . . . . . . . . . . . . . . 118 13.3. Ćwiczenia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 Rozdział 14. Unie
129
14.1. Wprowadzenie . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 14.2. Przykładowe programy . . . . . . . . . . . . . . . . . . . . . . . 131 Rozdział 15. Tablice dwuwymiarowe
135
15.1. Wprowadzenie . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 15.2. Przykładowe programy . . . . . . . . . . . . . . . . . . . . . . . 136 15.3. Ćwiczenia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Spis treści
5
Rozdział 16. Zadania algorytmiczne 16.1. 16.2. 16.3. 16.4. 16.5. 16.6. 16.7.
Algorytm zachłanny . . . Algorytm z powrotami . . Algorytm dynamiczny . . Kwiaciarnia . . . . . . . . Sortowanie przez zliczanie Sortowanie pozycyjne . . Unikalna liczba . . . . . .
139 . . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
139 141 145 150 154 156 159
Rozwiązania zadań
161
Bibliografia
191
Rozdział 1
Elementy języka C++ Translacja programu napisanego w języku wysokiego poziomu (do którego należy też język C++) polega na utworzeniu kodu wynikowego na podstawie kodu źródłowego. Translacja składa się z etapu kompilacji kodu źródłowego oraz etapu konsolidacji, czyli łączenia. Kompilacja polega na tłumaczeniu kodu źródłowego programu na wewnętrzny język – język maszynowy i utworzeniu tzw. kodu obiektowego: • analizy syntaktycznej (składniowej) polegającej na grupowaniu symboli leksykalnych w wyrażenia gramatyczne, • analizy semantycznej polegającej na kontroli poprawności programu źródłowego i zbieraniu informacji do fazy tworzenia kodu wynikowego. Konsolidacja polega na łączeniu kodu obiektowego z dodatkowym kodem startowym, kodem z bibliotek i utworzeniu pliku końcowego z kodem wykonywalnym. W języku C++ wyróżnia się cztery podstawowe rodzaje jednostek leksykalnych (leksemów)[5]: 1. Identyfikatory, czyli nazwy zmiennych (np. x, x1, alfa), nazwy typów (np. int, double), nazwy funkcji (np. main, NWD, silnia), nazwy klas (np. complex, iostream), nazwy obiektów (np. cin, cout). Identyfikatory w języku C++ składają się tylko z sekwencji liter alfabetu angielskiego, cyfr i znaku podkreślenia _ . Identyfikator nie może się rozpoczynać od cyfry. Identyfikatory rozpoczynające się znakiem podkreślenia są często rezerwowane dla bibliotek. Rozróżnia się małe i wielkie litery! 2. Słowa kluczowe – zastrzeżone identyfikatory, których można używać tylko w ściśle określonym znaczeniu, np. float, long, if itd.
8
Rozdział 1. Elementy języka C++ 3. Operatory: – jednoznakowe, np. +, -; – dwuznakowe, np. >>, ==, +=; – trójznakowe, np. >>=, <<=; operatory dodatkowo pełnią rolę znaków przestankowych. 4. Literały (stałe): • całkowite: – dziesiętne, np. 13; – ósemkowe, np. 015 (rozpoczynają się od 0, zawierają cyfry 0–7); – szesnastkowe, np. 0xF, 0Xf (rozpoczynają się od 0x lub 0X i zawierają cyfry oraz litery z przedziałów a–f, A–F); • zmiennopozycyjne: – w notacji dziesiętnej z kropką, np. 6.0, 2., .5, -17.05; – w notacji wykładniczej, np. 2.7e10, -75E-20, 10e10; • znakowe – składają się z jednego lub kilku znaków ujętych w apostrofy, np. ’x’, ’A’, ’\n’; stałe znakowe mogą zawierać sekwencje specjalne rozpoczynające się od lewego ukośnika \, oznaczające niektóre znaki niegraficzne lub znaki specjalne np. ", \, ?, ’; dowolne, pojedyncze znaki mogą też być podane za pomocą liczby kodowej tego znaku, przedstawionej w systemie ósemkowym lub szesnastkowym; w tablicy 1.1 na stronie 9 umieszczono sekwencje specjalne, nazywane również sekwencjami ucieczki; • łańcuchowe – będące ciągiem znaków ujętym w cudzysłów, np. "abcd", "Pole = ", "koniec\n", "c:\\folder\\plik"; • separatory – np. spacje, tabulacje, znaki nowego wiersza, oraz komentarze, gdzie znaki // oznaczają komentarz do końca wiersza, znaki /* oznaczają początek komentarza, natomiast znaki */ oznaczają koniec komentarza.
Wszystkie zmienne występujące w programie muszą być przed wystąpieniem (zastosowaniem) zdefiniowane, co powoduje przydzielenie im miejsca w pamięci. Każda zmienna musi mieć określony typ, który określa zbiór wartości tej zmiennej, sposób kodowania wartości tej zmiennej, ilość bajtów zajmowanej pamięci oraz zbiór możliwych do wykonania operacji na tej zmiennej. W języku C++ wyróżnia się typy zmiennych podstawowe (wbudowane) oraz pochodne (definiowane przez programistę). W obliczeniach stosowane są typy arytmetyczne, w których wyróżnia się typy całkowite i zmiennopozycyjne. W grupie typów całkowitych, ze wzgledu na rozmiar, wyróżnia się cztery typy – deklarowane jako short int, int, long int, long long int. Kody
Rozdział 1. Elementy języka C++
9
Tablica 1.1. Sekwencje ucieczki
Nazwa sekwencji nowy wiersz tabulacja pozioma tabulacja pionowa cofnięcie o jeden znak powrót karetki nowa strona dzwonek lewy ukośnik znak zapytania apostrof cudzysłów zero całkowite liczba ósemkowa liczba szesnastkowa
Nazwa angielska new line horizontal tab vertical tab backspace carriage return form feed alert backslash question mark single quote double quote integer 0 octal number hex number
Symbol NL(LF) HT VT BS CR FF BEL \ ? ’ " NUL ooo hhh
Sekwencja \n \t \v \b \r \f \a \\ \? \’ \" \0 \ooo \xhhh
Źródło: W. Porębski, Programowanie w języku C++, Warszawa: Komputerowa Oficyna Wydawnicza „Help”, 1995.
liczb typów dłuższych zajmują nie mniej pamięci niż krótszych. Najczęściej zmienne typu short int zajmują dwa bajty, typ int dwa lub cztery bajty, zależnie od kompilatora, typ long int cztery bajty, a typ long long int osiem bajtów. Liczby całkowite bez znaku (dodatnie) są kodowane w naturalnym kodzie dwójkowym. Nazwa typu całkowitego bez znaku poprzedzana jest specyfikatorem unsigned. Stąd nazwy typów: • unsigned short int lub krócej: unsigned short; • unsigned int lub krócej: unsigned; • unsigned long int lub krócej: unsigned long; • unsigned long long int lub krócej: unsigned long long. Liczby całkowite bez znaku kodowane są w zakresie od 0 do 2b − 1, gdzie b jest liczbą bitów przeznaczonych do reprezentacji liczby. Przy dwubajtowej reprezentacji maksymalna liczba całkowita to 216 −1, czyli 65 535, przy reprezentacji czterobajtowej to 232 − 1, czyli 4 294 967 295, przy ośmiobajtowej reprezentacji maksymalna liczba całkowita to 264 − 1.
10
Rozdział 1. Elementy języka C++
Przykładowo liczba 40000, przy zastosowaniu 2-bajtowego (16-bitowego) typu unsigned short int jest kodowana jako 10011100 01000000, natomiast przy zastosowaniu typu 4-bajtowego (32-bitowego) unsigned long int jest kodowana jako 00000000 00000000 10011100 01000000. Gdy występują liczby całkowite ujemne, stosowane są typy całkowite ze znakiem. Liczby ujemne w typie całkowitym ze znakiem są kodowane w kodzie dwójkowym uzupełnieniowym do dwóch. Najstarszy bit ma wartość 0, gdy liczba jest dodatnia, 1 – gdy liczba jest ujemna. Nazwa typu całkowitego ze znakiem może być poprzedzona specyfikatorem signed. Zazwyczaj specyfikator ten jest pomijany, gdyż typ całkowity ze znakiem jest domyślnym typem całkowitym. Stąd nazwy tych typów: • signed short int lub krócej short, • signed int lub krócej int, • signed long int lub krócej long, • signed long long int lub krócej long long. Liczby całkowite ze znakiem są kodowane w zakresie od −2b−1 do 2b−1 − 1, gdzie b jest liczbą bitów przeznaczoną do reprezentacji liczby. Przy reprezentacji dwubajtowej jest to zakres od −215 (-32768) do 215 − 1 (32767), przy reprezentacji czterobajtowej od −231 (-2147483648) do 231 −1 (2147483647). Natomiast przy reprezentacji ośmiobajtowej od −263 (-9223372036854775808) do 263 − 1 (9223372036854775807). Przykładowo liczba -1 jest kodowana przy zastosowaniu typu 2-bajtowego (16-bitowego), signed short int jako 11111111 11111111, natomiast przy zastosowaniu typu 4-bajtowego (32-bitowego), signed long int, jest kodowana jako 11111111 11111111 111111111 11111111. Typy zmiennopozycyjne służą do reprezentacji liczb rzeczywistych wymiernych. Ich kod składa się z trzech części: bitu znaku, cechy i mantysy, kodowanych dwójkowo. Oto identyfikatory typów zmiennopozycyjnych: • float, 4-bajtowy, • double, 8-bajtowy, • long double, 10-bajtowy. Najczęściej używany typ zmiennopozycyjny to 8-bajtowy, 64-bitowy typ double, znaczenie poszczególnych bitów zmiennej tego typu przedstawiono poniżej.
Rozdział 1. Elementy języka C++
11
8 bajt´ ow
z
1 bit
11 bit´ ow
}|
{
52 bity
}| { z }| { z}|{ z s c10 c9 · · · c1 c0 m51 m50 · · · m1 m0 |{z} | {z } | {z }
znak
cecha
mantysa
Wartość liczby w jest określona następująco: (−1)s 2(c−1023) (1.m), s −1022 (0.m), (−1) 2
gdy gdy w = (−1)s 0, gdy s (−1) INF (przekroczenie zakresu), gdy (−1)s NAN (postać nienumeryczna), gdy
0 < c < 2047, c = 0 i m 6= 0, c = 0 i m = 0, c = 2047 i m = 0, c = 2047 i m 6= 0
Obliczenia zmiennopozycyjne wykonywane są za pomocą koprocesora arytmetycznego, IN F oznacza stan koprocesora „nieskończoność”, a N AN postać zmiennej „niearytmetyczna”. Przykładowo liczba 0 jest zakodowana w następujący sposób (typ double): 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000, gdzie bit znaku s = 0, c = 0, m = 0, zatem w = 0. Kod binarny liczby całkowitej 1, ale typu double ma postać: 00111111 11110000 00000000 00000000 00000000 00000000 00000000 00000000. W tym przykładzie znak ma kod 0 (liczba dodatnia), 0111111 1111 to kod cechy, czyli c = 1023, natomiast wartość mantysy to 0, stąd w = (−1)0 ∗ 21023−1023 ∗ (1, 0) = 1 Kod liczby 0.25 (typ double) jest następujący: 00111111 11010000 00000000 00000000 00000000 00000000 00000000 00000000, gdzie kod znaku 0, więc liczba dodatnia, cecha ma kod 0111111 1101, czyli c = 1021, wartość mantysy 0, stąd w = (−1)0 ∗ 21021−1023 ∗ (1, 0) = 2−2 =
1 = 0, 25 4
Kod liczby −4, 625 (typ double) 11000000 00010010 10000000 00000000 00000000 00000000 00000000 00000000 zawiera pierwszy bit znaku (1), oznaczający liczbę ujemną, cechę o kodzie 1000000 0001, więc c = 10025, natomiast kod mantysy to 0010 10000000 00000000 00000000 00000000 00000000 00000000, 5 co po odkodowaniu daje m = 32 = 0, 15625, stąd w = (−1)1 ∗ 21025−1023 ∗ (1, 15625) = −22 ∗ 1, 15625 = −4, 625
12
Rozdział 1. Elementy języka C++
Kod liczby 0,2 (typ double), składający się z 64 bitów, ma postać: 00111111 11001001 10011001 10011001 10011001 10011001 10011001 10011010, pierwszy bit (0) będący bitem znaku oznacza liczbę dodatnią, cechę koduje następne 11 bitów, 0111111 1100, więc c = 10025, natomiast 52 bity mantysy to 1001 10011001 10011001 10011001 10011001 10011001 10011010. 2 Po zamianie ułamka z systemu dziesiętnego 10 = 15 na ułamek w systemie dwójkowym powstaje ułamek okresowy o okresie (1001)2 . Mantysa zawiera ograniczoną liczbę bitów, stąd jej wartość jest zaokrąglona, z dokładnością do 52 bitów. Ostatnia uwzględniona czwórka bitów ułamka okresowego została zaokrąglona w górę do (1010)2 . Stąd ułamek 0,2 jest zakodowany w sposób przybliżony z zaokrągleniem w górę. Przy obliczeniach zachodzą zaokrąglenia w górę lub w dół, które wzajemnie się kompensują i często są mało zauważalne. W niektórych przypadkach jednak błędy tych zaokrągleń kumulują się. Przykładowo wynik działania (0.6 − 3 ∗ 0.2), wynoszący 0, wykonany z zastosowaniem typu double daje następujący wynik niezerowy (wynik w postaci zakodowanej): 10111100 10100000 00000000 00000000 00000000 00000000 00000000 00000000. W tym przykładzie s = 1, c = 970, m = 0, stąd w = (−1)1 ∗ 2970−1023 ∗ 1, 0, w = −2−53 , w = −1, 11022−16 . Wskutek zaokrąglenia w górę kodu liczby 0.2 otrzymujemy wartość obliczanego wyrażenia ujemną, bardzo małą, ale jednak różną od 0. Zmienne typu float zajmują 4 bajty pamięci, gdzie kolejno są: 1 bit znaku, 8 bitów cechy, oraz 23 bity mantysy. 4 bajty
z
1 bit
8 bit´ ow
}|
23 bity
{
}| { z }| { z}|{ z s c7 c6 · · · c1 c0 m22 m21 · · · m1 m0 |{z} | {z } | {z }
znak
cecha
mantysa
Wartość liczby w jest tu określona następująco: (−1)s 2(c−127) (1.m), s −126 (0.m), (−1) 2
gdy gdy w = (−1)s 0, gdy s (−1) INF (przekroczenie zakresu), gdy (−1)s NAN (postać nienumeryczna), gdy
0 < c < 255, c = 0 i m 6= 0, c = 0 i m = 0, c = 255 i m = 0, c = 255 i m 6= 0
Przykładowo kod zmiennej typu float o wartości 7 jest następujący: 01000000 111000000 00000000 00000000. Zatem s = 0, liczba dodatnia, kod cechy to 10000001, c = 129, kod mantysy to 1100000 00000000 00000000, czyli m = 2−1 + 2−2 = 0, 75. Stąd w = (−1)0 ∗ 2129−127 ∗ 1, 75, w = 22 ∗ 1, 75, w = 7.