, funkcje i tablice Zak lad Chemii Teoretycznej UJ 20 listopada 2008
wielowymiarowe 1 2 3 4 wielowymiarowe, funkcje i tablice
Czym sa wskaźniki? Plan wielowymiarowe Zmienne wskaźnikowe wskazuja na inne zmienne (obiekty) wartościa zmiennej wskaźnikowej(wskaźnika) jest adres obszaru pamieci zajmowanego przez jakaś zmienna (obiekt) wskaźnik należy do konkretnego typu (typu wskazywanego obiektu) wartościa wskaźnika może być adres pusty, funkcje i tablice
wielowymiarowe Definicja zmiennej wskaźnikowej i n t * i p ; // i p j e s t w skaznikiem na zmienna typu i n t double *ap, *bp, *cp ; // w s k a z n i k i na zmienne typu d o u b l e unsigned *a, b, c ; // b i c to zmienne typu unsigned, n i e w s k a z n i k i!, funkcje i tablice
wielowymiarowe Operator adresu & Zastosowany do zmiennej (obiektu) zwraca jej (jego) adres i n t i = 1 0 2 4 ; i n t *wi = &i ; // wi w s k a z u j e t e r a z na zmienna i i n t *wi2 = wi ; // wi2 r o w n i e z i n t *wi3 = &wi ; // b l e d n e i n t **wi3 = &wi ; // poprawne, wi3 to wskaznik do wskaznika do zmiennej typu i n t i n t *wi4 = i ; // pod a d r e s n i e mozna p r z y p i s a c po p r o s t u w a r t o s c i typu i n t, funkcje i tablice
wielowymiarowe Operator wy luskania (adresowania pośredniego) Zastosowany do wskaźnika zwraca zawartość zmiennej (obiektu) wskazywanego przez ten wskaźnik i n t i = 1 0 2 4 ; i n t *wi = &i ; i n t k = *wi ; // k ma t e r a z t a sama w a r t o s c co i /* k i l k a o p e r a c j i na z m i e n n e j wskazywanej p r z e z wi */ *wi = k + 1 ; *wi = abs (* wi ) ; *wi = *wi + 1 ; *wi = *wi + 2 ; // z w i e k s z a w a r t o s c z m i e n n e j wskazywanej p r z e z wi wi = wi + 2 ; // z w i e k s z a w a r t o s c w s k a z n i k a ( a d r e s u ), funkcje i tablice
void* Plan wielowymiarowe Wskaznik do typu void: może przechowywać adres zmiennej dowolnego typu nie można go stosować do adresowania pośredniego konwersja z(do) wskaźników innego typu jest automatyczna i n t i = 1 0 2 4 ; v o i d *wv = &i ; // poprawne, konwersja do void* i n t * i p ; double * jp ; ip = wv ; // poprawne, konwersja z void* jp = ip ; // blad, wskazniki roznych typow jp = ( double *) ip ; // poprawne ( jawna konwersja ), funkcje i tablice
wielowymiarowe Arytmetyka dla wskaźników i liczby ca lkowite nie moga być stosowane zamiennie double *a ; i n t i = 1 0 2 4 ; a = i ; // b l a d a = 0 ; // poprawne : wyjatek, 0 r e p r e z e n t u j e p u s t y a d r e s a = NULL ; // poprawne : j a k wyzej a = a + 1 ; /* adres zwiekszony o l i c z b e bajtow zajmowanych p r z e z j e d n a l i c z b e typu d o u b l e */ a = a 10; /* adres zmniejszony o l i c z b e bajtow zajmowanych p r z e z d z i e s i e c l i c z b typu d o u b l e */ double j = *a++; /* pod j podstaw w a r t o s c z m i e n n e j wskazywanej p r z e z a i z w i e k s z w s k a z n i k o 1 */, funkcje i tablice
wielowymiarowe Sta le wskaźniki i wskaźniki do sta lych i n t i ; c o n s t i n t k = 2 ; i n t * c o n s t wi = &i ; /* wi to s t a l y w s k a z n i k do z m i e n n e j typu i n t j e g o w a r t o s c ( przechowywany a d r e s ) n i e moze u l e c zmianie, c z y l i zawsze bedzie wskazywal na zmienna i */ c o n s t i n t *wi2 = &i ; /* wi2 to w s k a z n i k do s t a l e j typu i n t */ c o n s t i n t *wi3 = &k ; /* wi3 to t e z w s k a z n i k do s t a l e j typu i n t, co prawda k n i e j e s t s t a l a, a l e n i e mozna zmienic wartosci k za pomoca tego wskaznika, kazda zmienna na jaka wskazuje t a k i wskaznik j e s t dla niego s t a l a */ c o n s t i n t * c o n s t wi4 = &k ; /* s t a l y w s k a z n i k do s t a l e j typu i n t */, funkcje i tablice
wielowymiarowe Podzia l programu na funkcje Każdy program w C zawiera przynajmniej jedna funkcje, która jest funkcja main. Po co w ogóle wydzielać inne fragmenty jako funkcje? przejrzystość, jeśli pewien ciag operacji tworzy logiczna ca lość, wyodrebnienie go jako funkcji u latwia zrozumienie treści programu i poprawia jego strukture wygoda, jeśli pewien ciag operacji jest powtarzany wielokrotnie na różniacych sie od siebie wartościami argumentach, wyodrebnienie go w postaci funkcji pozwala uniknać powtarzania prawie identycznego kodu przenośność i możliwość wielokrotnego wykorzystania, funkcje można skompilować do osobnych plików (czy stworzyć biblioteki) i do l aczać do tworzonych programów w razie potrzeby, funkcje i tablice
wielowymiarowe Definicja funkcji /* t y p z w r a c a n e j w a r t o s c i nazwa ( l i s t a d e k l a r a c j i a r g u m e n t o w ) {......... */ i n t mojabs ( i n t a ) { r e t u r n ( a < 0? a : a ) ;, funkcje i tablice
wielowymiarowe Deklaracje funkcji Użycie funkcji wymaga jej wcześniejszego zadeklarowania. Deklaracj e stanowi również sama definicja funkcji. // w e r s j a p i e r w s z a #i n c l u d e <s t d i o. h> i n t min ( i n t a, i n t b ) { // d e f i n i c j a p e l n i r o l e d e k l a r a c j i r e t u r n ( a < b? a : b ) ; i n t main ( ) { i n t x = 2, y = 4 ; p r i n t f ( %d, min ( x, y ) ) ; r e t u r n 0 ;, funkcje i tablice
wielowymiarowe Deklaracje funkcji II /* d e k l a r a c j a : t y p z w r a c a n e j w a r t o s c i n a z w a f u n k c j i ( l i s t a t y p o w a r g u m e n t o w z o p c j o n a l n y m i n a z w a m i ) */ // w e r s j a druga #i n c l u d e <s t d i o. h> i n t min ( i n t, i n t ) ; // d e k l a r a c j a i n t main ( ) { i n t x = 2, y = 4 ; p r i n t f ( %d, min ( x, y ) ) ; r e t u r n 0 ; i n t min ( i n t a, i n t b ) { r e t u r n ( a < b? a : b ) ;, funkcje i tablice
wielowymiarowe Specjalne deklaracje /* funkcja o konkretnej, a l e nieznanej w momencie deklarowania l i c z b i e i t y p i e argumentow */ i n t f o o ( ) ; /* f u n k c j a o z e r o w e j l i c z b i e argumentow */ i n t f o o ( v o i d ) ; /* p i e r w s z y argument f u n k c j i j e s t typu c h a r *, moga t e z p o j a w i c s i e i n n e argumenty o nieznanym a p r i o r i t y p i e i l i c z b i e */ i n t p r i n t f ( char *,... ) ; Standardy wcześniejsze niz C99 dopuszczaja domyślna deklaracje. /* min nie zadeklarowane, domyslna d e k l a r a c j a ma p o s t a c i n t min ( ) ; */ i n t main ( ) { i n t x = 2, y = 4 ; p r i n t f ( %d, min ( x, y ) ) ; r e t u r n 0 ;, funkcje i tablice
wielowymiarowe Deklarowanie funkcji jako inline Deklarowanie funkcji jako inline jest sugestia dla kompilatora, żeby zastapi l w kodzie wywo lania funkcji jej rozwiniet a treścia. #i n c l u d e <s t d i o. h> i n l i n e i n t min ( i n t, i n t ) ; // d e k l a r a c j a f u n k c j i typu i n l i n e i n t main ( ) { i n t x = 2, y = 4 ; p r i n t f ( %d, min ( x, y ) ) ; r e t u r n 0 ; i n t min ( i n t a, i n t b ) { r e t u r n ( a < b? a : b ) ; /* Funkcja main po r o z w i n i e c i u */ i n t main ( ) { i n t x = 2, y = 4 ; p r i n t f ( %d, ( x < y? x : y ) ) ; r e t u r n 0 ;, funkcje i tablice
wielowymiarowe Przekazywanie argumentów do funkcji Argumenty sa przekazywane do funkcji zawsze przez wartość. Oznacza to, że w momencie wywo lania tworzone sa lokalne kopie przekazanych zmiennych(obiektów), które sa używane wewnatrz funkcji. v o i d swap ( i n t a, i n t b ) { i n t tmp = a ; a = b ; b = tmp ; v o i d s w a p c o r r e c t e d ( i n t *a, i n t *b ) { i n t tmp = *a ; *a = *b ; *b = tmp ; i n t main ( ) { i n t x = 2, y = 4 ; swap ( x, y ) ; p r i n t f ( %d %d, x, y ) ; // w y p i s z e : 2 4 swap corrected (&x, &y ) ; p r i n t f ( %d %d, x, y ) ; // w y p i s z e : 4 2 r e t u r n 0 ;, funkcje i tablice
wielowymiarowe Użycie zmiennych zewn etrznych w celu przekazania argumentów Pewnym sposobem przekazania argumentów do funkcji jest użycie zmiennych zewn etrznych. i n t x = 2, y = 4 ; v o i d swap ( ) { i n t tmp = x ; x = y ; y = tmp ; i n t main ( ) { swap ( ) ; r e t u r n 0 ; Stanowi to zazwyczaj również świetny sposób na uczynienie kodu mniej odpornym na b l edy., funkcje i tablice
wielowymiarowe Wejście i wyjście z funkcji Wejście do funkcji nastepuje w chwili napotkania instrukcji nazwa funkcji(lista argumentów). Wyjście z funkcji nastepuje w momencie napotkania instrukcji return wyrazenie; badź nawiasu klamrowego ja kończacego. Funkcja zadeklarowana jako zwracajaca wartość powinna we wszystkich punktach wyjścia być zaopatrzona w instrukcje return wyrazenie; (wymóg od standardu C99). double min ( double a, double b ) { r e t u r n ( a < b? a : b ) ; double min ( double a, double b ) { i f ( a < b ) r e t u r n a ; e l s e r e t u r n b ; v o i d swap ( double *a, double *b ) { i n t tmp = *a ; *a = *b ; *b = tmp ; r e t u r n 0 ; // b l a d, funkcje i tablice
Rekurencja Plan wielowymiarowe Funkcja rekurencyjna, to taka, która bezpośrednio lub pośrednio wywo luje sama siebie. // n! unsigned l o n g s i l n i a ( i n t n ) { i f ( n > 1) r e t u r n n * s i l n i a ( n 1 ) ; r e t u r n n ; // n a j w i e k s z y wspolny d z i e l n i k i n t nwd ( i n t m, i n t n ) { i f (! n ) r e t u r n n ; r e t u r n nwd ( n, m % n ) ; Rekurencyjnie czy iteracyjnie? krótszy i prostszy kod zazwyczaj mniej efektywne wykonanie, funkcje i tablice
Typ tablicowy Plan wielowymiarowe Tablica Zajmujacy spójny obszar w pamieci zestaw zmiennych (obiektów) tego samego typu. Poszczególne zmienne(obiekty) nie maja nazw a dostep do nich jest możliwy przez indeks. Pierwszy element tablicy ma indeks równy zeru. i n t i ; // p o j e d y n c z a zmienna typu i n t i n t t i [ 1 0 ] ; // d z i e s i e c i o e l e m e n t o w a t a b l i c a zmiennych typu i n t i = t i [ 2 ] ; // i ma t e r a z w a r t o s c t r z e c i e g o elementu t a b l i c y t i [ 7 ] = i ; // zmodyfikowany osmy e l e m e n t, funkcje i tablice
wielowymiarowe Definicja tablicy specyfikator typu nazwa[rozmiar] Rozmiar powinien być wyrażeniem sta lym typu ca lkowitego (z zastrzeżeniem, że standard C99 wprowadza tablice o dynamicznie ustalanym rozmiarze). Definicja tablicy może zawierać jej inicjalizacj e. Rozmiar w pewnych sytuacjach nie musi być podawany, kompilator odgaduje go na podstawie dokonanej inicjalizacji. i n t t i [ 1 0 ] ; //10 elementowa t a b l i c a c o n s t i n t s i z e = 3 ; i n t wi [ s i z e ] = {0, 1, 2 ; /* z a i n i c j a l i z o w a n a : wi [ 0 ] = 0, wi [ 1 ] = 1, wi [ 2 ] = 2 */ i n t x i [ ] = {0, 1, 2 ; /* z a i n i c j a l i z o w a n a, a r o z m i a r u s t a l o n y na 3 */ c o n s t i n t s i z e 2 = 5 ; i n t y i [ s i z e 2 ] = {0, 1, 2 ; /* z a i n i c j a l i z o w a n a : wi [ 0 ] = 0, wi [ 1 ] = 1, wi [ 2 ] = 2, p o z o s t a l y m elementom p r z y p i s a n e 0 */, funkcje i tablice
wielowymiarowe o dynamicznym rozmiarze - C99 i n t n ; s c a n f ( %d, &n ) ; double a [ n ] ; /* poprawne w C99, n i e d o z w o l o n e w s t a r s z y m s t a n d a r d z i e */, funkcje i tablice
wielowymiarowe znakowe char t z 1 [ ] = { C, D, a ; // r o z m i a r u s t a l o n y na 3 char tz2 [ ] = CDa ; /* rozmiar ustalony na 4, bo kazdy n a p i s z a w i e r a na koncu znak p u s t y \ 0 */ char tz3 [ 3 ] = CDa ; /* poprawne w C, wymuszony rozmiar 3, znak pusty z ko niec zn osc i zignorowany */, funkcje i tablice
Ograniczenia Plan wielowymiarowe nie można dokonać przypisania tablicy jako ca lości c o n s t s i z e = 3 ; i n t t i [ s i z e ] = { 0, 1, 2 ; i n t t i 2 [ s i z e ] = t i ; // b l a d /* poprawne r o z w i a z a n i e wymaga p e t l i */ i n t t i 2 [ s i z e ] ; f o r ( i n t i = 0 ; i < s i z e ; ++i ) t i 2 [ i ] = t i [ i ] ; tablica nie pami eta swojego rozmiaru wyjście z indeksem poza obszar tablicy nie jest wykrywane przez kompilator, funkcje i tablice
sizeof Plan wielowymiarowe operator jednoargumentowy sk ladnia: sizeof (nazwa typu) sizeof (obiekt) sizeof obiekt zwraca wartość typu ca lkowitego bez znaku odpowiadajac a rozmiarowi obiektu (zmiennej danego typu) wyliczany na etapie kompilacji, wyjatek stanowi użycie do tablic o dynamicznym rozmiarze (C99), funkcje i tablice
wielowymiarowe Jeszcze o sizeof i n t a ; double b [ 3 ] ; s i z e o f ( f l o a t ) ; s i z e o f a ; s i z e o f ( b ) ; // r o z m i a r t a b l i c y (w b a j t a c h, n i e w l i c z b i e elementow ) s i z e o f ( b [ 0 ] ) ; // r o z m i a r elementu i n t n o e l e m e n t s = s i z e o f ( b ) / s i z e o f ( b [ 0 ] ) ; size t: typ danych definiowany w bibliotece standardowej, tak aby odpowiada l typowi zwracanemu przez operator sizeof, funkcje i tablice
wielowymiarowe Co kryje sie pod nazwa tablicy char buf [ 8 ] = abcdefg ; char var ; /* buf j e s t nazwa t a b l i c y i r o w n o c z e s n i e s t a l y m wskaznikiem do pierwszego j e j elementu ; buf == &buf [ 0 ] */ /* buf [ 0 ] == * buf == a */ v a r = buf [ 1 ] ; v a r = *( buf + 1 ) ; // t e i n s t r u k c j e d a j a i d e n t y c z n y e f e k t f o r ( i n t i x = 0 ; i x < 8 ; ++i x ) i f ( buf [ i x ]!= *( buf + i x ) ) p r i n t f ( Houston, mamy problem \n ) ; char * c o n s t wbuf = buf ; // po obu s t r o n a c h w s k a z n i k tego samego typu char *wbuf 2 = buf ; // automatyczna k o n w e r s j a c h a r * c o n s t do c h a r * /* n o t a c j a t a b l i c a [ i n d e k s ] j e s t rownowazna n o t a c j i *( w s k a z n i k + o f f s e t ) */, funkcje i tablice
wielowymiarowe jako argumenty funkcji #i n c l u d e <s t d i o. h> v o i d p r i n t i n t t a b l e ( i n t c [ ], i n t n ) { f o r ( i n t i = 0 ; i < n ; ++i ) p r i n t f ( %d\n, c [ i ] ) ; /* rownowazne znaczeniowo : v o i d p r i n t i n t t a b l e ( i n t c [ 5 ], i n t n ) v o i d p r i n t i n t t a b l e ( i n t c [ 2 ], i n t n ) v o i d p r i n t i n t t a b l e ( i n t *c, i n t n ) */ i n t main ( ) { i n t a [ 5 ] = {2, 3, 5, 9, 1 1 ; p r i n t i n t t a b l e ( a, 3 ) ; // wydrukuj p i e r w s z e 3 e l e m e n t y t a b l i c y a r e t u r n 0 ;, funkcje i tablice
wielowymiarowe Jeszcze jedna funkcja operujaca na tablicach(wskaźnikach) #i n c l u d e <s t d i o. h> i n t s t r l e n ( char s [ ] ) { /* argumentem j e s t t a b l i c a znakow, a tak naprawde wskaznik typu char *, w momencie wywolania tworzona j e s t prywatna kopia przekazanego wskaznika */ i n t n ; f o r ( n = 0 ; * s!= \0 ; ++s ) n++; r e t u r n n ; i n t main ( ) { char a [ ] = Napis ; p r i n t f ( Dlugosc n a p i s u wynosi %d\n, s t r l e n ( a ) ) ; /* wywolana z argumentem bedacym nazwa t a b l i c y, c z y l i wskaznikiem typu c h a r * c o n s t */ p r i n t f ( Dlugosc n a p i s u wynosi %d\n, s t r l e n ( Napis ) ) ; /* wywolana z argumentem bedacym w skaznikiem typu c o n s t c h a r * */ r e t u r n 0 ;, funkcje i tablice
wielowymiarowe Czym sa tablice wielowymiarowe? i n t t i [ 3 ] [ 2 ] ; /* t a b l i c a dwuwymiarowa o r o z m i a r a c h 3( w i e r s z e ) i 2( kolumny ), a t ak naprawde to t a b l i c a jednowymiarowa o r o z m i a r z e 3, k t o r e j elementami sa t a b l i c e o r o z m i a r z e 2 */ t i [ 2 ] [ 1 ] = 0 ; /* p r z y p i s u j e 0 do elementu w t r z e c i m w i e r s z u i d r u g i e j kolumnie */ i n t i = t i [ 0 ] [ 0 ] ; /* p r z y p i s u j e z m i e n n e j i w a r t o s c elementu z p i e r w s z e g o w i e r s z a i p i e r w s z e j kolumny */ /* Z tego, ze to t a b l i c e t a b l i c wynika, ze e l e m e n t y sa przechowywane w i e r s z a m i. Kolejnosc w pamieci bedzie nastepujaca : t i [ 0 ] [ 0 ], t i [ 0 ] [ 1 ], t i [ 1 ] [ 0 ], t i [ 1 ] [ 1 ], t i [ 2 ] [ 0 ], t i [ 2 ] [ 1 ] */, funkcje i tablice
wielowymiarowe Definicje tablic wielowymiarowych i n t t i [ 3 ] [ 2 ] = {0, 1, 2, 3, 4, 5 ; /* t i [ 0 ] [ 0 ] = 0, t i [ 0 ] [ 1 ] = 1, t i [ 1 ] [ 0 ] = 2, t i [ 1 ] [ 1 ] = 3, t i [ 2 ] [ 0 ] = 4, t i [ 2 ] [ 1 ] = 5 */ i n t t i [ 3 ] [ 2 ] = {{0, 1, {2, 3, {4, 5 ; /* I d e n t y c z n y e f e k t j a k w yzej */ i n t t i [ 3 ] [ 2 ] = {0, 2, 4 ; /* t i [ 0 ] [ 0 ] = 0, t i [ 0 ] [ 1 ] = 2, t i [ 1 ] [ 0 ] = 4, r e s z t a z a i n i c j a l i z o w a n a na 0 */ i n t t i [ 3 ] [ 2 ] = {{0, {2, { 4 ; /* t i [ 0 ] [ 0 ] = 0, t i [ 1 ] [ 0 ] = 2, t i [ 2 ] [ 0 ] = 4, r e s z t a z a i n i c j a l i z o w a n a na 0 */, funkcje i tablice
wielowymiarowe wielowymiarowe jako argumenty funkcji #i n c l u d e <s t d i o. h> v o i d p r i n t m u l t i a r r a y ( i n t c [ ] [ 2 ], i n t m, i n t n ) { /* w y p i s u j e e l e m e n t y z b l o k u m x n p r z e k a z a n e j t a b l i c y o 2 kolumnach */ f o r ( i n t i = 0 ; i < m; i ++) f o r ( i n t j = 0 ; j < n ; j ++) p r i n t f ( %d\n, c [ i ] [ j ] ) ; /* rownowazne znaczeniowo : v o i d p r i n t m u l t i a r r a y ( i n t c [ 1 2 ] [ 2 ], i n t m, i n t n ) v o i d p r i n t m u l t i a r r a y ( i n t (* c ) [ 2 ], i n t m, i n t n ) */ i n t main ( ) { i n t t i [ 3 ] [ 2 ] = {0, 1, 2, 3, 4, 5 ; p r i n t m u l t i a r r a y ( t i, 2, 2 ) ; /* w y p i s z e e l e m e n t y z b l o k u 2 x 2 t a b l i c y t i */ r e t u r n 0 ;, funkcje i tablice
wielowymiarowe wielowymiarowe jako argumenty funkcji II #i n c l u d e <s t d i o. h> v o i d p r i n t m u l t i a r r a y ( i n t *c, i n t np, i n t m, i n t n ) { /* w y p i s u j e e l e m e n t y z b l o k u m x n p r z e k a z a n e j t a b l i c y o np kolumnach */ f o r ( i n t i = 0 ; i < m; i ++) f o r ( i n t j = 0 ; j < n ; j ++) p r i n t f ( %d\n, *( c + i * np + j ) ) ; i n t main ( ) { i n t t i [ 3 ] [ 2 ] = {0, 1, 2, 3, 4, 5 ; p r i n t m u l t i a r r a y (& t i [ 0 ] [ 0 ], 2, 2, 2 ) ; /* w y p i s z e e l e m e n t y z b l o k u 2 x 2 t a b l i c y t i */ r e t u r n 0 ;, funkcje i tablice