Programowanie w C

Embed Size (px)

Citation preview

PrzedmowaC++ naley do grupy obiektowych jzykw programowania. Korzenie tych jzykw sigaj koca lat szedziesitych; rok 1967 uwaa si za dat powstania pierwszego jzyka obiektowego, Simula-67. Jzyk Simula-67 bazowa na wczeniejszej pracy nad specjalizowanym jzykiem Simula-1, przeznaczonym do symulacji zdarze dyskretnych, zachodzcych w reaktorach jdrowych. Twrcami Simuli byli dwaj badacze norwescy, Kristen Nygaard i Ole-Johan Dahl, pracujcy w Norweskim Centrum Obliczeniowym. W jzyku tym wprowadzono szereg poj i koncepcji, ktre z niewielkimi zmianami przejy wspczesne jzyki obiektowe. W szczeglnoci, obok typw wbudowanych (integer, real, Boolean), podobnych do stosowanych w najbardziej wwczas znanym jzyku proceduralnym ALGOL, wprowadzono w Simuli pojcie klasy. Wprowadzono rwnie mechanizm dziedziczenia, ktry przekazuje klasie potomnej cechy klasy rodzicielskiej. Kolejnym znaczcym krokiem w rozwoju jzykw obiektowych byo opracowanie przez Alana Kay z Xerox PARC jzyka Smalltalk. Jzyk ten powsta w latach 1970-1972 i posuy jako pierwowzr dla wspczesnej jego wersji, opracowanej przez Adele Goldberg w roku 1983; wersja ta znana jest obecnie pod nazw Smalltalk-80. Okresem szczeglnej aktywnoci w badaniach nad jzykami programowania byy lata siedemdziesite. Powstao wtedy prawdopodobnie kilka tysicy rnych jzykw i ich dialektw, ale przetrwao w szerszym obiegu zaledwie kilka. Tak wic na rynku utrzymay si jzyki: Smalltalk, Ada (sukcesor jzykw ALGOL 68 i Pascal, z pewnym wkadem od jzykw Simula, Alphard i CLU), C++ (pochodzcy z mariau jzykw C i Simula), Eiffel (oryginalne dzieo Bertranda Meyera, bazujcy po czci na Simuli) oraz obiektowe wersje jzykw Pascal (Object Pascal, Turbo Pascal) i Modula-2 (Modula-3). Powstao rwnie szereg jzykw obiektowych dla konstruowania systemw ekspertowych oraz tzw. sztucznej inteligencji. Wrd nich take nastpia ostra selekcja i powszechnie stosowanych jzykw pozostao niewiele; mona tu wymieni dwa szerzej znane: CLOS (akronim od Common Lisp Object System) oraz CLIPS (akronim od C Language Integrated Production System), ktry po rozszerzeniu o mechanizm dziedziczenia znany jest obecnie pod nazw COOL (akronim od. CLIPS Object-Oriented Language). Sprbujmy teraz okreli, jakie wsplne wasnoci maj wszystkie wymienione jzyki. Obecnie uwaa si, e jzyk programowania mona uzna za obiektowy, jeeli spenia nastpujce wymagania: Pozwala definiowa klasy i ich wystpienia, nazywane obiektami. Definicja klasy w jzyku obiektowym jest podobna do definicji abstrakcyjnego typu danych w jzykach proceduralnych (typu, ktry nie jest wbudowany, lecz moe by zdefiniowany przez programist). W jzykach Eiffel, Smalltalk i Simula klasa jest niepodzieln jednostk syntaktyczn, zawierajc definicje struktur danych i definicje operacji wykonywanych na tych strukturach. Natomiast w jzykach hybrydowych, jak np. Object Pascal, Turbo Pascal, CLOS i C++ klasa jest traktowana jako deklaracja typu umieszczana w jednym pliku, a definicje operacji (nazywane metodami, funkcjami skadowymi, lub funkcjami pierwotnymi) umieszcza si zwykle w innym pliku. Konkretna operacja moe by implementowana za pomoc jednej tylko metody lub wielu metod. W pierwszym przypadku nazywamy j monomorficzn, za w drugim polimorficzn albo wirtualn. Wystpienia obiektw danej klasy s tworzone wedug tego samego wzorca, zawartego w definicji klasy. W rezultacie wszystkie obiekty danej klasy maj takie same struktury danych (atrybuty) i operacje. Tym niemniej kady obiekt ma wasn tosamo, a wic, po utworzeniu, istnieje niezalenie od innych obiektw tej samej klasy. Zapewnia ukrywanie informacji (hermetyzacj, ang. encapsulation), co mona rozumie jako

