Zak lad Chemii Teoretycznej UJ 26 listopada 2007
wielowymiarowe 1 2 wielowymiarowe 3
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
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 ; /* to n i e j e s t w y r a z e n i e s t a l e, a l e z o s t a n i e z a a k c e p t o wane przez wiekszosc kompilatorow, 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 */
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 */
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 k oni ec zno s ci zignorowany */
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
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)
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
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 t e g o 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 ) */
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 ;
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 wskaznikiem typu c o n s t c h a r * */ r e t u r n 0 ;
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 tak 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 k olumnie */ 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 ] */
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 */
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 ;
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 ;
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
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 ) ;
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 ;
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 ) ;
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 ;
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 ;
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 ;
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.
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
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