Wykład 11.
Transkrypt
Wykład 11.
Tablice i wskaźniki Elwira Wachowicz [email protected] 29 maja 2013 Elwira Wachowicz ([email protected]) Tablice i wskaźniki 29 maja 2013 1 / 12 /* binar.c -- wyświetla liczbę w systemie dwójkowym */ #include <stdio.h> void do_binar(int); int main(void) { int liczba; printf("podaj liczbę całkowitą (q kończy program): \n"); while ( scanf("%d", &liczba) == 1 ) { printf("W systemie dwójkowym: "); do_binar(liczba); putchar(’\n’); printf("podaj liczbę całkowitą (q kończy program): \n"); } return 0; } void do_binar(int n) { int r; /* funkcja rekurencyjna */ r = n % 2; if ( n >= 2) do_binar( n / 2 ); putchar(’0’ + r); return; } Elwira Wachowicz ([email protected]) Tablice i wskaźniki podaj liczbę całkowitą (q kończy program): 9 W systemie dwójkowym: 1001 podaj liczbę całkowitą (q kończy program): 255 W systemie dwójkowym: 11111111 podaj liczbę całkowitą (q kończy program): 1024 W systemie dwójkowym: 10000000000 podaj liczbę całkowitą (q kończy program): q 29 maja 2013 2 / 12 Tablice Tablica: ciąg wartości tego samego typu (np. dziesięciu znaków lub piętnastu liczb typu int) przechowywanych obok siebie. Cała tablica nosi jedną nazwę, a dostęp do poszczególnych elementów uzyskujemy przez podanie indeksu, który zawsze jest liczbą naturalną. float dlugi[20] – 20-elementowa tablica o nazwie dlugi dlugi[0] – wartość pierwszego elementu tablicy dlugi ... dlugi[19] – wartość dwudziestego elementu tablicy dlugi Przypisywanie wartości: dlugi[5] = 32.54; dlugi[6] = 1.2e+21; int nianie[22]; char aktorzy[26]; long duzy[500]; /* tablica z 22. liczbami typu int */ /* tablica przechowująca 26 znaków */ /* tablica z 500. liczbami typu long int */ Elwira Wachowicz ([email protected]) Tablice i wskaźniki 29 maja 2013 3 / 12 /* wyniki.c -- wykorzystuje pętle do przetwarzania tablicy */ #include <stdio.h> #define ROZMIAR 10 #define PAR 72 int main(void) { int index, wynik[ROZMIAR]; int suma = 0; float srednia; printf("Podaj %d wyników gry w golfa:\n", ROZMIAR); for (index = 0; index < ROZMIAR; index++) scanf("%d", &wynik[index]); /* wczytanie 10 wyników */ printf("Odczytane wyniki to:\n"); for (index = 0; index < ROZMIAR; index++) printf("%5d", wynik[index]); /* wyświetlenie wczytanych wyników */ printf("\n"); for (index = 0; index < ROZMIAR; index++) suma += wynik[index]; /* i ich zsumowanie */ srednia = (float) suma / ROZMIAR; printf("Suma wyników = %d, średnia = %.2f.\n", suma, srednia); printf("Oznacza to handicap w wysokości %.0f.\n", srednia - PAR); } Podaj 10 wyników gry w golfa: 102 98 112 108 105 103 99 101 96 102 100 Odczytane wyniki to: 102 98 112 108 105 103 99 101 Suma wyników = 1026, średnia = 102.60. Oznacza to handicap w wysokości 31. Elwira Wachowicz ([email protected]) 96 102 Tablice i wskaźniki 29 maja 2013 4 / 12 Zmienne lub tablice automatyczne Zmienna lub tablica automatyczna: to zmienna lub tablica zadeklarowana wewnątrz funkcji. Zmienna zadeklarowana wewnątrz istnieje tylko w czasie działania funkcji – po zakończeniu działania funkcji pamięć przeznaczona na zmienną jest zwalniana. int main(void) { int potegi[8] = {1, 2, 4, 8, 16, 32, 64, 128}; ... } Elwira Wachowicz ([email protected]) Tablice i wskaźniki 29 maja 2013 5 / 12 Zmienne i tablice zewnętrzne Zmienna lub tablica zewnętrzna: to zmienna lub tablica zadeklarowana poza jakąkolwiek funkcją. Są znane wszystkim funkcjom, które występują po ich deklaracji w pliku źródłowym. Istnieją przez cały czas działania programu. Są standardowo inicjalizowane i przyjmują wartość 0. int raport; int wilki[5] = {12, 10, 8, 9, 6}; int jedzenie(int); int main(void) { ... } int jedzenie(int n) { ... } Wachowicz ([email protected]) Elwira Tablice i wskaźniki 29 maja 2013 6 / 12 Zmienne i tablice statyczne Zmienne i tablice statyczne: definiuje się wewnątrz funkcji korzystając ze słowa kluczowego static. Są lokalne wewnątrz funkcji, ale zachowują swoje wartości między wywołaniami funkcji i otrzymują wartość początkową 0. int konto(intn, int m) { static int fasola[2] = {343, 332}; ... } Elwira Wachowicz ([email protected]) Tablice i wskaźniki 29 maja 2013 7 / 12 /* brak_dan.c -- niezainicjalizowane tablice */ #include <stdio.h> #define ROZMIAR 4 int zewntab[ROZMIAR]; /* niezainicjalizowana tablica zewnętrzna */ int main(void) { static int statab[ROZMIAR]; /* niezainicjalizowana tablica statyczna */ int autab[ROZMIAR]; /* niezainicjalizowana tablica automatyczna */ int i; printf("%2s%10s%10s%10s\n", "i","zewntab","statab","autab"); for (i = 0; i < ROZMIAR; i++) printf("%2d%10d%10d%10d\n", i, zewntab[i], statab[i], autab[i]); return 0; } i 0 1 2 3 zewntab 0 0 0 0 statab 0 0 0 0 autab 0 0 4195344 0 Elwira Wachowicz ([email protected]) Tablice i wskaźniki 29 maja 2013 8 / 12 /* troche_dan.c -- częściowo zainicjalizowane tablice */ #include <stdio.h> #define ROZMIAR 4 int zewntab[ROZMIAR] = {1956, 1966}; int main(void) { static int statab[ROZMIAR] = {-50, -90}; int autab[ROZMIAR] = {492, 567}; int i; printf("%2s%10s%10s%10s\n", "i","zewntab","statab","autab"); for (i = 0; i < ROZMIAR; i++) printf("%2d%10d%10d%10d\n", i, zewntab[i], statab[i], autab[i]); return 0; } i 0 1 2 3 zewntab 1956 1966 0 0 statab -50 -90 0 0 Elwira Wachowicz ([email protected]) autab 492 567 0 0 Tablice i wskaźniki 29 maja 2013 9 / 12 Przypisywanie wartości do tablic Przypisywanie wartości następuje element po elemencie! /* nieprawidlowe przypisania */ #define ROZMIAR 5 int main(void) { int byki[ROZMIAR] = {5, 3, 2, 8}; int jaki[ROZMIAR]; /* w porządku jaki = byki; jaki[ROZMIAR] = byki[ROZMIAR]; jaki[ROZMIAR] = {5, 3, 2, 8}; */ /* niedozwolone /* nieprawidlowa /* niedopuszczalna */ */ */ } Elwira Wachowicz ([email protected]) Tablice i wskaźniki 29 maja 2013 10 / 12 Wskaźniki Wskaźnik: zmienna, której wartość jest adresem w pamięci. wsk = &ach; /* przypisuje zmiennej wsk adrese zmiennej ach */ Mówimy: wsk wskazuje na ach Elwira Wachowicz ([email protected]) Tablice i wskaźniki 29 maja 2013 11 / 12 Operator dereferencji (pośredniości): * wsk = &ach; wart = *wsk; /* przypisuje zmiennej wsk adrese zmiennej ach */ /* znajduje wartość, na którą wskazuje wsk */ Powyższe dwie instrukcje są równoważne: wart = ach; Elwira Wachowicz ([email protected]) Tablice i wskaźniki 29 maja 2013 12 / 12 Deklarowanie wskaźników Prawidłowa deklaracja wskaźnika: int * pi; char * pc; float * pf, * pq; /* pi jest wskaźnikiem do zmiennej całkowitej */ /* pc jest wskaźnikiem do zmiennej znakowej */ /* pf i pg są wskaźnikami do zmiennej typu float */ Elwira Wachowicz ([email protected]) Tablice i wskaźniki 29 maja 2013 13 / 12 /* zamien.c -- zamiana z wykorzystaniem wskaźników #include <stdio.h> void zamiana(int * u, int * v); int main(void) { int x = 5, y = 10; */ printf("Początkowo x = %d, a y = %d.\n", x, y); zamiana(&x, &y); /* wysyłanie adresów do funkcji */ printf("A teraz x = %d, a y = %d.\n", x, y); return 0; } void zamiana(int * u, int * v) { int temp; temp = *u; *u = *v; *v = temp; /* temp otrzymuje wartość, na którą wskazuje u */ } Dostajemy: Początkowo x = 5, a y = 10. A teraz x = 10, a y = 5. Elwira Wachowicz ([email protected]) Tablice i wskaźniki 29 maja 2013 14 / 12 Operatory związane ze wskaźnikami – podsumowanie Operator adresu &: pozwala uzyskać adres zmiennej, której nazwa po nim występuje. Przykład: &siostra jest adresem zmiennej siostra. Operator deferencji *: zwraca wartość przechowywaną pod adresem wskazanym przez zmienną wskaźnikową. Przykład: siostra = 22; wsk = &siostra; wart = * wsk; Elwira Wachowicz ([email protected]) Tablice i wskaźniki 29 maja 2013 15 / 12 /* wsk_dod.c -- dodawanie do wskaźników #include <stdio.h> #define ROZMIAR 4 int main(void) { short daty[ROZMIAR], * ptc, index; double oplaty[ROZMIAR], * ptz; */ ptc = daty; /* przypisuje adres tablicy wskaźnikowej ptz = oplaty; printf("%25s %10s\n", "short", "double"); for (index = 0; index < ROZMIAR; index++) printf("wskaźniki + %d: %10p %10p\n", index, ptc + index, ptz + index); return 0; */ } Dostajemy: wskaźniki wskaźniki wskaźniki wskaźniki + + + + 0: 1: 2: 3: short 0x7fff1f922f40 0x7fff1f922f42 0x7fff1f922f44 0x7fff1f922f46 Elwira Wachowicz ([email protected]) double 0x7fff1f922f20 0x7fff1f922f28 0x7fff1f922f30 0x7fff1f922f38 Tablice i wskaźniki 29 maja 2013 16 / 12 wskaźniki wskaźniki wskaźniki wskaźniki + + + + 0: 1: 2: 3: short 0x7fff1f922f40 0x7fff1f922f42 0x7fff1f922f44 0x7fff1f922f46 Elwira Wachowicz ([email protected]) double 0x7fff1f922f20 0x7fff1f922f28 0x7fff1f922f30 0x7fff1f922f38 Tablice i wskaźniki 29 maja 2013 17 / 12 Wskaźniki do tablic Nazwa tablicy jest zarazem adresem jej pierwszego elementu: domek == &domek[0] Wartością wskaźnika jest adres wskazywanego elementu – sposób reprezentacji zależy od platformy sprzętowej. PC: adresowanie bajtowe. Adres dużego obiektu, to adres pierwszego bajtu. Zastosowanie do wskaźnika operatora *, daje wartość wskazywanego obiektu. Dodanie 1 do wskaźnika zwiększa jego wartość o rozmiar (w bajtach) wskazywanego obiektu. daty + 2 == &daty[2] *(daty + 2) == daty[2] *daty + 2 /* ten sam adres */ /* ta sama wartość */ /* 2 dodane do wartości 1. elementu */ Elwira Wachowicz ([email protected]) Tablice i wskaźniki 29 maja 2013 18 / 12 /* dni_m.c -- wykorzystuje zapis wskaźnikowy */ #include <stdio.h> #define MIESIACE 12 int main(void) { int dni[MIESIACE] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int index; for (index = 0; index < MIESIACE; index++) printf("Miesiąc %d ma %d dni.\n", index + 1, *(dni + index)); // równoważne dni(index) return 0; } Elwira Wachowicz ([email protected]) Tablice i wskaźniki 29 maja 2013 19 / 12 Tablice wielowymiarowe int M[4][5] – dwuwymiarowa macierz zmiennych całkowitych o 4 wierszach i 5 kolumnach. Inicjalizacja tablicy dwuwymiarowej: int M[4][5] = { {10, 5, -3, 17, 82}, { 9, 0, 0, 8, -7}, {32, 20, 1, 0, 14}, { 0, 0, 8, 7, 6} }; int M[4][5] = { 10, 20, 5, -3, 17, 82, 1, 0, 14, 0, 9, 0, 0, 8, 0, 7, 8, -7, 6}; 32, int macierz[4][3] = { [0][0] = 1, [1][1] = 5, [2][2] = 9}; Macierz trójwymiarowa: int pudelko[10][20][30]; Elwira Wachowicz ([email protected]) Tablice i wskaźniki 29 maja 2013 20 / 12 /* podwtab.c -- podwaja elementy tablicy #include <stdio.h> void podwoj(int tab[], int rozmiar); int main(void) { int smieci[3][4] = { {2, 4, 5, 8}, {3, 5, 6, 9}, {12, 10, 8, 6} }; int i, j; \begin{columns} */ for(i = 0; i < 3; i++) podwoj(smieci[i], 4); 4 6 24 for(i = 0; i < 3; i++) { for(j = 0; j < 4; j++) printf("%5d", smieci[i][j]); putchar(’\n’); } return 0; } void podwoj(int tab[], int rozmiar) { int i; /* lub int * tab 8 10 20 10 12 16 16 18 12 */ for(i = 0; i < rozmiar; i++) tab[i] *= 2; } Elwira Wachowicz ([email protected]) Tablice i wskaźniki 29 maja 2013 21 / 12