zamknicie obiektu w swego rodzaju czarnej skrzynce lub kapsuce. W wikszoci jzykw obiektowych hermetyzacja nie zawsze jest pena, poniewa zawieraj one mechanizmy kontroli dostpu do elementw klasy. Jako zasad przyjmuje si ukrywanie przed uytkownikiem definicji struktur danych i definicji operacji, przy czym same operacje (lub tylko cz z nich) s publicznie dostpne. Zbir publicznie dostpnych operacji dla obiektu danej klasy nazywa si czsto publicznym interfejsem obiektu. Taka konstrukcja klas jest logiczna, poniewa dla uytkownika klasy istotne jest tylko to, jak si nazywa dana operacja, do czego suy i jak si j uaktywnia (wywouje). Hermetyzacj realizuje si zwykle w ten sposb, e uytkownik nie ma dostpu do kodu rdowego z definicjami klas i operacji, a jedynie do publicznych interfejsw. Dziki temu zapewnia si ochron klas (przede wszystkim predefiniowanych klas bibliotecznych) przed nieuprawnionym dostpem. Posiada wbudowany mechanizm dziedziczenia, dziki ktremu mona tworzy klasy potomne (podklasy, klasy pochodne) od jednej lub kilku klas rodzicielskich, nazywanych superklasami lub klasami bazowymi. Klasy potomne mog z kolei by klasami rodzicielskimi dla swoich klas pochodnych, co pozwala tworzy drzewa (hierarchie) klas. W praktyce klasa bazowa jest na og prost konstrukcj jzykow, za klasa pochodna jest jej specjalizacj, co zwykle prowadzi do rozszerzenia definicji klasy bazowej o nowe elementy. Elementami tymi mog by nowe struktury danych i nowe metody, bd te operacje o tych samych nazwach co w klasie bazowej, ale o innych definicjach. Mechanizm dziedziczenia jest niezwykle efektywny: nie wymaga kopiowania kodu rdowego klasy bazowej, poniewa klasa pochodna automatycznie dziedziczy wszystkie lub wybrane cechy klasy bazowej. W rezultacie mamy lepsz, bardziej przejrzyst organizacj programu. Dysponuje cechami polimorfizmu. Polimorfizm jest terminem zapoyczonym z biologii i oznacza dosownie wielopostaciowo. W odniesieniu do programw obiektowych polimorfizm mona okreli krtko: jeden interfejs (operacja), wiele metod. Najprostsz postaci (wbudowany polimorfizm ad hoc) polimorfizmu jest wykorzystanie tego samego symbolu dla semantycznie nie zwizanych operacji. Polimorfizm tego rodzaju jest charakterystyczny dla wikszoci wspczesnych jzykw programowania wysokiego poziomu, nie tylko obiektowych. Przykadem moe by uywanie tych samych symboli operacji arytmetycznych, np. symbolu mnoenia *, przy mnoeniu liczb cakowitych i rzeczywistych, chocia w kadym konkretnym przypadku bdzie wywoywana inna metoda mnoenia. Realizacja takiego wywoania wymaga wyznaczenia adresu danej metody; jeeli adresy odpowiednich metod s przekazywane w fazie kompilacji, to proces ten nazywany jest wizaniem wczesnym lub statycznym. W jzykach obiektowych mechanizm wizania wczesnego wykorzystuje si rwnie przy przecianiu operatorw, tj. nadawaniu innego znaczenia operatorom wbudowanym w jzyk oraz (co jest specyfik jzyka C++) przy przecianiu funkcji. Jednak o sile jzyka obiektowego decyduje moliwo wykorzystania wizania pnego (dynamicznego), gdy adres wywoywanej metody staje si znany dopiero w fazie wykonania programu. Wizanie pne wystpuje dla hierarchii klas zaprojektowanej w taki sposb, e zdefiniowane w pierwotnej klasie bazowej (korzeniu drzewa klas) metody s redefiniowane w klasach pochodnych z zachowaniem tej samej nazwy, typu, liczby i typw argumentw. Tego rodzaju metody nazywa si wirtualnymi. Zauwamy, e konstrukcja taka nie pozwala na zwizanie wywoania operacji z jej metod w fazie kompilacji, poniewa posta wywoania jest dokadnie taka sama dla kadej operacji w caej hierarchii klas. Dopiero w fazie wykonania, gdy zostanie utworzony obiekt odpowiedniej klasy, mona wywoa metod wirtualn dla tego obiektu.

Jzyk C++ zawiera wszystkie wymienione cechy, a ponadto takie, ktre czyni go bardzo efektywnym; dziki temu staje si de facto standardem przemysowym. De facto, poniewa dotychczasowe prace komitetw normalizacyjnych ANSI X3J16 oraz ISO WG-21 doprowadziy jedynie do opublikowania w roku 1994 zarysu standardu. Tekstem rdowym dla obu komitetw

bya wykadnia jzyka, opublikowana w ksice Margaret Ellis i twrcy C++, Bjarne Stroustrupa, The Annotated C++ Reference Manual [2]. Pierwotnym zamysem Stroustrupa byo wyposaenie bardzo efektywnego jzyka C w klasy, wzorowane na klasach Simuli. Zrealizowa go w roku 1980, konstruujc preprocesor rozszerzonego w ten sposb jzyka C. Nowy jzyk, nazwany C with classes, by wtedy traktowany raczej jako dialekt jzyka C, chocia zawiera ju wikszo cech jzyka C++ (dziedziczenie, kontrola dostpu, konstruktory i destruktory, klasy zaprzyjanione, silna typizacja). W latach 80-tych Stroustrup wraz z grup wsppracownikw wprowadza dalsze mechanizmy i konstrukcje jzykowe (funkcje rozwijalne, argumenty domylne, przecianie operatorw i funkcji, referencje, stae symboliczne, zarzdzanie pamici, dziedziczenie mnogie, funkcje wirtualne, szablony klas i funkcji, obsuga wyjtkw), co wraz ze cilejsz kontrol typw doprowadzio jzyk C++ do obecnego ksztatu. C++ jest jzykiem wysoce modularnym; kady program mona zdekomponowa na oddzielnie kompilowane moduy z publicznym interfejsem i ukryt implementacj. I odwrotnie: do kadego programu mona docza wczeniej opracowane moduy, przechowywane na dysku w postaci tzw. plikw nagwkowych. Kluczowym pojciem w C++ jest klasa, traktowana jako typ definiowany przez uytkownika. W definicji jzyka nie przewidziano standardowej biblioteki klas jako czci rodowiska programowego, chocia opracowanie [4], sygnowane przez AT&T, zawiera opis i sposb korzystania z bibliotek wejcia/wyjcia. W praktyce mona wic spotka wiele bibliotek klas, opracowanych niezalenie od standardu AT&T, jak np. bibliotek NIH (USA, National Institutes of Health), wzorowan na bibliotece jzyka Smalltalk; bibliotek Interviews, ktra pozwala na dogodne uywanie systemu X Window z poziomu C++; bibliotek GNU C++ (g++), opracowan w ramach projektu GNU; biblioteki dla tworzenia obiektw trwaych (POET, ObjectStore, ONTOS, Versant). biblioteki specjalizowane, jak np. RHALE++ (dla oblicze matematycznych w fizyce), SIMLIB (dla symulacji sieci przeczanych). Z biecych informacji wynika, e komitety ANSI/ISO przyjy ju standardy dla nastpujcych klas bibliotecznych: array (szablon tablic), dynarray (szablon tablic dynamicznych), string (szablon acuchw), wstring (szablon acuchw z rozszerzonym kodem znakw), bits (szablon zbioru bitowego o ustalonej licznoci), bitstring (szablon zbioru o zmiennej licznoci) i complex (liczby zespolone). W najbliszym czasie mona si spodziewa przyjcia standardw dla szablonw klas: vector, list i associative array (map). Ze wzgldu na brak niektrych standardw, biblioteki klas s uywane w niniejszej ksice raczej oszczdnie; prawie wycznie bd to biblioteki wejcia/wyjcia z bardzo nielicznymi odstpstwami. Dziki temu zamieszczone w tekcie przykady (a jest ich ponad 160) byy kompilowane i wykonywane zarwno w rodowisku Windows95 (kompilator Borland C++, wersja 5.01, kompilator Visual C++ v.4.0), jak i w rodowisku Unix (kompilatory CC, GNU gcc, GNU g++, v.2.8.1). Prezentowany tekst naley traktowa raczej jako wstp do programowania w jzyku C++, a nie jako wyczerpujcy podrcznik (zarwno w sensie kompletnoci wykadu, jak i znuenia potencjalnego czytelnika). W stwierdzeniu tym nie naley upatrywa samokrytyki; w ksice o rozsdnej objtoci mona dokadnie opisa skadni i semantyk jzyka C++, ale pragmatyka moe mie potencjalnie (i ma) tak wiele kontekstw, e nie jest praktycznie moliwe opisanie wszystkich moliwych wariantw i niuansw. Chocia jzyk C++ zosta nadbudowany nad jzykiem C, zrozumienie prezentowanego tekstu, przykadw i programw, nie wymaga umiejtnoci programowania w jzyku C. Tym niemniej zaoono, e czytelnik ma pewne dowiadczenia programistyczne w ktrym z jzykw wysokiego poziomu, jak np. Pascal, Modula-2, czy wreszcie wspomniany jzyk C. Bardzo polecam uwane przestudiowanie zamieszczonych przykadw; poniewa zdecydowana wikszo z nich to kompletne programy, warto je skompilowa i wykona w dostpnym rodowisku programowym.

