Spis treści I. PSEUDO-KOD... 3 1.WIADOMOŚCI WSTĘPNE.... 3 2. PSEUDO-KOD... 5 2.1. Zdanie proste, które określa czynność do wykonania... 5 2.2. Zdanie decyzyjne jeŝeli.... 6 2.3. Zdanie iteracyjne podczas gdy... 6 2.4. Zdanie iteracyjne powtarzaj... 7 2.5. Zdanie iteracyjne dla... 7 2.6. Zdanie wybierz... 7 2.7. Zdanie grupujące... 8 3. POJĘCIE ZMIENNEJ.... 8 4.PRZYKŁADOWE ALGORYTMY W PSEUDO-KODZIE... 9 4.1. Pierwszy algorytm... 9 4.2. Drugi algorytm... 9 4.3. Algorytm trzeci... 10 5. REGUŁY ZAPISU WYRAśEŃ MATEMATYCZNYCH.... 11 II. PROGRAMOWANIE W JĘZYKU C... 11 1. CECHY JĘZYKA... 12 2. WPROWADZENIE DO PROGRAMOWANIA W JĘZYKU C... 13 3. PODSTAWOWE ELEMENTY JĘZYKA C... 13 3.1. Zestaw znaków języka C... 13 3.2. Nazwy i słowa zastrzeŝone języka C... 14 3.3. Podstawowe typy danych... 14 3.4. Stałe... 14 3.5. Zmienne i ich deklaracje... 15 3.6. WyraŜenia i operatory... 15 3.7. Instrukcje... 16 4. KOMENTARZE... 16 5. OPERATORY... 17 5.1. Operatory porównania... 17 5.2. Operatory inkrementacji (zwiększania) i dekrementacji (zmniejszania) o jeden... 17 5.3. Operatory logiczne.... 17 6. INSTRUKCJE PODSTAWIENIA... 18 7. INSTRUKCJE GRUPUJĄCE NAWIASY KLAMROWE... 18 8. INSTRUKCJE WYBORU... 19 8.1. Instrukcja if else... 19 8.2. Instrukcja wielokrotnego wyboru switch.... 19 9. INSTRUKCJE ITERACYJNE (PĘTLE)... 20 9.1. Pętla while... 20 9.2. Pętla for... 20 9.3. Pętla do while... 21 10. INNE INSTRUCJE STERUJĄCE PRZEBIEGIEM PROGRAMU... 22 10.1. Instrukcja break... 22 10.2. Instrukcja continue.... 22 10.3. Instrukcja return... 22 10.4. Instrukcja skoku do etykiety... 22 11. OGÓLNA STRUKTURA PROGRAMU NAJPROSTSZY PROGRAM W JĘZYKU C.... 23 12. PREPROCESOR.... 24 12.1. Dyrektywa włączająca pliki biblioteczne... 24 12.2. Dyrektywy makrodefinicji... 24 12.3. Dyrektywy warunkowej kompilacji... 25 13. FUNKCJE.... 25 14. PODSTAWOWE TYPY DANYCH - CD.... 27 14.1. Typy całkowite.... 27 14.2. Typy rzeczywiste.... 28 14.3. Typ void.... 28 14.4. Typ wyliczeniowy... 28 14.6. Typ logiczny... 28 14.5. Typ tablicowy... 29 Strona 1
15. ZASIĘG ZMIENNYCH.... 30 16. FORMATOWE WEJŚCIE I WYJŚCIE... 32 16.1. Formatowe wyjście.... 32 16.2. Formatowe wejście.... 34 17. WEJŚCIE I WYJŚCIE ZNAKOWE.... 35 17.1. Operacje wejścia.... 35 17.2. Operacje wyjścia.... 35 18. TRYB TEKSTOWY... 37 19. PLIKI W JĘZYKU C.... 40 19.1. Operacje otwarcia i zamknięcia pliku... 40 19.2. Czytanie z pliku... 41 19.3. Zapis do pliku... 42 20. WSKAŹNIKI... 43 20.1 Wskaźniki i tablice... 44 20.2. Wskaźniki i funkcje... 44 20.3. Wskaźniki znakowe i funkcje... 45 Strona 2
I. PSEUDO-KOD 1.WIADOMOŚCI WSTĘPNE. Program komputerowy jest to ciąg operacji przeznaczonych do wykonania przez komputer. Komputer wykonuje operacje jedna po drugiej, chyba, Ŝe wystąpi operacja powodująca zmianę kolejności wykonywania operacji (operacja skoku). Na początku istnienia komputerów wszystkie programy pisano w języku maszynowym, zrozumiałym dla komputera. Zapis taki był dokonywany w postaci dwójkowej (binarnej), co było oczywiście bardzo niewygodne i stało się przyczyną wielu błędów. Dlatego teŝ zostały wprowadzone języki, w których operacje i dane przedstawiano poprzez symbole. W takim języku jedna operacja w programie odpowiadała wykonaniu jednej instrukcji komputera. W chwili obecnej na podobnej zasadzie programuje się w języku Assemblera. Na bazie tych języków rozwinęły się języki wyŝszego poziomu, w których jedna instrukcja programu odpowiada zwykle wykonaniu wielu operacji maszynowych. Języki dzielimy na języki naturalne (językiem takim posługują się ludzi) oraz języki sztuczne. Języki programowania naleŝą do języków sztucznych. Podstawowe róŝnice pomiędzy językami programowania i naturalnymi: - wielkość słownika: w języku naturalnym ponad 200 tysięcy słów, w językach programowania poniŝej tysiąca; - zasady gramatyczne: w języku programowania są duŝo prostsze i jednoznacznie określone. Algorytm dokładny przepis wykonywania szeregu operacji (instrukcji) w celu rozwiązania określonego zagadnienia. Ostatecznym wykonawcą instrukcji zawartej w algorytmie jest oczywiście procesor. Instrukcje te powinny być dla procesora zrozumiałe, chociaŝ sam algorytm nie jest dla niego zrozumiały. W kaŝdym algorytmie powinno się znaleźć: - opis startu, w tym m.in. konieczne dane wejściowe i wyliczenia warunków rozpoczęcia pracy; - opis wykonania, tzn. co robić i jak; - opis zatrzymania pracy, czyli jakie warunki muszą być spełnione, aby proces wykonywania poleceń został zakończony. Program zapisany w postaci ciągu instrukcji języka programowania nazywa się programem źródłowym. Kompilacja (tłumaczenie) programu polega na zastąpieniu elementarnych operacji danego języka programowania elementarnymi operacjami komputera. Jej celem jest sprawdzenie poprawności składniowej i wygenerowanie kodu wynikowego. Do tłumaczenia uŝywane są specjalne programy, nazywane kompilatorami. Kompilator moŝe sam wykryć niektóre błędy popełnione przez programistę. Błędy te moŝna porównać do błędów ortograficznych i składniowych języka naturalnego. Nazywa się je błędami kompilacji. Strona 3
Innym rodzajem błędów są błędy wykonania. Uaktywniają się one podczas wykonywania programu, wtedy, gdy komputer nie moŝe wykonać Ŝądanej operacji, np.: próba dzielenia przez zero. Osobną kategorię błędów są błędy logiczne. Muszą być one wykryte przez programistę, gdyŝ kompilator nie jest w stanie ich rozpoznać. Są to błędy, które sprawiają, Ŝe program działa nieprawidłowo, np.: podaje nieprawidłowe wyniki, mimo iŝ nie był zasygnalizowany Ŝaden błąd. Błędy te wynikają najczęściej z błędów popełnionych w fazie projektowania algorytmu i mogą być bardzo trudne do wykrycia oraz usunięcia. Programowanie strukturalne jest to rodzaj programowania, w którym program podzielony jest na niewielkie moduły - procedury, bądź funkcje. Programowanie strukturalne ułatwia projektowanie, testowanie, a takŝe utrzymanie kodu programu. Do najpopularniejszych języków strukturalnych zalicza się Pascal, C, Modula-2. Język proceduralny (angielskie procedural language), język spełniający paradygmat programowania proceduralnego, np. Fortran, Pascal lub C, lecz takŝe kaŝdy nowszy język w swej warstwie proceduralnej. Technika ta charakteryzuje się tym, Ŝe moŝna wyodrębnić części realizujące pewne czynności. Tymi częściami są procedury i funkcje. W ramach takiej jednej funkcji moŝna definiować dodatkowe zmienne, tzw. lokalne czyli dostępne tylko dla tej funkcji. Zatem polega na zamianie danego problemu na serię zadań do wykonania. Te kolejne zadania realizują funkcje. Wykonywanie takiego programu to określona sekwencja wywołań róŝnych funkcji. System przetwarzania danych składa się z oprogramowania (software) i sprzętu (hardware). We wszystkich systemach występują zawsze trzy elementy: dane źródłowe stanowiące dane wejściowe systemu, przetwarzanie danych realizowane przez system, wyniki, czyli dane wyjściowe uzyskane z systemu. Dane wyjściowe przetwarzanie dane wyjściowe GENERACJE JĘZYKÓW PROGRAMOWNIA Języki programowania moŝna podzielić na pięć wyraźnie róŝniących się generacji: GENERACJA I programy były opracowywane bezpośrednio w kodzie binarnym (jako ciąg 0,1). KaŜdy typ komputera (procesora) operuje własnym kodem, który nazywamy językiem wewnętrznym lub maszynowym. Jest to wadą tych języków, gdyŝ programista kaŝdorazowo musi dostosowywać się do języka konkretnej maszyny. GENERACJA II poniewaŝ, operowanie ciągami 0, 1 jest niewygodne dla programisty przypisano im symbole mnemotechniczne (MOV, ADD, POP) w ten sposób powstały języki symboliczne niskiego poziomu zwane asemblerami. Stanowią one proste tłumaczenie języka maszynowego na symbole i są one ściśle związane z danym modelem komputera (procesora), ułatwiają pisanie instrukcji i czynią program bardziej czytelny. Strona 4
GENERACJA III kolejnym krokiem było powstanie języków wysokiego poziomu. Symbole asemblera oznaczające konkretne instrukcje zostały zastąpione kodem nie związanym z maszyną, bardziej zbliŝonych do języka naturalnego lub matematycznego. Język C i Pascal naleŝy do tej generacji języków. GENERACJA IV wyróŝnić tutaj moŝna szereg narzędzi, które umoŝliwiają budowę prostych aplikacji przez zestawianie modułów. Przyjęło się, Ŝe nazwę czwarta generacja naleŝy stosować wyłącznie w odniesieniu do programu obiektowego. Przykładem moŝe tu być język C++ GENERACJA V nazwę tę stosuje się czasem w odniesieniu do języków uŝywanych do tworzenia programu wykorzystujących tak zwaną sztuczną inteligencję lub inaczej systemów ekspertowych. 2. PSEUDO-KOD. Algorytm moŝna zapisać na wiele sposobów. MoŜna go przedstawić przy pomocy schematów blokowych, języka naturalnego, jak równieŝ bezpośrednio przy pomocy języka programowania. Obecnie często wykorzystuje się w tym celu technikę pośrednią pomiędzy językiem naturalnym a językiem programowania, tj. pseudo-kod. Pseudo-kod jest to niby-kod programu, czyli kod programu zapisany przy pomocy ustalonych zdań w języku naturalnym. Nie jest on zrozumiały dla Ŝadnego kompilatora i nie moŝe być przetłumaczony przez niego na język maszynowy ani na program wykonywalny. Ułatwia jednak zrozumienie zasad programowania i w późniejszym etapie takŝe pomaga w napisaniu programów w dowolnym języku programowa. Jest to moŝliwe dlatego, Ŝe poszczególne zdania pseudo-kodu są odpowiednikami podstawowych instrukcji, operatorów lub funkcji w językach programowania wysokiego poziomu. Pseudo-kod jest częściowo sformalizowany, czyli obok pewnych ustalonych struktur dopuszcza równieŝ uŝycie języka naturalnego do opisu róŝnych czynności. Zawiera ona pewne elementy składniowe, które są nazywane zdaniami. 2.1. ZDANIE PROSTE, KTÓRE OKREŚLA CZYNNOŚĆ DO WYKONANIA. Zdania te zapisywane są w języku naturalnym (czyli po prostu w języku polskim) i określają elementarny lub bardziej złoŝony krok algorytmu. Jeśli jest to krok elementarny, to wystarczy przy tworzeniu programu zapisać ten krok w języku programowania, natomiast jeśli jest to złoŝony krok algorytmu, to podczas uszczegółowiania projektu zostanie on zastąpiony sekwencją prostszych zdań pseudo-kodu. Przykład przypisz średniej wartość zero Jest to elementarny krok algorytmu mający odpowiednik w języku programowania. Przykład oblicz wartość średniej Jest to złoŝony krok algorytmu wymagający uszczegółowienia, kilku kroków elementarnych. Strona 5
2.2. ZDANIE DECYZYJNE JEśELI. Zdanie to zawiera strukturę opisującą decyzje podejmowane w algorytmie. Do zapisu tej struktury uŝywa się słów : jeŝeli, to i w przeciwnym przypadku, których znaczenie jest takie samo jak w języku polskim. Decyzje będziemy zapisywać przy pomocy dwóch struktur: a) struktury prostej jeŝeli warunek to zdanie gdzie warunek jest wyraŝeniem przyjmującym dwie wartości: wartość prawdy lub fałszu. Jeśli warunek przyjmie wartość prawdy, to wykonuje się zdanie, a gdy warunek przyjmie wartość fałszu, to zdanie nie zostaje wykonane. Przykład jeŝeli średnia ocen ucznia jest większa od 4.5 to wpisz ucznia na listę nagrodzonych uczniów b) struktury z alternatywą jeŝeli warunek to zdaniel w przeciwnym przypadku zdanie2 Przykład jeŝeli następny dzień to niedziela to wyłącz budzik w przeciwnym przypadku nastaw budzik na 6.40 2.3. ZDANIE ITERACYJNE PODCZAS GDY Zdanie to opisuje sytuację, w której pewne czynności naleŝy powtarzać dopóty, dopóki jest spełniony podany warunek. Zdanie to ma postać: podczas gdy warunek wykonuj zdanie Powtarzaną czynność opisuje zdanie. Powtarzanie tej czynności kończy się, gdy warunek przestaje być prawdziwy. Przykład podczas gdy istnieje zapas w magazynie wykonuj realizuj zlecenia wydania towaru Strona 6
2.4. ZDANIE ITERACYJNE POWTARZAJ Zdanie to, podobnie jak zdanie podczas gdy, opisuje sytuację, gdy pewne czynności naleŝy powtórzyć w zaleŝności od spełnienia określonego warunku. Zdanie to ma postać: powtarzaj zdanie aŝ warunek Przykład powtarzaj czytaj wartość liczby wykonaj operację na liczbie aŝ wczytano liczbę równą zeru 2.5. ZDANIE ITERACYJNE DLA Zdanie to stosujemy, gdy pewne działanie naleŝy powtórzyć określoną liczbę razy. Zdanie to ma następującą strukturę: dla lista sytuacji wykonuj zdanie Przykład: dla x=1,2,...,100 wykonuj drukuj wartości x, x do kwadratu oraz x do sześcianu 2.6. ZDANIE WYBIERZ Zdanie wybierz słuŝy do wyboru z kilku moŝliwości jednej. Ma ono postać: wybierz przełącznik z wartość_1: zdanie_1... wartość_n: zdanie_n w przeciwnym przypadku akcja awaryjna Przykład wybierz p z 1: wykonaj operację pierwszą 2: wykonaj operację drugą 3: wykonaj operację trzecią 4: wykonaj operację czwartą w przeciwnym przypadku wypisz komunikat o błędzie Strona 7
2.7. ZDANIE GRUPUJĄCE Zdanie to słuŝy do wskazania, Ŝe ciąg zdań ujęty w nawiasy grupowania moŝna traktować jako pojedyncze zdanie. Ma ono następującą postać: zdanie_l zdanie_2... zdanie_n Przykład jeŝeli rachunek ma saldo ujemne to wyślij ostrzeŝenie do klienta zapisz klienta na listę dłuŝników w przeciwnym przypadku wyślij zwykły wyciąg o stanie konta 3. POJĘCIE ZMIENNEJ. W języku programowania pod pojęciem danych występują takie wartości jak liczby naturalne, liczby całkowite, liczby rzeczywiste, znaki, ciągi znaków, czyli napisy (łańcuchy) posiadające sens lub nie, itp. Z kaŝdym algorytmem (programem) związany jest pewien zbiór danych, który musi zostać odpowiednio przetworzony w wyniku, czego wykonanie algorytmu prowadzi do otrzymania wyników. Podczas przetwarzania danych wykonuje się na nich róŝnego typu operacje jak np. modyfikacja danych czy obliczanie wyników pomocniczych. Do przechowywania wartości danych uŝywa się w języku programowania zmiennych, które są odpowiednikami występujących w matematyce niewiadomych. KaŜda niewiadoma ma ściśle określony zbiór, z którego moŝe przyjmować wartości, zwany zakresem zmienności zmiennej. Na podstawie tego właśnie zbioru mówimy o zmiennej naturalnej, całkowitej, wymiernej czy rzeczywistej. Takie zbiory występują równieŝ w językach programowania i nazywane są typami. W odróŝnieniu od matematyki nie mówimy, Ŝe zmienna X naleŝy do typu A, tylko fakt ten wypowiadamy krócej: X jest typu A. Zmiennym muszą być przypisane konkretne wartości. Przypisywanie wartości zmiennym stanowi podstawowe działanie wykonywane w algorytmach i programach komputerowych. Zawartość zmiennej moŝna wielokrotnie odczytywać, zamazywać i zapisywać. Do przechowywania wartości danej zmiennej wykorzystuje się zawsze to samo miejsce w pamięci operacyjnej komputera. Dlatego teŝ zmienną moŝna sobie wyobrazić jako pudełko do przechowywania wartości analizowanych danych. Strona 8
4.PRZYKŁADOWE ALGORYTMY W PSEUDO-KODZIE. 4.1. PIERWSZY ALGORYTM Obliczyć sumę i iloczyn elementów w ciągu liczb zakończonych zerem. Zakładamy, Ŝe w ciągu występuje co najmniej jedna liczba róŝna od zera. przypisz zmiennej suma wartosc 0 przypisz zmiennej iloczyn wartosc 1 wczytaj liczba podczas gdy liczba jest rozna od 0 wykonuj przypisz zmiennej suma wartosc suma plus wartosc liczba przypisz zmiennej iloczyn wartosc iloczyn razy wartosc liczba czytaj kolejna liczba wypisz wartosc zmiennych suma i iloczyn Analiza algorytmu, dla ciągu liczb: 2,4,5,3,0 suma iloczyn liczba 0 1 2 2 2 4 6 8 5 11 40 3 14 120 0 4.2. DRUGI ALGORYTM Wyznaczyć maksimum z trzech liczb a, b, c wykorzystując zdanie pseudo-kodu jeŝeli. wczytaj a, b, c jeŝeli a > b to jeŝeli a > c to wypisz a w przeciwnym przypadku wypisz c w przeciwnym przypadku jeŝeli b > c to wypisz b w przeciwnym przypadku wypisz c Gdzie znak > oznacza większe, czyli zdanie: a > b oznacza a większe od b Strona 9
4.3. ALGORYTM TRZECI Znaleźć najczęściej występujące wartości w ciągu liczb dodatnich (modalna) o długości określonej przez pierwszy wyraz ciągu. Dla ułatwienia zakładamy, Ŝe ciąg jest uporządkowany w kolejności nie-malejącej (np. 1,1,2,2,3,4,4,5,5,5,6,6). /* ustawiamy wartości początkowych zmiennych: */ licznik = 0 // licznik wystąpień modalna = 0 // modalną max = 0 // maksymalną liczbę wystąpień ostatni = - 1 // ostatnią liczbę czytaj dlugosc ciagu dla kazdej liczby z ciągu wykonuj czytaj liczba jeŝeli ostatni == liczba to licznik = licznik + 1 w przeciwnym przypadku jeŝeli licznik > max to max = licznik modalna = ostatni licznik = 1 ostatni = liczba jeŝeli licznik > max to max = licznik modalna = ostatni Gdzie znak = oznacza przypisz zmiennej.. wartosc, zatem zdanie licznik=0 oznacza przypisz zmiennej licznik wartosc 0 Znak == oznacza czy jest rowny?, zatem zdanie ostatni == liczba oznacza czy ostatni jest rowny liczba?. W celu znalezienia najczęściej powtarzającej się liczby w ciągu uporządkowanym wystarczy przeglądając kolejno elementy ciągu zliczać, ile razy wystąpiła ta sama liczba. JeŜeli przy przejściu do następnego elementu ciągu, liczba nie zmieniła się, to naleŝy zwiększyć licznik wystąpień, natomiast gdy nastąpiła zmiana naleŝy porównać wartość licznika wystąpień z wartością zmiennej max, w której przechowywana jest największa dotychczasowa liczba wystąpień. JeŜeli wartość licznika jest większa od wartości zmiennej max oznacza to, Ŝe znaleźliśmy najdłuŝszy do tej pory ciąg jednakowych liczb. NaleŜy wtedy ustawić nową wartość zmiennej max i nową wartość modalnej. KaŜdorazowo jeŝeli ostatnia liczba jest róŝna od aktualnie sprawdzanej naleŝy wartość licznika ustawić na jeden oraz za ostatnią liczbę przyjąć aktualną. Strona 10
5. REGUŁY ZAPISU WYRAśEŃ MATEMATYCZNYCH. Tekst programu powinien być zapisywany w postaci ciągu znaków dostępnych z klawiatury (bez znaków specjalnych, specyficznych dla danego języka narodowego, takich jak np.: ą, ä). NaleŜy pisać kaŝdy znak mnoŝenia *, nawet wtedy, gdy w matematyce zwykle się go opuszcza. Potęgowanie najlepiej zamieniać na mnoŝenie lub zapis przy pomocy operatora ˆ, przed którym naleŝy podać podstawę potęgowania, a po nim wykładnik potęgi. Natomiast we wszystkich ułamkach zwykłych kreskę ułamkową naleŝy zastąpić dzieleniem /. Przykład: Ułamek x-1 ( y + z 2 ) powinien być zapisany w sposób następujący: (x-1)/((y+z)*(y+z)) lub (x-1)/((y+z) ˆ2 II. PROGRAMOWANIE W JĘZYKU C LITERATURA 1. Brian W. Kerninghan, Dennis M. Ritchie: Język ANSI C. 2. Jerzy Grębosz: Symfonia C++. 3. Andrzej Zalewski: Programowanie w językach C i C++ z wykorzystaniem pakietu Borland C++. Strona 11
1. CECHY JĘZYKA 1. Język C jest językiem ogólnego stosowania, charakteryzuje się: prostotą wyraŝeń, bogatym zbiorem operatorów, efektywnością instrukcji oraz nowoczesnymi strukturami danych. Został opracowany i zrealizowany przez Dennisa Ritchie dla systemu Unix działającego na minikomputerze DEC PDP-11 w 1972 roku w Bell Laboratories w New Jersey. DuŜo elementów języka C pochodzi z języka BCPL, opracowanego przez Martina Richardsa, a takŝe z języka B, stworzonego w 1970 r. przez Kena Thompsona dla pierwszego systemu Unix działającego na maszynach DEC PDP 7. 2. ChociaŜ nazwano go "językiem programowania systemowego", (interesującym jest fakt, Ŝe sam system operacyjny Unix, kompilator języka C jak i ogromna grupa programów usługowych tego systemu została napisana w języku C) równie dobrze moŝna go uŝyć do pisania programów numerycznych, przetwarzania tekstów oraz obsługi baz danych. 3. Język C jest językiem względnie "niskiego poziomu", nie oznacza to nic negatywnego lecz to, Ŝe posługuje się tym samym zbiorem obiektów co większość kompilatorów, np. znakami, liczbami i adresami. Obiekty mogą być przemieszczane za pomocą zwykłych operacji arytmetycznych i logicznych. 4. W języku C nie istnieją operacje na obiektach złoŝonych traktowanych jako całość, takich jak ciągi znaków, pliki, listy, tablice czy rekordy. 5. Język C nie dostarcza instrukcji we/wy, brak w nim instrukcji typu Read czy Write oraz automatycznych metod dostępu do plików. Operacje we/wy są realizowane przez jawnie wywołane funkcje naleŝące do biblioteki standardowej(<stdio.h>). 6. Język C oferuje jedynie proste, jednoprocesorowe konstrukcje sterujące: instrukcje warunkowe, instrukcje pętli oraz funkcje. Nie zapewnia wieloprogramowości, współbieŝności i synchronizacji procesów. 7. W języku C występują wskaźniki - zmienne przechowujące adresy oraz jest moŝliwość wykonywania obliczeń na adresach obiektów dynamicznych. 8. W języku C definicje funkcji nie mogą być zagnieŝdŝone ( jedna w drugiej), podczas wywołania przekazywanie argumentów funkcjom odbywa się przez kopiowanie wartości argumentu aktualnego w miejsce argumentu formalnego ("przekazywanie przez wartość"). Funkcje mogą zwracać obliczone wartości, których typ określany jest w nagłówku jej definicji. 9. Aby zwrócić większą liczbę obliczonych wartości, moŝna zastosować efekt "przekazywania parametru przez adres" (znany z języka Pascal), naleŝy wtedy bezpośrednio przekazać do funkcji wskaźnik (adres) do obiektu, wówczas funkcja ma moŝliwość zmiany wartości (zwrócenia obliczonej wewnątrz funkcji wartości) wskazywanego obiektu. Jeśli argumentami funkcji są nazwy tablic, oznacza to, Ŝe przekazywane są adresy połoŝenia początków tablic. 10. W języku C dowolną funkcję moŝna wywołać rekurencyjnie (bezpośrednio lub pośrednio), zmienne lokalne funkcji są automatycznie tworzone przy kaŝdym jej wywołaniu. 11. W języku C rozróŝniane są duŝe i małe litery w nazwach obiektów, wszystkie uŝywane w programie obiekty muszą być wcześniej zadeklarowane. Program w języku C moŝe być zapisany w kilku plikach. W najprostszej postaci program jest funkcją o wyróŝnionej nazwie: main(). Strona 12
2. WPROWADZENIE DO PROGRAMOWANIA W JĘZYKU C Do przygotowania programów na komputerach PC w środowisku systemu Dos lub Windows, wykorzystamy pakiet programów firmy Borland, zawierający kompilator języka C i C++ wersji 3.11. Aktualnie na rynku moŝna spotkać równieŝ inne pakiety związane z językiem C: Visual C++, Builder C++. W ramach tego pakietu otrzymujemy: 1. edytor programów źródłowych, 2. kompilator, tłumaczący programy źródłowe w języku C lub C++ na język binarny. 3. program pomagający śledzić wykonywanie programów - Debugger. W innych systemach operacyjnych typu Unix lub Linux równieŝ istnieją kompilatory języka C lub C++. W przypadku systemu Unix musimy utworzyć program źródłowy w pliku o nazwie z rozszerzeniem '.c', np. nazwa.c a następnie przetłumaczyć go do postaci binarnej za pomocą polecenia: cc nazwa.c Jeśli tłumaczenie zakończy się sukcesem zostanie utworzony plik programu binarnego o nazwie 'a.out', który po załadowaniu i uruchomieniu wypisze wyniki. 3. PODSTAWOWE ELEMENTY JĘZYKA C Do podstawowych elementów języka C naleŝą: zestawy znaków, nazwy i słowa zastrzeŝone, typy danych, stałe, zmienne i ich deklaracje, wyraŝenia, INSTRUKCJE. 3.1. ZESTAW ZNAKÓW JĘZYKA C Do zestawu znaków w języku C naleŝą: duŝe litery alfabetu łacińskiego (od A do Z), małe litery (od a do z), cyfry (od 0 do 9), znaki specjalne: _!*/+-\"<>=#()[]^;', &:~ \b, \n, \t, \0 - oznaczają odpowiednio znaki: backspace, nowa linia, tabulacja, koniec słowa. Strona 13
3.2. NAZWY I SŁOWA ZASTRZEśONE JĘZYKA C Nazwy słuŝą do identyfikowania elementów w programie (stałych, zmiennych, funkcji, typów danych, itp.). Nazwa składa się z ciągu liter, cyfr i znaków podkreślenia, przy czym pierwszym znakiem musi być litera, ponadto rozróŝniane są duŝe i małe litery. Tradycyjnie w języku C nazwy zmiennych pisane są małymi literami, natomiast nazwy stałych symbolicznych - dla lepszego rozróŝnienia - pisane są duŝymi literami. Słowa zastrzeŝone (kluczowe) są to wybrane słowa o szczególnym znaczeniu dla języka C, np. char, case, while, for, void, return, if, else, itp. Słów tych nie wolno uŝywać jako nazw zmiennych. 3.3. PODSTAWOWE TYPY DANYCH. Do podstawowych typów danych języka C naleŝą: char znak - jeden bajt, int liczba całkowita short liczba całkowita krótka, long liczba całkowita długa, float liczba zmiennopozycyjna (rzeczywista-pojedynczej precyzji), double liczba zmiennopozycyjna podwójnej precyzji. 3.4. STAŁE. W języku C występują cztery rodzaje stałych programowych: Stałe całkowite: dziesiętne: 0, 123, -123, +999 ósemkowe: 0123, 0345, -0123 (uwaga: pierwszą cyfrą musi być zero) szesnastkowe: 0x123, 0xA1, 0xff (uwaga: pierwszymi znakami muszą być 0x lub 0X). Stałe rzeczywiste: 123.456, 12.23e-12 (oznacza 12.23 * 10-12 ), 12.34E+12 (oznacza 12.34 * 10 12 ). Stałe znakowe: znaki ujęte w apostrofy, np. 'a', 'A', '', '#', '1' escapesekwencje: \n, \t, \0, \b Łańcuchy znakowe: Łańcuchy znakowe to ciągi znaków ujęte w cudzysłów, np..:: " wynik= ", "WIELICZKA". Na łańcuch znaków moŝna patrzeć jak na pewne poindeksowane pole elementów, np. napis "Polska", jest reprezentowany jako: [P][o][l][s][k][a][\0] 0 1 2 3 4 5 6 - indeksy Strona 14
3.5. ZMIENNE I ICH DEKLARACJE. Zmienne w programie reprezentują komórki pamięci, w których będą przechowywane dane kreślonego typu. KaŜda zmienna powinna mięć nadaną wartość początkową, w trakcie pracy programu wartości poszczególnych zmiennych ulegają zwykle zmianom. Przed uŝyciem zmiennej naleŝy zmienną zadeklarować, tzn. określić typ i zakres wartości, jakie moŝe przyjmować. W przypadku języka C wszystkie zmienne naleŝy zadeklarować na początku programu lub funkcji, przed pierwszą instrukcją. Deklaracja zmiennej wygląda następująco: identyfikator_typu nazwa_zmiennej; Np.: deklaracja zmiennej numer typu rzeczywistego: int numer; MoŜna zadeklarować jednocześnie (jedną instrukcją) kilka zmiennych, jak równieŝ przy deklaracji moŝna zainicjalizować zmienną (nadać jej wartość początkową): int numer=1, licznik, a; // deklaracja zmiennych numer, licznik, a typu całkowitego // oraz inicjalizacja zmiennej numer wartością 1 Błędne oszacowanie typu lub zakresu zmiennej moŝe być przyczyną błędów kompilacji lub błędów wykonania programu. np.: Jeśli zadeklarujemy zmienne: promien i obwod typu całkowitego oraz pi typu rzeczywistego, a następnie wyznaczymy obwód okręgu o promieniu promien: int promien, obwod; float pi=3.14; to podstawienie obwod=2*promien*pi; spowoduje przypisanie wartości 0 zmiennej obwod. Jest to oczywiście błędny wynik, spowodowany przez dwa błędy: brak nadania wartości początkowej zmiennej promien, nieprawidłowy typ zmiennej obwod. 3.6. WYRAśENIA I OPERATORY WyraŜeniem moŝe być samodzielny element danych, np. liczba, znak, stała lub zmienna jak równieŝ kombinacja w/w elementów połączonych znakami odpowiednich operatorów, np. arytmetycznych, relacyjnych lub logicznych. Przykłady: b + c b /3 " wynik " + " = 12 " x > y x!= y x <=y x ==y k * ( a + 1 ) b[i-1] ++ Strona 15
3.7. INSTRUKCJE Instrukcja jest ciągiem znaków, oznaczającym polecenie przekazywane kompilatorowi do wykonania. Zazwyczaj (poza kilkoma wyjątkami) instrukcja musi być zakończona średnikiem. Instrukcje mogą być zapisywane w jednej linii po kilka (gdy są krótkie) lub w wielu liniach, gdy są długie. Z uwagi jednak na czytelność programu zaleca się pisanie jednej instrukcji w jednej linii. Instrukcje w języku C moŝna podzielić na następujące grupy: przypisania ( obliczające wartości zmiennych ) a = b + c ; instrukcje grupujące - (bloki: sekwencje instrukcji w nawiasach ) a=b+c; x=2*(a-1);... instrukcje sterujące: warunkowe if.. else, wielokrotnego wyboru switch case; instrukcje sterujące: pętle (while, for,do while); instrukcje wywołania funkcji. 4. KOMENTARZE Komentarze mogą być umieszczone w dowolnym miejscu programu i mają słuŝyć wyjaśnieniu wybranych fragmentów kodu. Treść komentarza jest opuszczana przez kompilator i nie jest interpretowana. Komentarze oznacza się w następujący sposób: /* treść komentarza*/ w językach C i C++ - wszystko, co znajduje się pomiędzy znakami /* oraz */ jest traktowane przez kompilator jako komentarz // komentarz do skomentowania jednej linii wszystko, co znajduje się po tym znaku jest traktowane przez kompilator jako komentarz - tylko język C++, jednak w przypadku naszego kompilatora, tego typu komentarze są dopuszczalne takŝe dla języka C. Komentarze nie mogą być zagnieŝdŝone, np.: nie jest poprawny następujący zapis: /* początek komentarza 1 /* początek komentarza 2 koniec komentarza 2*/ koniec komentarza 1*/ Strona 16
5. OPERATORY 5.1. OPERATORY PORÓWNANIA W językach C, C++ występują następujące operatory porównania: == // równy, np.: a==3 oznacza czy a równe 3!= // róŝny, np.: a!=3 oznacza czy a róŝne od 3 < // mniejszy, np.: a<3 oznacza czy a mniejsze od 3 > // większy, np.: a>3 oznacza czy a większe od 3 <= // mniejszy lub równy, np.: a<=3 oznacza czy a mniejsze lub równe 3 >= // większy lub równy, np.: a>=3 oznacza czy a większe lub równe 3 5.2. OPERATORY INKREMENTACJI (ZWIĘKSZANIA) I DEKREMENTACJI (ZMNIEJSZANIA) O JEDEN. Są to operatory ++ oraz --. Przykładowo instrukcje: a++; oraz ++a; oznaczają zwiększenie o 1 wartości zmiennej a. RóŜnica pomiędzy tymi instrukcjami jest następująca: x = a++; // oznacza, Ŝe najpierw zostanie wykonane podstawienie x = a, następnie //wartość zmiennej a zostanie zwiększona o 1. x = ++a; // oznacza, Ŝe najpierw wartość zmiennej a zostanie zwiększona o 1, następnie // zostanie wykonane podstawienie x = a. Zatem przykładowo: a = 3; if (b>3) x = a++; // x = 3, a = 4 else x = ++a; // x = 4, a = 4 Natomiast instrukcje: a--; oraz --a; oznaczają zmniejszenie o 1 wartości zmiennej a. RóŜnice po między nimi są identyczne jak powyŝej. 5.3. OPERATORY LOGICZNE. W językach C/C++ wartość logiczna prawda jest reprezentowana jako liczba całkowita róŝna od zera, zaś fałsz jako zero (całkowite). Jednak reprezentacja ta jest zaleŝna od kompilatora i moŝe nieco odbiegać od tego schematu, dlatego lepiej nie posługiwać się numerycznym odpowiednikiem wartości logicznych. Operatory umoŝliwiające operacje na wartościach logicznych to: Nazwa operatora Reprezentacja w C/C++ Reprezentacja w PascaluZnaczenie koniunkcja && and i (iloczyn logiczny) alternatywa or lub (suma logiczna) negacja! not nieprawda, Ŝe Strona 17
Przykłady zastosowań: if ((a>b) && (a>c)) // jeśli a>b i a>c to podstaw max = a max = a; if ((a>b) or (a>c)) // jeśli a>b lub a>c to zmniejsz a o 1 a--; if!koniec // jeśli nieprawda, Ŝe koniec to zwiększ a o 1 a++; 6. INSTRUKCJE PODSTAWIENIA Ma ona postać: identyfikator_nazwy_zmiennej = wartosc np.: a = 3; // zmiennej o nazwie a została przypisana wartość 3 a = (a-3)*2; // zmiennej a została przypisana wartość (a-3)*2 Wartość przypisywana zmiennej musi być zgodna z typem zmiennej. Inne instrukcje przypisania: a += 3; // oznacza podstawienie: a = a + 3 a *= 3; // oznacza podstawienie: a = a * 3 a *= y - 5; // oznacza podstawienie: a = a * (y 5) a /= 3; // oznacza podstawienie: a = a / 3 a %= 3; // oznacza podstawienie: a = a % 3, czyli podstaw resztę z dzielenia a przez 3 a ^= 3; // oznacza podstawienie: a = a ^ 3, czyli podstaw a do potęgi 3 a -= 3; // oznacza podstawienie: a = a - 3 7. INSTRUKCJE GRUPUJĄCE NAWIASY KLAMROWE Nawiasy klamrowe słuŝą do grupowania instrukcji prostych oraz deklaracji w jedną instrukcję złoŝoną, czyli blok, aby całość składniowo odpowiadała jednej instrukcji. Pełnią funkcję instrukcji begin i end z Pascala. Stosuje się je np.: w instrukcjach sterujących if, for, while, do while itd. Strona 18
8. INSTRUKCJE WYBORU. 8.1. INSTRUKCJA IF ELSE if (warunek) instrukcja1; else instrukcja2; Konstrukcja ta oznacza: jeśli warunek jest spełniony to wykonaj instrukcje instrukcja1, w przeciwnym wypadku wykonaj instrukcje instrukcja2. Jeśli instrukcja1 lub instrukcja2 składa się z więcej niŝ jednej instrukcji prostej, to jest to naleŝy umieścić ją w nawiasach klamrowych. Część else nie jest wymagana. Jest ona związana z najbliŝszą, poprzedzającą ją instrukcją if, o ile nie zostaną uŝyte nawiasy klamrowe, określające inne przyporządkowanie, np.: if (a<b) if (a>c) a=c; else a=b; Część else dotyczy drugiej instrukcji if, czyli if (a>c). if (a<b) if (a>c) a=c; else a=b; Część else dotyczy pierwszej instrukcji if, czyli if (a<b). 8.2. INSTRUKCJA WIELOKROTNEGO WYBORU SWITCH. switch (wyraŝenie) case wartość1: instrukcja1; break; case wartość2: instrukcja2; break;... default: // ta część jest opcjonalna nie jest wymagana instrukcja3; break; SłuŜy ona do podejmowania wyboru: jeśli wartość wyraŝenia odpowiada jednej z wartości, podanych po słowie case, to są realizowane instrukcję odpowiadające temu przypadkowi. JeŜeli wyraŝenie nie przyjmuję Ŝadnej z wymienionych wartości, to albo zostaną wykonane akcje, zdefiniowane po słowie default, o ile ta część jest zdefiniowana, albo nie zostanie wykonana Ŝadna akcja, jeśli nie jest zdefiniowana część default. Instrukcja break powoduje natychmiastowe opuszczenie instrukcji switch i gwarantuje wybranie tylko jednej moŝliwości Strona 19
spośród podanych w instrukcji. Jest to związane z tym, Ŝe poszczególne przypadki (określone przez case) oznaczają etykiety i po wykonaniu akcji związanych z daną etykietą program przechodzi do wykonania następnej etykiety, chyba, Ŝe zostanie zaŝądane wykonanie instrukcji break, które spowoduje opuszczenie całej instrukcji. 9. INSTRUKCJE ITERACYJNE (PĘTLE). Instrukcja iteracyjna powoduje wielokrotne wykonywanie pewnego fragmentu kodu w zaleŝności od spełnienia podanego warunku. 9.1. PĘTLA WHILE. Jest to instrukcja iteracyjna, której składnia ma postać: while (warunek) instrukcje; W pętli while najpierw oblicza się warunek i jeśli jest prawdziwy, to są wykonywane instrukcje, potem znów sprawdzany jest warunek. Operacje te są powtarzane dotąd, dokąd jest spełniony (prawdziwy) warunek. Przykładowe wykorzystanie pętli while: suma=0; while(i<100) suma = suma + i; i++; NaleŜy pamiętać, Ŝe w przypadku wykonywania w pętli while więcej instrukcji niŝ jedna, naleŝy wszystkie te instrukcje umieścić w nawiasach klamrowych. 9.2. PĘTLA FOR. Jest to instrukcja iteracyjna, której składnia ma postać: for (wyrazenie1;wyrazenie2;wyrazenie3) instrukcje; W pętli for najpierw wykonywane jest wyrazenie1, następnie wylicza się wartość wyraŝenia wyrazenie2 i jeśli jest prawdziwe, to są wykonywane instrukcje, potem jest wyliczana wartość wyraŝenia wyrazenie3 i znów sprawdzana jest wartość wyraŝenia wyrazenie2. Operacje te są powtarzane dotąd, dokąd jest spełnione (prawdziwe) wyraŝenie wyrazenie2. Wyrazenie1 zazwyczaj ma charakter instrukcji podstawienia lub jest wywołaniem funkcji i ustala warunki początkowe. Wyrazenie2 jest warunkiem i ustala warunek opuszczenia pętli. Wyrazenie3 równieŝ ma charakter instrukcji podstawienia lub jest wywołaniem funkcji i steruje licznikiem pętli. Dowolną z tych części moŝna pominąć, ale naleŝy pozostawić Strona 20
średniki. Opuszczenie części środkowej powoduje utworzenie pętli nieskończonej, gdyŝ automatycznie przyjmuje się w takiej sytuacji, Ŝe jest ono prawdziwe, dlatego naleŝy w inny sposób zagwarantować opuszczenie pętli, np.: przez warunkowe uŝycie instrukcji break. Przykładowe wykorzystania pętli for: suma=0; for(i=1; i<100; i++) suma = suma + i; Fragment kodu równowaŝny powyŝszemu, z zastosowaniem nieskończonej pętli for. suma=0; for(i=1; ; i++) if(i==100) break; suma+=1; TakŜe w pętli for w przypadku wykonywania więcej instrukcji niŝ jedna, naleŝy wszystkie te instrukcje umieścić w nawiasach klamrowych. 9.3. PĘTLA DO WHILE. Jest to instrukcja iteracyjna, której składnia ma postać: do instrukcje; while (warunek) W pętli do while najpierw wykonywane są instrukcje, następnie sprawdza się wartość warunek i jeśli jest prawdziwy, to znów są wykonywane instrukcje. Operacje te są powtarzane dotąd, dopóki jest spełniony (prawdziwy) warunek. Instrukcja ta tym róŝni się od poprzednich, Ŝe zawsze się wykona przynajmniej raz. Przykładowe uŝycie pętli do while: suma=0; i=0; do suma=suma+i; i++ while(i<100); RównieŜ w pętli do while w przypadku wykonywania więcej instrukcji niŝ jedna, naleŝy wszystkie te instrukcje umieścić w nawiasach klamrowych. Strona 21
10. INNE INSTRUCJE STERUJĄCE PRZEBIEGIEM PROGRAMU. 10.1. INSTRUKCJA BREAK. Instrukcja break, czyli przerwij jest dopuszczalna tylko w instrukcjach iteracyjnych (for, while, do.. while) oraz instrukcji wyboru switch. Powoduje ona opuszczenie aktualnego poziomu pętli lub instrukcji wyboru, czyli wychodzi z pętli lub instrukcji switch. Jeśli pętle są zagnieŝdŝone, to break powoduje opuszczenie tylko tej pętli, w której został wykonany. Składnia instrukcji: break; 10.2. INSTRUKCJA CONTINUE. Instrukcja continue, czyli kontynuuj moŝe być stosowana jedyne wewnątrz instrukcji iteracyjnych. Jej uŝycie wewnątrz pętli while oraz do.. while powoduje przeniesienie sterowania z wnętrza pętli do wyraŝenia warunkowego, które zostanie obliczone i w spowoduje wykonanie odpowiedniej akcji. Wykonanie instrukcji continue wewnątrz pętli for spowoduje przekazanie sterowania do wyraŝenia zwiększającego licznik. Podobnie jak w przypadku instrukcji break, tak teŝ instrukcja continue jest związana z najbliŝszą pętlą w sytuacji, gdy pętle są zagnieŝdŝone. Składnia instrukcji: continue; 10.3. INSTRUKCJA RETURN. Instrukcja return, czyli zwróć wartość i powróć powoduje zakończenie wykonywania funkcji. Jeśli funkcja zwraca wartość, to wykonanie instrukcji return spowoduje równieŝ zwrócenie tej wartości. Składnia instrukcji: return wyraŝenie; 10.4. INSTRUKCJA SKOKU DO ETYKIETY. Instrukcja skoku do etykiety umoŝliwia przeniesienie sterowania do określonego miejsca wewnątrz aktualnie wykonywanej funkcji programu. Składnia instrukcji: goto etykieta; Etykieta określa miejsce w programie, do którego ma nastąpić skok. NiemoŜliwy jest skok do miejsc znajdujących się poza funkcją, do której naleŝy instrukcja skoku. Nie naleŝy naduŝywać tej instrukcji, gdyŝ pogarsza ona czytelność programu, a jej uŝycie nie zawsze jest uzasadnione. Etykieta składa się z nazwy, zakończonej dwukropkiem, np.: Etykieta1: Instrukcje; Etykieta2: Instrukcje; Strona 22
11. OGÓLNA STRUKTURA PROGRAMU NAJPROSTSZY PROGRAM W JĘZYKU C. Na ogólną strukturę programu w języku C składają się następujące elementy: Dyrektywy preprocesora: włączające biblioteki, makrodefinicje (opcjonalnie), warunkowa kompilacja (opcjonalnie); Deklaracje zmiennych globalnych oraz funkcji (opcjonalnie jeśli są potrzebne); Definicje funkcji (jeśli w programie są wykorzystywane jakieś własne funkcje i będą one wywoływane w funkcjach znajdujących się poniŝej); Funkcja główna programu main od tej funkcji rozpocznie się wykonywanie programu (jest ona obowiązkowa!!!); Pozostałe definicje funkcji (opcjonalnie jeśli nie zostały wcześniej podane). Przykład najprostszego programu w języku C: #include <stdio.h> main() //Dyrektywy preprocesora //Funkcja główna programu main printf( Witam w najprostszym programie w języku C! ); return 0; Zostały tu pominięte wszystkie części struktury programu, które nie są wymagane. Inny przykład prostego programu, który zawiera wszystkie wymienione powyŝej elementy. #include <stdio.h> #include <conio.h> int aa; void f2(); // Dyrektywy preprocesora // Deklaracja zmiennej globalnej aa // Deklaracja funkji f2 int f1() // Definicja funkcji f1 printf("\ntu funkcja f1! \nnaciśnij dowolny klawisz...\n"); getch(); return 0; main() // Definicja funkcji głównej int a=5; char tab_dom[]="dom"; clrscr(); printf("\nahoj, przygodo! \nnasza zmienna globalna to %d",aa); printf("\n A to nasza tablica: %s, a jej rozmiar %d",tab_dom, sizeof(tab_dom)); printf( \Naciśni dowolny klawisz... ); getch(); f1(); f2(); return a+aa; void f2() printf("\ntu funkcja f2!\n"); printf("press any key...\n"); getch(); return; // Definicja pozostałej funkcji Strona 23
12. PREPROCESOR. Preprocesor języka C jest pojęciowo oddzielnym, pierwszym krokiem tłumaczenia programu. Wykonuje on tzw. dyrektywy preprocesora, odpowiedzialne za makrodefinicje, włączanie zawartości innych plików źródłowych oraz kompilację warunkową. Wszystkie dyrektywy preprocesora zaczynają się od znaku #. 12.1. DYREKTYWA WŁĄCZAJĄCA PLIKI BIBLIOTECZNE. Jest to dyrektywa #include, która powoduje zastąpienie tej instrukcji zawartością pliku o wskazanej nazwie. W ten sposób włączane są biblioteki, czyli pliki o rozszerzeniu h, zawierające kompletne definicje zmiennych, stałych oraz funkcji. Składnia instrukcji jest następująca: #include <nazwa_biblioteki.h> Np.: #include <stdio.h> PowyŜsza instrukcja jest poleceniem włączenia do programu standardowej biblioteki języka C o nazwie stdio.h, która zawiera definicje podstawowych funkcji tego języka. Jeśli dołączamy bibliotekę standardową, to jej nazwę naleŝy ująć w nawiasy <>. Natomiast w przypadku włączania bibliotek niestandardowych (np.: napisanych przez nas) nazwę biblioteki naleŝy ująć w cudzysłów, np.: #include <stdio.h> #include moja_bl.h Stosowanie tej dyrektywy gwarantuje, Ŝe w wielomodułowym programie w kaŝdym module wszystkie definicje i deklaracje zmiennych będą identyczne. A dla programów jednomodułowych, jak teŝ wielomodułowych, dyrektywa ta umoŝliwia korzystanie z funkcji standardowych języka. 12.2. DYREKTYWY MAKRODEFINICJI. Są to dyrektywy #define i #undef, które słuŝą do definiowania lub kasowania definicji nazwy. Składnia tych dyrektyw jest następująca: #define nazwa zastepujacy_tekst_lub_wartosc #undef nazwa_do_skasowania Po wystąpieniu dyrektywy #define wszystkie wystąpienia nazwa będą zastępowane przez ciąg znaków podany w zastepujacy_tekst_lub_wartosc. Dyrektywa #undef kasuje wcześniejszą definicję. Przykłady makrodefinicji: #define Pi 3.14 // kaŝde wystąpienie słowa Pi będzie zastąpione wartością 3.14 #define max(a,b) ((A)>(B)? (A) : (B)) // Makrodefinicja do wyznaczania // maksymalnej wartości spośród dwóch liczb. #undef Pi // definicja Pi została wykasowana teraz Pi nic juŝ nie znaczy. Strona 24
12.3. DYREKTYWY WARUNKOWEJ KOMPILACJI. Są to dyrektywy: #if, #else, #endif, #elif, #ifdef, #ifndef. Realizują one trochę rozbudowaną instrukcję if-else dla preprocesora, np.: #if system==mswindowsnt #define Pi 3.14 #else #define Pi 3.1423456 #endif Znaczenie dyrektyw: #elif: #else if #ifdef: #if zdfefiniowano #ifndef: #if nie_zdefiniowali W zaleŝności od treści tych dyrektyw preprocesor wykonuje pewne operacje lub nie. 13. FUNKCJE. Funkcje to małe programy, podprogramy. Są to logicznie spójne fragmenty programu, które moŝna wydzielić z całości i potraktować jako jedno zadanie, polecenie, jeden krok w algorytmie. Zazwyczaj program dzieli się na takie kawałki, aby uzyskać większą przejrzystość algorytmu i poprawić jego czytelność. Często tak skonstruowane funkcje są wielokrotnie wykorzystywane w programie w róŝnych miejscach. Mogą być równieŝ stosowane w wielu róŝnych programach. Taki program moŝna porównać do budowli z klocków, a funkcje do samych klocków. Podczas deklaracji funkcji w języku C/C++ naleŝy podać typ zwracanej wartości (jeśli nie zostanie podany, to domyślnie jest to typ całkowity), nazwę funkcji oraz listę jej parametrów. Wszystkie te elementy składają się na tzw. prototyp funkcji. Wygląda to następująco: identyfikator_typu_zwracanej_wartosci nazwa_funkcji (lista_parametrow_funkcji); np.: int Max(int a, int b); // funkcja Max zwraca wartość typu całkowitego, posiada dwa // parametry typu całkowitego. Przy definicji funkcji naleŝy dodatkowo podać zawartość ciała funkcji, które jest umieszczone w nawiasach klamrowych, np.: int Max(int a, int b) int wynik; if (a>b) wynik=a; else wynik=b return wynik; // Ciało funkcji Strona 25
Na wewnętrzną strukturę funkcji składają się deklaracje zmiennych i stałych (w języku C muszą one wystąpić na początku funkcji, w przypadku C++ mogą wystąpić w dowolnym miejscu, ale zanim zostaną uŝyte) oraz instrukcje, wśród których musi znaleźć się instrukcja return bez względu na to, czy funkcja zwraca jakąś wartość, czy teŝ nie (typ void). W języku C/C++ nie ma procedur, ich rolę spełniają funkcje, które zwracają wartość typu void. Wywołanie funkcji wygląda następująco: zm_max=max(13,b); // do zmiennej zm_max wstaw wartość zwracaną // przez funkcję Max dla argumentów 13 i b Strona 26
14. PODSTAWOWE TYPY DANYCH - CD. 14.1. TYPY CAŁKOWITE. TYP Rozmiar w bajtach Wartość min Wartość max unsigned char 1 0 255 signed char 1-128 127 unsigned int 2 0 65535 short signed int 2-32768 32767 signed int 2-32768 32767 long unsigned int 4 0 4294967295 long signed int 4-2147483648 2147483647 W niektórych kompilatorach rozmiar dla niektórych typów moŝe być nieco inny, co powoduję równieŝ zmianę wartości min i max dla danego typu. RównowaŜność typów całkowitych: Typ char short unsigned short int unsigned long unsigned long Typy równowaŝne signed char lub unsigned char (zaleŝy od opcji kompilatora) short int, short signed, short signed int unsigned short int signed int unsigned int long int, signed long int unsigned long int Zmienne całkowite są reprezentowane w dwojaki sposób: bez znaku (unsined) lub ze znakiem (signed). W przypadku danych typu char (typ znakowy) wartość moŝe zostać przypisana na dwa sposoby: przez podanie stałej dziesiętnej (liczby) lub znaku ujętego w apostrofy, np.: char literab=66; // równowaŝne literab = B char literaa= A ; // równowaŝne literaa = 65 signed char znak=-71; // równowaŝne znak = «char znakenter= \n ; // znak specjalny przejście do następnej linii char znak7c= \x7c ; // znak o kodzie szesnastkowym 7c char znak8= \10 ; // znak o kodzie dziesiętnym 8 (ósemkowo 10) Strona 27
14.2. TYPY RZECZYWISTE. Typ Rozmiar w bajtach Zakres float 4 3.4*10-38 3.4*10 38 double 8 1.7*10-308 1.7*10 308 long double 10 3.4*10-4932 1.1*10 4932 W niektórych kompilatorach rozmiar dla niektórych typów moŝe być nieco inny, co powoduję równieŝ zmianę wartości min i max dla danego typu. Przykłady deklaracji i inicjalizacji zmiennych rzeczywistych: float s=123.16e10; // wartość 123.16*10 10 double x=10.0; // wartość 10 double y=10.; // wartość 10 long double x=.12398; // wartość 0.12398 double xx=-123.98; // wartość 123.98 double xy=.98e-5; // wartość 0.98*10-5 float xz=10.08e37f; // wartość 10.08*10 37, typ float korzysta w pełni z precyzji typu 14.3. TYP VOID. Typ void reprezentuje pusty zbiór wartości. Jest uŝywany często jako typ wartości zwracanej przez funkcję, która nie zwraca Ŝadnej wartości. MoŜe być równieŝ wykorzystany do deklarowania wskaźników, wskazujących na obiekty nieznanego typu. 14.4. TYP WYLICZENIOWY. Typ wyliczeniowy jest osobnym typem dla liczb całkowitych. Składa się z listy nazw, którym zostały przyporządkowane wartości całkowite. Pierwsza nazwa na liście ma wartość zero, następna wartość 1 i tak dalej, chyba, Ŝe jawnie zostanie nadana inna wartość. Wszystkie nazwy, nieokreślone jawną wartością, przyjmują wartość kolejnych liczb całkowitych od ostatnio określonej wartości. Deklaracja wygląda następująco: enum nazwa_typu lista wyliczeniowa nazw; Np.: enum dni Pon,Wt,Sr,Czw,Pt,Sob,Nie; // Pon=0, Wt=1 itd. enum dni Pon=1,Wt,Sr,Czw,Pt=10,Sob,Nie; // Pon=1, Wt=2, Pt=10, Sob=11 itd.. 14.6. TYP LOGICZNY W języku C/C++ nie ma zmiennej typu logicznego, która odpowiadałaby pascalowskiej zmiennej typu Boolean. Typ ten pojawia się dopiero w niektórych kompilatorach dla C++ (np.: Borland Builder C++ 4.0) i jest zdefiniowany jako typ wyliczeniowy o nazwie Bool. Jednak samo pojęcie prawdy lub fałszu jest rozpoznawane i w większości kompilatorów języka C wartość FALSE (fałsz) jest utoŝsamiana z zerem, zaś wartość TRUE (prawda) jest utoŝsamiana z kaŝdą liczbą całkowitą, róŝną od zera. Strona 28
14.5. TYP TABLICOWY. Tablica jest złoŝoną strukturą danych, składającą się z elementów tego samego typu. Zajmuje ona ciągły obszar pamięci o rozmiarze potrzebnym do zapamiętania jej elementów. Elementy tablicy mogą być dowolnego typu oprócz typu referencyjnego. Deklaracja n-wymiarowej tablicy: identyfikator_typu elementu nazwatablicy[wymiar1][wymiar2]...[wymiarn]; Jeśli nie podamy rozmiaru tablicy, to musimy ją od razu zainicjalizować, jej rozmiar zostanie obliczony na podstawie wartości przypisanej podczas inicjalizacji. W przypadku tablic wielowymiarowych moŝna opuścić tylko pierwszy wymiar. Przykłady deklaracji i inicjalizacji char str[30]; int tab[15]; char str1[6]= Rynek ; char tab_dom[]= dom ; int tab1[4]=0,1,2,3; int tab3[2][3]=1,2,3,4,5,6; // tablica 30 znaków // tablica 15 liczb całkowitych // deklaracja tablicy 6 znaków oraz // inicjalizacja zmiennej wartością Rynek // równowaŝna deklaracja: char tab_dom[]= dom ; // deklaracja 4 elementowej tablicy liczb całkowitych // połączona z inicjalizacją // deklaracja 2-wymiarowej tablicy połączona z // inicjalizacją, pierwszy wymiar oznacza liczbę wierszy, // drugi liczbę kolumn: tab3 posiada 2 wiersze // zawierające po 3 elementy (3 kolumny) NaleŜy pamiętać, Ŝe w języku C/C++ elementy tablic są numerowane od zera. W przypadku tablic znakowych naleŝy równieŝ pamiętać o zarezerwowaniu dodatkowego elementu tablicy na znak końca łańcucha znaków ( \0 ), np.: dla słowa dom naleŝy zadeklarować tablicę 4-ro elementową (a nie 3- elementową): char tab_dom[4]= dom ; Odwoływanie się do poszczególnych elementów tablicy realizowane jest przy pomocy nawiasów kwadratowych, np.: char tab[]= domek ; char znak; znak=tab[0]; // Zmiennej znak zostanie nadana wartość d tab[0]= T ; // Aktualna zawartość tablicy tab to słowo Tomek Strona 29
15. ZASIĘG ZMIENNYCH. Ogólnie rzecz biorąc, zmienna jest widoczna w obrębie modułu, w którym jest zadeklarowana od momentu deklaracji. Zmienne moŝemy podzielić na zewnętrzne (globalne) oraz lokalne (prywatne, automatyczne). Deklaracje zmiennych zewnętrznych (globalnych) znajdują się za zewnątrz wszystkich funkcji i są dostępne przez nazwę we wszystkich funkcjach znajdujących się w pliku, w którym zostały zadeklarowane. Jeśli program składa się z wielu modułów to zmienne zewnętrzne są widoczne w tych modułach, w których została powtórzona ich deklaracja ze słowem extern. RównieŜ, jeśli w jakiejś funkcji uŝywamy zmiennej zewnętrznej, a jej deklaracja znajduje się w dalsze części pliku, to naleŝy ją zadeklarować wewnątrz funkcji, ale ze słowem extern. Jeśli np.: w pliku głównym mamy deklarację int licznik; Aby ta zmienna była widoczna w innych modułach programu, musimy umieścić w nich deklarację: extern int licznik; Deklaracja zmiennej globalnej jest równocześnie jej definicją (inicjalizacją), czyli powoduje przydzielenie jej rzeczywistej pamięci i nadanie wartości domyślnej w zaleŝności od jej typu. Zmienna zewnętrzna (globalna) istnieje przez cały czas działania programu i zachowuje swoją wartość nawet po zakończeniu działania funkcji, która nadała jej wartość. Natomiast deklaracje zmiennych lokalnych (automatycznych) to deklaracje prywatnych zmiennych funkcji. Znajdują się one w ciele funkcji i Ŝadna inna funkcja nie ma do nich dostępu. Są one widoczne tylko w obrębie danej funkcji i pojawiają się oraz znikają wraz z wywołaniem funkcji istnieją tylko podczas wykonywania funkcji. Dlatego teŝ zmienne te nie zachowują swoich wartości i za kaŝdym razem, gdy dana funkcja jest wywoływana, to naleŝy nadać im wartość. Aby zmienne lokalna zachowywała swoją wartość pomiędzy poszczególnymi wywołaniami funkcji, to naleŝy zadeklarować ją w tej funkcji jako zmienną statyczną, czyli jej deklarację poprzedzić słowem static. Wówczas zmienna ta nie znika wraz z zakończeniem działania funkcji, tylko istnieje pomiędzy jej wywołaniami. Deklaracja zmiennej automatycznej nie powoduje ani przydzielenia jej pamięci, ani nadania wartości początkowej, dlatego teŝ naleŝy ją zainicjalizować, w przeciwnym wypadku będzie zawierać śmieci. Przykład: #include <stdio.h> int licznik; // Zmienna globalna, została zainicjalizowana wartością domyślną, dla // int jest to zero, czyli licznik=0 int f1() // funkcja o nazwie f1 int moja, moja1=5; // Zmienne lokalne, nie są automatycznie inicjalizowane, dlatego // zmienna moja zawiera śmieci. static int zm_statyczna=0; // Zmienna statyczna, zachowa swoją poprzednią wartość przy // następnym wywołaniu funkcji moja=licznik+1; // Zmiennej moja zostaje przypisana wartość 1, po zakończeniu // działania funkcji straci ona swoją wartość. zm_statyczna++; // Wartość zmiennej statycznej została zwiększona o 1 i taką wartość Strona 30