1k likes | 1.18k Views
Programowanie strukturalne i obiektowe – język C. Programowanie. Język C B. W. Kernighan, Dennis M. Ritchie – „Język ANSI C” kompilator GCC http://gcc.gnu.org system operacyjny Microsoft Windows XP środowisko programistyczne DEV-C++ http:// www.bloodshed.net/devcpp.html.
E N D
Programowanie • Język C • B. W. Kernighan, Dennis M. Ritchie – „Język ANSI C” • kompilator GCC • http://gcc.gnu.org • system operacyjny Microsoft Windows XP • środowisko programistyczne DEV-C++ • http://www.bloodshed.net/devcpp.html
Odrobina historii języka C • 1969 – Martin Richards – język BCPL • 1970 – Ken Thompson – język B • adaptacja dla UNIX na maszynie DEC PDP-7 • 1972 – Dennis Ritchie – język C • DEC PDP-11 • 1983-1989 – standaryzacja ANSI • American National Standards Institute • 1990 – standard ISO • International Organization for Standardization
Podstawowe cechy języka C • język ogólnego stosowania • względnie „niski poziom” • język imperatywny (proceduralny) • podstawowe konstrukcje sterujące programowania strukturalnego: • grupowanie instrukcji, podejmowanie decyzji, wybór przypadku, powtarzanie ze sprawdzaniem warunku zatrzymania na początku i końcu pętli, przerwanie pętli
Podstawowe cechy języka C – c.d. • język typowy • typy podstawowe: znaki, liczby całkowite i zmiennopozycyjne w różnych zakresach • typy pochodne: wskaźniki, tablice, struktury, unie • wyrażenia buduje się z operatorów i ich argumentów • wyrażenie może pełnić rolę instrukcji • włącznie z przypisaniem i wywołaniem funkcji • input/output jest częścią biblioteki a nie języka • przenośny - niezależny od architektury • system UNIX jest rozwijany w języku C
Elementarz • „Nie można się nauczyć programowania bez samodzielnego pisania programów!” • proces kompilacji • edycja kodu źródłowego (*.c) • asemblacja (*.o) • konsolidacja (plik uruchamialny, np. *.exe) • pierwszy program • Wypisanie na konsoli napisu „Hello World!”
Podstawowe typy danych • int • -32768 ... +32767 (przynajmniej 2 bajty) • float • 1.E-36 … 1.E+36 (4 bajty, precyzja do 7 miejsc) • double • 1.E-303 … 1.E+303 (8 bajtów, precyzja do 13 miejsc) • char • 0 … 255 (1 bajt)
Deklaracje zmiennych i stałych • typ nazwa-zmiennej; • int a; • int x,y,z; • int count=7; • const typ nazwa-stałej = wartość; • const int NUM=123; • const float PI=3.14;
Dodatkowe deklaratory typu • short • short int = short • long • long int = long • signed • unsigned
Stałe znakowe i liczbowe • "string" • ‘A’, ‘a’, … • ‘A’ = 65 • ‘\ooo’ • ‘\xhh’ • \n, \t, \r, … • 1234 • 123456789L (123456789l) • 123U (123u) • 31 = 037 = 0x1f = 0X1F
Formatowany input/output • printf(…); • int res=7; printf("Result: %d",res); • int a=2; int res; res=a+7; printf("In:%d, Result: %d",a,res); • scanf(…); • int dat; scanf("%d",&dat); • char str[20]; scanf("%s",str);
Formatowany input/output – c.d. Usual variable type Display %c char single character %d (%i) int signed integer %e (%E) float or double exponential format %f float or double signed decimal %g (%G) float or double use %f or %e as required %o int unsigned octal value %p pointer address stored in pointer %s array of char sequence of characters %u int unsigned decimal %x (%X) int unsigned hex value
Formatowany input/output – c.d. flag width.precision flag meaning - left justify + always display sign space display space if there is no sign 0 pad with leading zeros # use alternate form of specifier
Formatowany input/output – c.d. %#o adds a leading 0 to the octal value %#x adds a leading 0x to the hex value %#f or %#e ensures decimal point is printed %#g displays trailing zeros
Operacje i operatory • Arytmetyczne: • +, -, *, /, % (modulo) • Inkrementacja: • ++, -- (++x, x++) • Przypisanie: • =, +=, -=, *=, /=, … • Relacyjne: • ==, !=, <, >, <=, >= • Logiczne • &&, ||, ! • Bitowe: • & (AND), | (OR), ^ (XOR), <<, >>, ~ • Koercja/rzutowanie (ang. cast) • (typ) wyrażenie • (float)2/5
Wyrażenia warunkowe • wyr1?wyr2:wyr3 • Np. z=(a>b) ? a : b; • /*z=max(a,b)*/
Instrukcja warunkowa • if(wyrażenie)instrukcja • {…} – instrukcja złożona • if(wyrażenie)instrukcja1elseinstrukcja2 • if(wyrażenie1)instrukcja1else if(wyrażenie2)instrukcja2…else if(wyrażenieX)instrukcjaXelseinstrukcja
Instrukcja wyboru • switch(wyrażenie) {casewyrażenie-stałe1:instrukcje1casewyrażenie-stałe2:instrukcje2default:instrukcje} • break
Instrukcje skoku • bezwarunkowe przekazanie sterowania do innego miejsca • return wyrażenieopc; • break; • continue; • goto etykieta; • etykieta: - poprawny identyfikator • skok w obrębie tej samej funkcji • nie należy nadużywać! • uzasadnione w przypadku wyskoku z kilku pętli jednocześnie
Instrukcje iteracyjne (pętli) • while (wyrażenie) instrukcja • do instrukcja while (wyrażenie); • for (wyr1opc; wyr2opc; wyr3opc) instrukcja • można opuścić wyrażenia • for (;;) instrukcja • for (;;) ; • ominięcie wyr2 jest równoważne wystąpieniu stałej różnej od zera
Instrukcje pętli - przerywanie • break; • przerwanie "najciaśniej otaczającej" pętli • continue; • przekazanie sterowania do miejsca wznowienia "najciaśniej otaczającej" pętli
Przerywanie pętli - c.d. while (...){ do { for(...){ ... ... ... } } while (...); } br: ; br: ; br: ; • break; jest równoważne goto br; jeśli w ciele pętli nie występuje "ciaśniejsza" pętla
Przerywanie pętli - c.d. while (...){ do { for(...){ ... ... ... contin: ; contin: ; contin: ; } } while (...); } • continue; jest równoważne goto contin; jeśli w ciele pętli nie występuje "ciaśniejsza" pętla
Instrukcje pętli - równoważność • for (wyr1; wyr2; wyr3) instrukcja • wyr1; while (wyr2){ instrukcjawyr3 ;} • Uwaga: pętle są równoważne gdy instrukcja nie zawiera continue;
Instrukcje pętli - porównanie • while (wyrażenie) instrukcja • wyrażenie sprawdzane na początku - instrukcja nie musi być wykonana ani razu • np. odczyt z pliku • do instrukcja while (wyrażenie); • wyrażenie sprawdzane na końcu - instrukcja musi być wykonana przynajmniej raz • for (wyr1; wyr2; wyr3) instrukcja • zwykle wyr1 to inicjalizacja a wyr3 to inkrementacja • np. ustalona liczba iteracji
Tablice • deklaracja:typidentyfikator [rozmiar]; • np. int array[7]; char tab[256]; • Wniosek: elementy jednolitego typu • indeksowanie: • x=array[6]; • tab[i]='Z'; • Uwaga: indeksowanie od 0 !
Tablice -c.d. • deklaracja tablicy wielowymiarowej:typidentyfikator [rozmiar1][rozmiar1]...; • np. int array[7][2]; char tab[256][10][100]; • inicjowanie • int arr[4] = {2,3,4,5}; • int arr[] = {2,3,4,5}; • float f[2][3]={{1,2,3}, {4,5,6} }; • Uwaga: najłatwiej przetwarzać pętlą for
Tablice i wskaźniki • wskaźnik to zmienna zawierająca adres innej zmiennej • postać deklaracji: typ * zmienna; • np. char * c; • korzyści z użycia wskaźników • bardziej zwarty i efektywny kod • czasami jedyny sposób implementacji pewnych algorytmów w języku C • możliwość dynamicznego tworzenia zmiennych (w trakcie pracy programu) • Uwaga: łatwo można napisać zupełnie niezrozumiały lub błędny kod gdy nie zachowuje sie ostrożności!
Tablice i wskaźniki -c.d. • pamięć komputera można przedstawić jako tablicę kolejno numerowanych (adresowanych) komórek pamięci • komórkami pamięci można manipulować indywidualnie lub całymi grupami • bajtowi odpowiada typ char • dwóm bajtom odpowiada typ short int • czterem bajtom odpowiada typ long int • wskaźnik jest grupą komórek, która może pomieścić adres • 2 bajty (komputery 16-bitowe) • 4 bajty (komputery 32-bitowe)
Tablice i wskaźniki -c.d. • operator adresowy (&) i wskaźnikowy (*) • & - referencja, * - dereferencja • przykład • int x=1, y=2, z[10]; • int *ip; • ip jest wskaźnikiem do obiektów typu int • ip=&x; • teraz ip wskazuje na x • y=*ip; • y ma teraz wartość 1 • *ip=0; • x ma teraz wartość 0 • ip=&z[0]; • teraz ip wskazuje na element z[0]
Tablice i wskaźniki -c.d. • równoważność tablic i wskaźników • przykład • int a[10]; • int *pa; pa=&a[0]; • x=*pa; x=a[0]; • pa=&a[0]; pa=a; • x=a[3]; x=pa[3]; • arytmetyka na adresach • adresy można inkrementować (++) i dekrementować (--) • pa+1 - wskazuje na następny obiekt • pa+i &a[i] • *(pa+i) a[i]
Specjalne typy wskaźnikowe • wskaźniki na znak (tablice znakowe) można inicjować poprzez stałe łańcuchowe • char str[ ] = "blah, blah, blah"; • nie można zmienić wartości str • char * ptr = " blah, blah, blah"; • można przypisać zmiennej ptr inne wskaźniki • wskaźnik na typ void może przechowywać wskaźniki na dowolny typ • void * v; char *p; int *q; ... v=p; ... v=q; ... • v nie może być użyty do adresowania pośredniego (wymaga rzutowania - cast) • p=(*char)v;
Funkcje w języku C • program w C jest "zbiorem funkcji" • musi zawierać przynajmniej jedna funkcję (main) • funkcja to podprogram realizujący określone zadanie mogący zwracać do miejsca wywołania wartość określonego typu • można stosować wielokrotnie • może przyjmować parametry • ukrywa szczegóły implementacji przed innymi częściami programu • można pisać funkcje w różnych plikach kompilowanych oddzielnie • można łączyć funkcje w biblioteki • Uwaga: raczej kilka małych niż jedna duża funkcja!
Funkcje w C - ograniczenia • funkcji nie można "zagnieżdżać" • cała funkcja musi być umieszczona w jednym pliku • funkcje zawsze przekazują parametry "przez wartość" • konieczne jest używanie wskaźników • używana funkcja musi być uprzednio zadeklarowana
Funkcje w C - c.d. • deklaracja:typ-wyniku nazwa (parametryopc); • definicja:typ-wyniku nazwa (parametryopc);{... instrukcje ...return wyrażenieopc;} • standaryzacja w ANSI C
Funkcje w C - c.d. • domyślny typ wyniku to int • gdy funkcja nie zwraca wartości stosuje się typ void • parametry mają postać:typ1 zmienna1[, typ2 zmienna2]... • w deklaracji mogą występować tylko nazwy typów • listę parametrów można pominąć w deklaracji - nie będą wtedy sprawdzane przez kompilator! • dla funkcji bez parametrów stosuje się zapis (void) jako listę parametrów
Funkcje w C - c.d. • zmienne globalne - zewnętrzne (extern) • deklaracja poza ciałem funkcji • dostępne z każdej funkcji • nie należy nadużywać - komplikuje to większe programy • inicjalizacja na 0 gdy brak przypisania • extern int x; • extern jest domyślne poza funkcją • zmienne statyczne (static) • przechowują wartość we wszystkich wywołaniach tej samej funkcji • static int x; • inicjalizacja na 0 gdy brak przypisania
Funkcje rekurencyjne w C • Funkcja może wywoływać samą siebie • bezpośrednio • pośrednio (również rekurencja wzajemna!) • konieczny jest mechanizm stosowy • każde wznowienie funkcji otrzymuje na stosie swój komplet wszystkich zmiennych automatycznych (niezależny od poprzedniego) • zalety rekurencji • bardziej zwarta postać • bardzo łatwo implementować struktury danych zdefiniowane w sposób rekurencyjny, np. drzewa • wady rekurencji • zwykle dłuższy czas działania • zwykle większe zużycie pamięci
Rekurencja - przykłady • potęga • xn=x * x *...* x (n razy) • x0=1 , xn+1=x * xn • silnia • n!=1*2*...*n • 0!=1, n!=(n-1)!*n • liczby Fibonacciego • realizacja iteracyjna • realizacja rekurencyjna • realizacja poprzez formułę Bineta
Rekurencja - przykłady c.d. • klasyczny problem "Wieże Hanoi" • szybkie sortowanie (QuickSort)
Struktury • struktura w C to obiekt złożony z jednej lub kilku zmiennych, być może różnych typów, zgrupowanych "dla wygody" pod jedną nazwą • ułatwiają zorganizowanie skomplikowanych danych • umożliwiają traktowanie związanych ze sobą danych jako jeden obiekt • przykład - pozycja listy płac • pracownik ma imię, nazwisko, adres, wynagrodzenie, itp. • adres to miejscowość, ulica, numer domu, itp. - elementem struktury może być inna struktura
Struktury - c.d. • standard ANSI C daje możliwość • przypisywania struktur • przypisywania wartości początkowych • przekazywania jako parametrów do funkcji • zwracania jako wartość funkcji • Uwaga: przekazywanie do funkcji przez wartość może być kosztowne - czasami lepiej użyć wskaźnika
Struktury - c.d. • definicja • structnazwaopc {typ1 składowa1;typ2 składowa2;...}zmienneopc; • nazwa jest etykietą - może być wykorzystana przy późniejszych deklaracjach • bez zmiennych mamy tylko opis kształtu struktury - nie jest rezerwowana żadna pamięć • odwołania • nazwa-struktury . składowa • wskaźnik-do-struktury -> składowa (np. p->s zamiast (*p).s) • inicjalizacja jak dla tablicy (poprzez stałe)
Struktury - przykłady • struct point { int x; int y;}; • struct point pt; • struct point maxpoint={640,480}; • struct point { int x; int y;} p,q,r; • struct rect {struct point pt1;struct point pt2;}; • struct rect r; • r.pt1.y=100;
Struktury - przykłady - c.d. • struct rect r, *rp = &r; • równoważne wyrażenia: • r.pt1.x • rp->pt1.x • (r.pt1).x • (rp->pt1).x • Uwaga: operatory strukturowe (.), (->), podobnie jak nawiasy otaczające parametry funkcji (()) i indeksowanie tablic ([ ]) znajdują się na szczycie hierarchii priorytetów - wiążą najmocniej
Deklaracja typedef • mechanizm typedef umożliwia tworzenie nowych nazw dla typów danych, np. • typedef int Length; • Length len, maxlen; • typedef char *String; • typ deklarowany w typedef pojawia się składniowo w miejscu zmiennej • konstruowanie struktur "rekurencyjnie" - np. drzew • typedef struct tnode *Treeptr;typedef struct tnode { char *word; int count; Treeptr left; Treeptr right;} Treenode;
Unie • unia w C to zmienna, która może zawierać obiekty różnych typów i rozmiarów • przykład definicji • union u_tag { int ival; floaf fval; char *sval;} u; • odwołania • nazwa-unii . składowa • wskaźnik-do-unii -> składowa
Unie - c.d. • kompilator "troszczy" się o zgodność położenia i pamięci • unia jest wystarczająco obszerna żeby pomieścić wartość największego z zadeklarowanych w niej typów • składnia zbliżona do struktury • unia de facto jest strukturą o składowych nie przesuniętych względem jej początku • inicjalizacja tylko wartością pierwszego typu • programista musi się troszczyć o to, aby pobierane dane były zgodne z typem ostatnio zapisanym
Unie - przykład unii w strukturze • struct{ char *name; int flags; int utype; union { int ival; float fval; char *sval; } u;} symtab[NSYM]; • odwołanie do składowej ival • symtab[i].u.ival • odwołanie do pierwszego znaku tekstu w sval • *symtab[i].u.sval • symtab[i].u.sval[0]
Pola bitowe • mogą reprezentować znaczniki jednobitowe • umożliwiają upakowanie wielu znaczników w jedno słowo maszyny (zależne od implementacji) • oszczędność • narzucone fomaty danych, np. łącza z urządzeniami zewnętrznymi mogą wymagać dostępu do kawałków słów