Sdz, e towarzyszce przykadom dyskusje i analizy programw oka si interesujce nie tylko dla pocztkujcych, ale i dla zaawansowanych programistw, ktrych uwadze polecam rozdziay 10 i 11, powicone obsudze wyjtkw i dynamicznej kontroli typw. Zawarte w tych rozdziaach opisy i dyskusje oparto na ostatnich ustaleniach wspomnianych komitetw ANSI/ISO, a kompilacja i wykonanie programw wymagaj dostpu do najnowszych kompilatorw, np. Borland C++ w wersji 5.01 lub CC w wersji 4.0. Gdask, w sierpniu 1998 W. M. Porbski

1. Podstawowe elementy jzyka C++W jzyku C++ wykorzystuje si zbir znakw ASCII, zdefiniowany norm ANSI3.4-1968. Jest to amerykaski wariant midzynarodowego, 7-bitowego kodu ISO 646-1983. Elementami tego zbioru s: mae i due litery alfabetu aciskiego, cyfry od 0 do 9, znaki przestankowe i inne symbole specjalne. Kady znak zbioru ASCII ma swj numer porzdkowy (kod znaku); np. kodem znaku 'A' jest liczba 65 w dziesitnym systemie liczenia, lub 101 w systemie oktalnym (semkowym). Znaki kodu ASCII zestawiono w Dodatku A. Poniewa C++ jest jzykiem o silnej typizacji, zatem kada nazwa (identyfikator) w programie musi mie zwizany z ni typ, podawany w deklaracji identyfikatora. Typ okrela zbir wartoci, jakie mona przypisa danej nazwie oraz zbir operacji, jakie mona zastosowa do takiej nazwy (tj. do reprezentowanej przez t nazw struktury danych), a take sposb interpretacji poszczeglnych operacji. 1.1. Wbudowane typy danych

Kada implementacja jzyka C++ zawiera dwie kategorie typw danych: typy wbudowane i typy definiowane przez uytkownika. Zarwno pierwsze, jak i drugie s abstrakcyjnymi reprezentacjami rzeczywistych struktur danych. Pord typw wbudowanych wyrnia si typy podstawowe: typ char, typ int, typ float, typ double, typ bool i typ enum. Nazwy typw podstawowych mona poprzedza tzw. specyfikatorami typu, tj. sowami kluczowymi short, long, signed i unsigned, ktre zmieniaj wewntrzn reprezentacj danych tych typw. Kady typ wbudowany ma take szereg skojarzonych z nim typw pochodnych: wskaniki, referencje i tablice. Rysunek 1-1 ilustruje typy wbudowane.int char double enum Podstawowe typy danych unsigned int i; Deklaracja zmiennej i, ktra jest typu unsigned int bool float short unsigned Specyfikatory signed long

Rysunek 1-1 Podstawowe typy danych C++ Poniej zestawiono sensowne (i najczciej uywane) kombinacje typw i specyfikatorw. Dla wielkoci (staych i zmiennych) cakowitych: char, short int, int, long int. Norma ANSI/ISO stanowi, e zapisw short int oraz long int nie mona w programach skraca do short i long. Dla wielkoci (staych i zmiennych) zmiennoprzecinkowych: float, double, long double. Dla wielkoci cakowitych bez znaku, wartoci logicznych, tablic bitowych: unsigned char,

unsigned short int, unsigned int, unsigned long int. Przy jawnym deklarowaniu wielkoci ze znakiem: signed char, signed short int, signed int. F Uwaga1. Jeeli na wielkociach typw char oraz int maj by przeprowadzane operacje arytmetyczne lub logiczne, to s one najpierw niejawnie przeksztacane do typu int. W analogicznej sytuacji dane typu float s przeksztacane do typu double. W jzyku C++ istnieje ponadto typ void, ktry posiada pusty zbir wartoci. Z punktu widzenia skadni typ void zachowuje si analogicznie do typw podstawowych (int, char, float, double, enum). Jednake mona go uywa jedynie jako fragmentu typu pochodnego, poniewa nie ma obiektw typu void. Na pierwszy rzut oka moe si wydawa dziwnym posiadanie typu, dla ktrego nie ma zdefiniowanych wartoci. Jednak w praktyce typ ten jest bardzo uyteczny, szczeglnie w zastosowaniu do funkcji, ktre nie zwracaj adnej wartoci, a wic odpowiadaj znanym z innych jzykw programowania procedurom. F Uwaga 2. Typy char, int (z ewentualnymi specyfikatorami) oraz enum s cznie nazywane typami cakowitymi. Typy cakowite i zmiennopozycyjne s cznie nazywane typami arytmetycznymi. 1.2. Jednostki leksykalne

W jzyku C++ znajdujemy cztery rodzaje jednostek leksykalnych: identyfikatory, sowa kluczowe, literay oraz rne separatory. Spacje, znaki tabulacji poziomej i pionowej, znaki nowego wiersza i nowej strony oraz komentarze (nazywane cznie biaymi znakami) s w oglnoci ignorowane, chyba e su do separacji jednostek leksykalnych. W procesie kompilacji programu jednostki leksykalne s wyodrbniane (ang. parsing) z wejciowego strumienia znakw w ten sposb, e jako nastpn jednostk bierze si najduszy cig znakw po biaym znaku lub po sekwencji takich znakw. 1.2.1. Identyfikatory Nazwa (identyfikator) jest sekwencj liter i cyfr o dowolnej dugoci. Pierwszy znak musi by liter, przy czym znak podkrelenia '_' jest traktowany jako litera. Rozrniane s litery mae i due. Naley unika stosowania nazw, zaczynajcych si od znaku podkrelenia lub dwch kolejnych znakw podkrelenia, poniewa nazwy takie s zarezerwowane dla predefiniowanych identyfikatorw, m. in. dla bibliotek. 1.2.2. Komentarze Komentarze s, w pewnym sensie, wizytwk programisty, poniewa ich zadaniem jest zwikszenie czytelnoci programu. Krtkie komentarze maj posta dowolnego cigu znakw, zapisywanych w jednym wierszu po symbolu komentarza '//'. Taki komentarz koczy si wraz z kocem danego wiersza. Dusze komentarze zaleca si umieszcza pomidzy parami znakw '/*' i '*/'. Jeeli po symbolu '//' lub pomidzy symbolami '/*' i '*/' wystpi pary znakw '//', bd pary znakw '/*' i '*/', to bd one traktowane jak zwyke znaki (w C++ nie ma komentarzy zagniedonych). Podobnie jak w innych jzykach programowania, komentarze wpywaj tylko na wielko kodu rdowego, poniewa s usuwane z programu przez kompilator przed generacj kodu wynikowego. Poniewa komentarze nie s wczane do wynikowego kodu programu, mog by w nich uywane polskie znaki diakrytyczne, np. , , etc. Jest to pewne uatwienie dla polskiego programisty, ktry jest zmuszony korzysta wycznie ze 127 znakw ASCII we wszystkich pozostaych elementach programu. 1.2.3. Sowa kluczowe i operatory Zestawione niej sowa kluczowe s niepodzielnymi cigami znakw. S to zastrzeone identyfikatory, ktre mona uywa jedynie w cile zdefiniowanym kontekcie.

Asm Auto Bool Break Case Catch Char Class Const const_cast Continue Default Delete

do double dynamic_cast else enum explicit extern false float for friend goto if

inline int long mutable namespace new operator private protected public register reinterpret_cast return

Short Signed Sizeof static static_cast struct switch template this throw true try typedef

typeid typename union unsigned using virtual void volatile wchar_t while

Jeeli reprezentacja wewntrzna kodu rdowego jest zapisywana w kodzie ASCII, to ponisze symbole jednoznakowe s uywane jako znaki przestankowe lub operatory: ! [ % ^ ] \ & ; * ' ( : ) " < + > = ? { , } . | / ~

Operatorami s rwnie nastpujce symbole dwu- i trzyznakowe: -> ++ -|| *= .* /= ->* %= > -= = == &= != ^= && |= ::

Ponadto wiersze tekstu programu rdowego, ktre maj by przetwarzane przez preprocesor, znakuje si symbolem '#' w pierwszej kolumnie nowego wiersza. 1.2.4. Stae cakowite Stae cakowite s przykadami literaw staych; literaw, poniewa mwimy jedynie o ich wartociach; staych, poniewa ich wartoci nie mona zmienia. Kady litera jest pewnego typu; np. 2 jest typu int. Staa cakowita jest traktowana jako cakowita liczba dziesitna, jeeli skada si z cigu cyfr dziesitnych. Cig cyfr dziesitnych z zakresu 0-7 jest traktowany jako oktalna (semkowa) liczba cakowita, jeeli pierwszym znakiem cigu jest cyfra 0. Szesnastkowa (ang. hexadecimal) staa cakowita jest cigiem cyfr szesnastkowych (cyfry 0-9 i/lub litery a-f, bd A-F), poprzedzonych dwuznakowymi symbolami '0x' (zero-x)lub '0X'. Przykady: 89 //liczba dziesitna 037 //liczba semkowa 0x12 //liczba szesnastkowa 0X7F //liczba szesnastkowa Typ staej cakowitej przyjmowany domylnie przez kompilator zaley od jej postaci, wartoci i przyrostka. Jeeli jest to liczba dziesitna i nie ma przyrostka, to typ domylny zaley od jej wartoci i jest typem int, long int, lub unsigned long int. Jeeli jest to liczba oktalna lub szesnastkowa i nie ma przyrostka, to typ domylny zaley od jej wartoci i jest typem int, unsigned int, long int, unsigned

long int. Dodajc specyfikator u bd U (dla unsigned int), i/lub l bd L (dla long int) moemy wymusi inny sposb reprezentacji staej cakowitej, np. 25UL, 127u, 38000L. 1.2.5. Stae zmiennopozycyjne Stae zmiennopozycyjne nale do podzbioru liczb rzeczywistych. Mona je zapisywa w notacji dziesitnej z kropk dziesitn, np. 0.0 .28 lub w notacji wykadniczej, np. 1.18e12 -3.1415E-3 2. 3e8 -84.17

Jeeli po liczbie nie podano specyfikatora typu, to kompilator nadaje jej typ domylny double. Dokadno reprezentacji staej zmiennopozycyjnej mona wymusi, dodajc po zapisie liczby specyfikator f lub F (dla typu floatalbo l lub L (dla typu long double), np. -84.17f 1.2.6. Stae znakowe Staa (litera) znakowa jest to cig, zoony z jednego lub wikszej liczby znakw, ujty w pojedyncze apostrofy, np. 'x'. Stae jednoznakowe s typu char. Wartoci staej jednoznakowej jest warto numeryczna znaku w maszynowym zbiorze znakw (np. dla zbioru znakw ASCII, wartoci 'A' jest 65 dziesitnie lub 101 oktalnie). Typem staej wieloznakowej jest int. Pewne znaki, ktre nie maj reprezentacji graficznej na ekranie monitora, czy te na papierze drukarki, mog by reprezentowane w programie przez tzw. sekwencje ucieczki, zapisywane ze znakiem '\' (ang. escape sequences; sowo ucieczka mwi o tym, e nastpny po \ znak ucieka od przypisanego mu standardowego znaczenia), jak pokazano w tablicy 1.1. Wartoci znakw podane w tablicy 1.1 s zapisane w systemie oktalnym lub szesnastkowym. Tablica 1.1 Sekwencje ucieczki dla znakw kodu ASCII Nazwa sekwencji nowy wiersz (new-line) tabulacja pozioma (horizontal tab) tabulacja pionowa (vertical tab) (backspace) powrt karetki (carriage return) nowa strona (form feed) dzwonek (alert) \ (backslash) znak zapytania (question mark) pojedynczy apostrof (single quote) Podwjny apostrof (double quote) znak zerowy integer() liczba oktalna (octal number) Symbol NL (LF) HT VT BS CR FF BEL \ ? ' " NUL ooo Zapis znakowy \n \t \v \b \r \f \a \\ \? \' \" \0 \ooo Warto liczbowa 12 11 13 10 15 14 7 x5c x3f x27 x22 0 ooo .28F, 1.0L 3.14159e-3L

liczba szesnastkowa (hex number) 1.2.7. Stae acuchowe

hhh

\xhh

xhh

Staa (litera) acuchowy jest to cig o dugoci zero lub wicej znakw, ujty w podwjne apostrofy. Jeeli w cigu wystpuj znaki niedrukowalne (np. BEL), to s one reprezentowane przez ich sekwencje ucieczki. W reprezentacji wewntrznej do kadego acucha jest dodawany terminalny znak zerowy '\0' o wartoci 0; tak wic np. acuch "abcd" ma dugo 5 (a nie 4) znakw, poniewa po znaku 'd' kompilator doda znak zerowy '\0'. Jeeli acuch rozciga si na kilka wierszy, to na kocu kadego wiersza mona doda znak '\', ktry sygnalizuje kompilatorowi, e staa acuchowa jest kontynuowana w nastpnym wierszu.

2. Struktura i elementy programu 2.1.Deklaracje i definicje

Jak ju wspomniano, wszystkie wielkoci wystpujce w programie musz by przed ich uyciem zadeklarowane. Deklaracje ustalaj nieodzowne odwzorowanie pomidzy strukturami danych i operacjami, a reprezentujcymi je konstrukcjami programowymi. Kada deklaracja wie podany przez uytkownika identyfikator z odpowiednim typem danych. Wikszo deklaracji, znanych jako deklaracje definiujce lub definicje, powoduje take utworzenie definiowanej wielkoci, tj. przydzielenie (alokacj) jej fizycznej pamici i ewentualne zainicjowanie. Pozostae deklaracje, nazywane deklaracjami referencyjnymi lub deklaracjami, maj znaczenie informacyjne, poniewa jedynym ich zadaniem jest podanie deklarowanej nazwy i jej typu do wiadomoci kompilatorowi. Tak zadeklarowany identyfikator musi by w programie zdefiniowany albo pniej w tym samym, albo w oddzielnym pliku z kodem rdowym. Dla danego identyfikatora moe wystpi wiele deklaracji referencyjnych, ale tylko jedna deklaracja definiujca (przypadki takie wystpuj najczciej w programach wieloplikowych). Oczywist jest zasada, e aden identyfikator nie moe by uyty w programie przed jego punktem deklaracyjnym w kodzie rdowym. Deklaracja zakoczona rednikiem nazywa si instrukcj deklaracji. Najczciej deklarowanymi wielkociami s zmienne. Zmienn okrela si jako pewien obszar pamici o zadanej symbolicznej nazwie, w ktrym mona przechowywa wartoci, interpretowane zgodnie z zadeklarowanym typem zmiennej. Jzyk C++ uoglnia to pojcie: wymieniony obszar pamici moe nie posiada nazwy, moe mie nie jedn lecz kilka nazw, za adres pocztku obszaru pamici moe by dostpny dla programisty. Przykad 2.1 ilustruje rnorodno moliwych deklaracji i definicji. Przykad 2.1. char znak; char litera = 'A'; char* nazwa = "Cplusplus"; extern int ii; int j = 10; const double pi = 3.1415926; enum day { Mon, Tue, Wed, Thu, Fri, Sat, Sun }; struct mystruct; struct complex { float re, im;}; complex zespolone; typedef complex punkt; class myclass; template abs(T x) { return x < 0 ? -x : x; } Dyskusja. Jak wida z powyszego przykadu, w deklaracji mona umieci o wiele wicej informacji dla kompilatora, ni jedynie wskaza, e dana nazwa jest zwizana z okrelonym typem. Tylko 3 spord nich extern int ii; struct mystruct; class myclass;

s deklaracjami referencyjnymi, a zatem musz im towarzyszy odpowiednie definicje. Definicje struktury mystruct i klasy myclass musz si znale w tym samym pliku, w ktrym podano ich deklaracje, za definicja zmiennej ii musi by podana w jednym z plikw programu. Pozostae deklaracje s jednoczenie definicjami:

Wielkoci znak, litera oraz j s zmiennymi typw podstawowych. Stosownie do ich typw kompilator przydzieli im odpowiednie obszary pamici. Zauwamy take, e zmienne litera, nazwa oraz j zostay zainicjowane odpowiednimi dla ich typw wartociami. Wielko pi typu double jest sta symboliczn, o czym informuje sowo kluczowe (deklarator staej) const na pocztku deklaracji. Warto tej staej (3.1415926) jest znana kompilatorowi, zatem nie trzeba dla niej rezerwowa pamici. Wielkoci day i complex s definicjami nowych typw; identyfikator zespolone jest zmienn typu complex, za identyfikator punkt jest zastpcz nazw (synonimem) dla complex.

2.1.1.

Deklaracje staych

Jzyk C++ pozwala definiowa szczeglnego rodzaju zmienne, ktrych wartoci s ustalone i niezmienne w programie. Jeeli definicj zmiennej zainicjowanej, np. int cyfra = 7; poprzedzimy sowem kluczowym const const int cyfra = 7; to przeksztacimy w ten sposb symboliczn zmienn cyfra z pierwszej definicji w sta symboliczn o tej samej nazwie. Warto tak zdefiniowanej staej symbolicznej pozostaje niezmienna w programie, a kada prba zmiany tej wartoci bdzie sygnalizowana jako bd. Sowo kluczowe const, ktre zmienia interpretacj definiowanej wielkoci, jest nazywane modyfikatorem typu. Nazwa uzasadniona jest tym, e const ogranicza moliwoci uycia definiowanej wielkoci tylko do odczytu, ale zachowuje informacj o typie ( w przykadzie jak wyej typ staej cyfra zosta zdefiniowany jako int). Dziki temu stae symboliczne w jzyku C++ mona uywa zamiast literaw tego samego typu. Zauwamy te, e skoro nie mona zmienia wartoci staej symbolicznej po jej zdefiniowaniu, to musi ona by zainicjowana. Np. zapis const double pi; jest bdny, poniewa wielko pi nie zostaa zainicjowana. Podobnie jak wszystkie obiekty programu, staa symboliczna moe mie tylko jedn definicj. Po zdefiniowaniu jest ona (domylnie) widoczna tylko w pliku, w ktrym umieszczono jej definicj. W wikszych programach, skadajcych si z wielu plikw, moemy uczyni j widoczn dla innych plikw, umieszczajc w nich deklaracje, informujce kompilator o tym, e w jednym z plikw programu znajdzie jej definicj. Informacj t przekazujemy kompilatorowi za pomoc sowa kluczowego extern, umieszczonego przed deklaracj. Np. sta cyfra moemy udostpni innym plikom programu, umieszczajc w nich deklaracje o postaci: extern const int cyfra; F Uwaga. Starsze kompilatory jzyka C++ odgaduj typ staej symbolicznej na podstawie jej wartoci numerycznej i formatu definicji. Jednak standard wymaga jawnego podawania typu kadej staej.

2.1.2.

Wyliczenia

Alternatywnym, a czsto bardziej przydatnym sposobem definiowania symbolicznych staych cakowitych jest uycie do tego celu typu wyliczeniowego (ang. enumerated type). Wyliczenie deklaruje si ze sowem kluczowym enum, po ktrym nastpuje wykaz staych cakowitych (ang.

enumerators) oddzielonych przecinkami i zamknitych w nawiasy klamrowe. Wymienionym staym s przypisywane wartoci domylne: pierwszej z nich warto 0, a kadej nastpnej warto o 1 wiksza od poprzedzajcej. Np. wyliczenie: enum {mon, tue, wed, thu, fri, sat, sun}; de niuj siedems ay h kowit c i prz pis j im war o ci od0 do6. a zauway,e fi e t c ca yh y ue t two powysz zapis skr s y sekwen jdekla a ji t c y je t t zni ca r c s ay h: const int mon = 0; const int tue = 1; . . . const int sun = 6; Staym typu wyliczeniowego mona rwnie przypisywa wartoci jawnie, przy czym wartoci te mog si powtarza. Np. deklaracja: enum { false, fail = 0, pass, true = 1 }; przypisuje warto 0 do false i fail (do false domylnie) oraz warto 1 do pass i true (do pass domylnie). W wyliczeniach mona po enum umieci identyfikator, ktry stanie si od tego momentu nazw nowego typu. Np. enum days { mon, tue, wed, thu, fri, sat, sun }; definiuje nowy typ days. Pozwala to od tej chwili deklarowa zmienne typu days, np. days anyday = wed; W taki sam sposb mona wprowadzi zapis, ktry imituje typ bool (jeli nasz kompilator nie zawiera implementacji tego typu) enum bool {false, true}; bool found, success; //lub np. bool success = true; Deklaracje zmiennych typu wyliczeniowego mona rwnie umieszcza pomidzy zamykajcym nawiasem klamrowym a rednikiem, np. enum bool {false,true} found, success; F Uwaga. Typ wyliczeniowy jest podobny do typw char oraz shortint w tym, e nie mona na jego wartociach wykonywa adnych operacji arytmetycznych. Gdy warto typu wyliczeniowego pojawia si w wyraeniach arytmetycznych, to jest niejawnie przeksztacana do typu int przed wykonaniem operacji.

2.2. Dyrektywy preprocesoraKompilacja programu rdowego, napisanego w jzyku C++, przebiega zwykle w czterech lub piciu kolejnych krokach; produktem kocowym jest kod adowalny. W pierwszym kroku uruchamiany jest program, nazywany preprocesorem. Preprocesor przetwarza te wiersze tekstu programu, ktre zaczynaj si znakiem # w pierwszej kolumnie. W wierszach tych zapisujemy

polecenia, nazywane dyrektywami. W odrnieniu od instrukcji, ktre s wykonywane po zakoczeniu kompilacji i uruchomieniu programu, dyrektywy s poleceniami do natychmiastowego wykonania przed rozpoczciem waciwego procesu kompilacji. Poniewa dyrektywy przywouj predefiniowane wielkoci biblioteczne, z reguy umieszcza si je w pierwszych wierszach tekstu programu.

2.2.1.

Dyrektywa #include

Dyrektywa #include pozwala zebra razem wszystkie fragmenty programu rdowego w jeden modu, nazywany plikiem rdowym lub jednostk translacji. Jeeli dyrektywa ta wystpuje w postaci: #include to nazwa-pliku.h odnosi si do standardowego, predefiniowanego pliku nagwkowego (bibliotecznego), umieszczonego w standardowym katalogu plikw doczanych (ang. standard include directory). Polecenie o takiej postaci zleca preprocesorowi poszukiwanie pliku tylko w standardowych miejscach bez przeszukiwania katalogu zawierajcego plik rdowy. Jeeli dyrektywa #include wystpuje w postaci: #include "nazwa-pliku.h" to preprocesor zakada, e plik o nazwie nazwa-pliku.h zosta zaoony przez uytkownika. W takim przypadku poszukiwanie pliku zaczyna si od katalogu biecego; jeeli wynik poszukiwania jest niepomylny, to jest ono kontynuowane w katalogu standardowym. F Uwaga 1. W implementacjach Unix-owych standardowym katalogiem dla plikw nagwkowych jest czsto /usr/include/CC. Jeeli jest inaczej, to mona wymusi pocztkow ciek poszukiwania, dodajc opcj -I w wierszu rozkazowym, np. $ CC -I incl -I/usr/local/include myprog.cc. W implementacji C++ firmy Borland pod systemem MS-DOS katalogiem standardowym bdzie katalog c:\borlandc\include F Uwaga 2. Zarwno dla standardowych, jak i przygotowanych przez uytkownika plikw nagwkowych mona w programie poda jawnie pen ciek do pliku, np. #include czy te < c:\borlandc\include\iostream.h >

2.2.2.

Dyrektywa #define

Najprostsza posta dyrektywy #define ma skadni: #define nazwa co czytamy: zdefiniuj identyfikator nazwa. Dyrektyw #define uywa si najczciej w kontekcie z dyrektyw #include, dyrektywami #if #elif #else #endif oraz #ifdef #else #endif i #ifndef #endif. Konteksty te stosuje si gwnie w celu uniknicia wielokrotnego definiowania tego samego identyfikatora i/lub wielokrotnego wstawiania tego samego pliku bibliotecznego do pliku rdowego. Dyrektyw #define mona rwnie zapisa w postaci: #define nazwa sekwencja-znakw

co czytamy: zastpuj wszystkie wystpienia identyfikatora nazwa podan sekwencj znakw. Przykad 2.2. #if SYSTEM == SYSV #define HDR "sysv.h" #elif SYSTEM == BSD #define HDR "bsd.h" #elif SYSTEM == MSDOS #define HDR == "msdos.h" #else #define HDR "default.h" #endif #include HDR Dyskusja. Pokazana wyej sekwencja dyrektyw testuje nazw SYSTEM dla podjcia decyzji, ktr wersj pliku nagwkowego naley wczy do programu. Dyrektywa #if sprawdza warto wyraenia: jeeli warto ta jest rna od zera (prawda), to przetwarzana jest nastpujca po niej dyrektywa #define i dyrektywa #include; jeeli nie to sprawdzane s kolejne alternatywy (elif odpowiada else if), po czym przetwarzana jest dyrektywa #include. Przy wczaniu do programu standardowych identyfikatorw i standardowych plikw bibliotecznych, uytkownik moe czu si zwolniony od takiego sprawdzania, poniewa obowizek ten spoczywa na twrcach kompilatorw. Niej pokazano tego rodzaju testy, zastosowane w plikach nagwkowych iostream.h dla dwch kompilatorw. Przykad 2.3. //Borland C++, plik iostream.h #ifndef __IOSTREAM_H #define __IOSTREAM_H #if !defined(__DEFS_H) #include #endif // definicje z plikw _defs.h i iostream.h #endif //Borland C++, plik ver.h ... typedef int BOOL; #define TRUE 1 #define FALSE 0 Dyskusja. Dyrektywa #ifndef daje warto TRUE (1) dla warunku nie zdefiniowany. Zatem #ifndef identyfikator daje taki sam efekt, jak #if 0 jeeli identyfikator zosta ju zdefiniowany i taki sam efekt, jak #if 1 jeeli identyfikator nie jest jeszcze zdefiniowany. Zatem #ifndef __IOSTREAM_H sprawdza, czy nazwa __IOSTREAM_H zostaa ju zdefiniowana. Jeeli nie, to przetwarzana jest dyrektywa #define __IOSTREAM_H (definiujca __IOSTREAM_H) i nastpujca po niej dyrektywa #if, ktra sprawdza, czy jest zdefiniowana nazwa __DEFS_H i w zalenoci od wyniku testu

wcza lub nie plik _defs.h i pozosta zawarto pliku iostream.h. Jeeli nazwa __IOSTREAM_H jest ju zdefiniowana, to preprocesor pominie dyrektyw #define i nastpujce po niej dyrektywy, dziki czemu zawarto pliku iostream.h nie zostanie wstawiona po raz drugi. Przykad 2.4. //plik iostream.h dla kompilatora CC Sun Microsystems #ifndef IOSTREAMH #define IOSTREAMH //definicje z pliku iostream.h ... #ifndef NULL #define NULL 0 #endif ... #ifdef EOF #if EOF ! = -1 #define EOF (-1) #endif #else #define EOF (-1) #endif ... #endif Dyrektywa #define bywa niekiedy stosowana dla definiowania staych. Zapisuje si j wtedy w drugiej z podanych postaci, tj. #define nazwa sekwencja-znakw np. #define WIERSZ 80

Taka posta dyrektywy zleca preprocesorowi zastpowanie dalszych wystpie identyfikatora podanym cigiem znakw. Zapisan wyej dyrektyw mona zastpi definicj staej symbolicznej const int WIERSZ = 80;

i uywa nazwy WIERSZ w programie w taki sam sposb. Definiowanie staych za pomoc #define jest mniej korzystne ni za pomoc modyfikatora const z nastpujcych powodw: Zastpienie identyfikatora cigiem znakw nie wnosi adnej dodatkowej informacji, poniewa tak zdefiniowanej staej nie przypisuje si adnego typu. Staa symboliczna definiowana z const niesie informacj o jej typie i moe by uywana przez program uruchomieniowy (ang. symbolic debugger).

2.3. Struktura prostych programwProgram w jzyku C++, niezalenie od jego rozmiaru, jest zbudowany z jednej lub kilku funkcji, opisujcych dane operacje procesu obliczeniowego. W tym sensie funkcje s podobne do podprogramw, znanych w innych jzykach programowania, a umoliwiajcych strukturalizacj i modularyzacj programw. Kady program musi zawiera funkcj o zastrzeonej nazwie main. Jest to funkcja, od ktrej rozpoczyna si dziaanie programu. Funkcja main zawiera zwykle wywoania rnych funkcji, przy czym niektre z nich s definiowane w tym samym programie, za inne pochodz z bibliotek uprzednio napisanych funkcji. W rezultacie program jest zbiorem odrbnych definicji i deklaracji funkcji. Komunikacja pomidzy funkcjami odbywa si za porednictwem argumentw i wartoci zwracanych przez funkcje, bd (rzadziej) przez zmienne zewntrzne, ktrych zakres obejmuje jeden plik rdowy programu. Pokazany niej przykad wprowadzajcy ilustruje struktur prostego programu. Przykad 2.5. // Struktura programu w jezyku C++ #include void czytaj(); void sortuj(); void pisz(); int main() { czytaj() ; sortuj() ; pisz() ; return 0; } void czytaj() { cout s wic operatorami selekcji. Poniewa wskanik wsk zosta zainicjowany adresem zmiennej nowy, zatem *wsk jest synonimem dla zmiennej nowy. Wobec tego zamiast np. s->status moglimy napisa (*wsk).status. Uycie nawiasw dla *wsk byo konieczne, poniewa operatory . i -> s lewostronnie czne (wi od prawej do lewej). Struktury mog by zagniedane; ilustruje to nastpny przykad. Przykad 4.20. #include struct A { int i; char znak; }; struct B { int j; A aa; double d; }; int main() { B s1, *s2 = &s1; s1.j = 4; s1.aa.i = 5; s2->d = 1.254; (s2->aa).znak = 'A'; cout aa).znak aa).znak dla wskanika (znowu konieczne nawiasy okrge). Kada deklaracja struktury wprowadza nowy, unikatowy typ, np. struct s1 { int i ; }; struct s2 { int j ; }; s dwoma rnymi typami; zatem w deklaracjach s1 x, y ; s2 z ; zmienne x oraz y sa tego samego typu s1, ale x oraz z s rnych typw. Wobec tego przypisania

x = y; y = x; s poprawne, podczas gdy x = z; z = y; s bdne. Dopuszczalne s natomiast przypisania skadowych o tych samych typach, np. x.i = z.j; Pola bitowe Obszar pamici zajmowany przez struktur jest rwny sumie obszarw, alokowanych dla jej skadowych. Jeeli np. struktura ma trzy skadowe typu int, a implementacja przewiduje 2 bajty na zmienn tego typu, to reprezentacja struktury w pamici zajmie 6 bajtw. Dla duych struktur (np. takich, ktrych skadowe s duymi tablicami) obszary te mog by znacznej wielkoci. W takich przypadkach moliwe jest cilejsze upakowanie pl struktury poprzez zdefiniowanie tzw. pl bitowych, ktre zawieraj podan w deklaracji liczb bitw. W pamici komputera pole bitowe jest zbiorem ssiadujcych ze sob bitw w obrbie jednej jednostki pamici zdefiniowanej w implementacji, a nazywanej sowem. Rozmieszczenie w pamici struktury z polami bitowymi jest take zalene od implementacji. Jeeli dane pole bitowe zajmuje mniej ni jedno sowo, to nastpne pole moe by umieszczone albo w nastpnym sowie (wtedy nic nie oszczdzamy), albo czciowo w wolnej czci pierwszego sowa, a pozostae bity w nastpnym sowie. Przy tym, zalenie od implementacji, alokacja pola bitowego moe si zaczyna od najmniej znaczcego lub od najbardziej znaczcego bitu sowa. Deklaracja skadowej bdcej polem bitowym ma posta: typ nazwa_pola : wyraenie; gdzie: typ oznacza typ pola i musi by jednym z typw cakowitych, tj. char, short int, int, long int ze znakiem (signed) lub bez (unsigned) oraz enum; wystpujce po dwukropku wyraenie okrela liczb bitw zajmowan przez dane pole. Pola bitowe mog by rwnie deklarowane bez nazwy (tzn. tylko typ, po nim dwukropek, a nastpnie szeroko pola). Takie pole nie moe by inicjowane, ale jest uyteczne, poniewa przy zadeklarowanej szerokoci 0 (zero) wymusza dopenienie do caego sowa wczeniej zadeklarowanego pola bitowego. Dziki temu alokacja nastpnego pola bitowego moe si zacz od pocztku nastpnego sowa. Pola bitowe zachowuj si jak mae liczby cakowite i mog wystpowa w wyraeniach arytmetycznych, w ktrych przeprowadza si operacje na liczbach cakowitych. Przykadowo, deklaracj struct sygnalizatory { unsigned int sg1 : 1; unsigned int sg2 : 1; unsigned int sg3 : 1; } s;

moemy wykorzysta do wczania lub wyczania sygnalizatorw s.sg1 = 1; s.sg2 = 0; s.sg3 = 1; lub testowania ich stanu if (s.sg1 == 0 && s.sg3 == 0) s.sg2 = 1; Zwrmy uwag na skadni dostpu do pola bitowego: jest ona taka sama, jak dla zwykego pola. Przykad 4.21. #include struct flagi { unsigned int flaga1 : 1; unsigned int flaga2 : 1; unsigned char flaga3 : 6; }; int main() { flagi bit1; cout