Tablice, funkcje, wskaźniki - wprowadzenie Przemysław Gawroński D-10, p. 234 Wykład 4 19 listopada 2018 (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 1 / 37
Outline 1 Tablice jednowymiarowe 2 Funkcje 3 Wskaźniki 4 Tablice a wskaźniki (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 2 / 37
Tablice jednowymiarowe Ogólna postać deklaracji tablicy jednowymiarowej: typ nazwa zmiennej [rozmiar]; (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 3 / 37
Tablice jednowymiarowe Ogólna postać deklaracji tablicy jednowymiarowej: typ nazwa zmiennej [rozmiar]; W standardzie C89 rozmiar tablicy: (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 3 / 37
Tablice jednowymiarowe Ogólna postać deklaracji tablicy jednowymiarowej: typ nazwa zmiennej [rozmiar]; W standardzie C89 rozmiar tablicy: musi być określony za pomocą stałego wyrażenia, (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 3 / 37
Tablice jednowymiarowe Ogólna postać deklaracji tablicy jednowymiarowej: typ nazwa zmiennej [rozmiar]; W standardzie C89 rozmiar tablicy: musi być określony za pomocą stałego wyrażenia, jest ustalany w czasie kompilacji. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 3 / 37
Tablice jednowymiarowe Ogólna postać deklaracji tablicy jednowymiarowej: typ nazwa zmiennej [rozmiar]; W standardzie C89 rozmiar tablicy: musi być określony za pomocą stałego wyrażenia, jest ustalany w czasie kompilacji. Przykład: double tab[100]; //pierwsza komórka tablicy - tab[0], ostatnia komórka tablicy - tab[99] tab[2] = 12.23; //przypisane trzeciej komórce tablicy wartości. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 3 / 37
Tablice jednowymiarowe Ogólna postać deklaracji tablicy jednowymiarowej: typ nazwa zmiennej [rozmiar]; W standardzie C89 rozmiar tablicy: musi być określony za pomocą stałego wyrażenia, jest ustalany w czasie kompilacji. Przykład: double tab[100]; //pierwsza komórka tablicy - tab[0], ostatnia komórka tablicy - tab[99] tab[2] = 12.23; //przypisane trzeciej komórce tablicy wartości. Standard C99 pozwala tworzyć tablice, których rozmiar określa się w czasie działania programu (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 3 / 37
Tablice znaków - łańcuchy W języku C łańcuch to jednowymiarowa tablica znaków zakończona znakiem końca łańcucha ( \0 ). (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 4 / 37
Tablice znaków - łańcuchy W języku C łańcuch to jednowymiarowa tablica znaków zakończona znakiem końca łańcucha ( \0 ). Przykład: char str[9]; // 8 znaków łańcucha plus znak końca łańcucha (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 4 / 37
Tablice znaków - łańcuchy W języku C łańcuch to jednowymiarowa tablica znaków zakończona znakiem końca łańcucha ( \0 ). Przykład: char str[9]; // 8 znaków łańcucha plus znak końca łańcucha Stała tekstowa tekst to t, e, k, s, t, \0. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 4 / 37
Tablice znaków - łańcuchy W języku C łańcuch to jednowymiarowa tablica znaków zakończona znakiem końca łańcucha ( \0 ). Przykład: char str[9]; // 8 znaków łańcucha plus znak końca łańcucha Stała tekstowa tekst to t, e, k, s, t, \0. W przypadku stałych tekstowych znak końca łańcucha dopisywany jest automatycznie przez kompilator. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 4 / 37
Tablice znaków - łańcuchy W języku C łańcuch to jednowymiarowa tablica znaków zakończona znakiem końca łańcucha ( \0 ). Przykład: char str[9]; // 8 znaków łańcucha plus znak końca łańcucha Stała tekstowa tekst to t, e, k, s, t, \0. W przypadku stałych tekstowych znak końca łańcucha dopisywany jest automatycznie przez kompilator. string.h (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 4 / 37
Inicjowanie tablic Ogólna postać inicjacji tablicy: typ nazwatab[rozmiar] = lista wartości; (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 5 / 37
Inicjowanie tablic Ogólna postać inicjacji tablicy: typ nazwatab[rozmiar] = lista wartości; Przykłady: int tab1 [3] = {2, 3, 4}; int tab2 [5] = {0}; int tab3 [ 123] = {1, 2, 3}; char znaki [8]={ A, B, C, D, E, _, G, \0 }; char tekst [8]= " 12345 _7"; (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 5 / 37
Tablice o nieokreślonym rozmiarze Przykład: char tek []= "\ ndlugi tekst, ktorego znakow nie chce mi sie liczyc.\n"; printf (" Tekst %s ma dlugosc %d\n", tek, tek / sizeof ( char )); sizeof (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 6 / 37
Tablice o nieokreślonym rozmiarze Przykład: char tek []= "\ ndlugi tekst, ktorego znakow nie chce mi sie liczyc.\n"; printf (" Tekst %s ma dlugosc %d\n", tek, tek / sizeof ( char )); sizeof Przykład: int tabs [] = {2, 3, 4, 5}; int roz = sizeof tabs / sizeof tabs [ 0]; int i; for (i =0; i<roz ; i ++) { tabs [i ]=(100* tab [i]-(i +28) ) %33; printf ("%d\n", tabs [i]); } (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 6 / 37
Tablice jednowymiarowe - idiomy Wczytywanie danych do tablicy # define SIZE 10... int tab_a [ SIZE ], tab_b [ SIZE ]; for (i =0;i< SIZE ;i ++) scanf ("%d", & tab_a [i]); // scanf ("% d", tab_a +i); (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 7 / 37
Tablice jednowymiarowe - idiomy Wczytywanie danych do tablicy # define SIZE 10... int tab_a [ SIZE ], tab_b [ SIZE ]; for (i =0;i< SIZE ;i ++) scanf ("%d", & tab_a [i]); // scanf ("% d", tab_a +i); Sumowanie elementów tablicy int sum =0; for (i =0;i< SIZE ;i ++) sum += tab_a [i]; (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 7 / 37
Tablice jednowymiarowe - idiomy Wczytywanie danych do tablicy # define SIZE 10... int tab_a [ SIZE ], tab_b [ SIZE ]; for (i =0;i< SIZE ;i ++) scanf ("%d", & tab_a [i]); // scanf ("% d", tab_a +i); Sumowanie elementów tablicy int sum =0; for (i =0;i< SIZE ;i ++) sum += tab_a [i]; Kopiowanie elementów tablicy for (i =0;i< SIZE ;i ++) tab_b [i]= tab_a [i]; (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 7 / 37
Tablice jednowymiarowe W języku C nie ma żadnej kontroli przekroczenia zakresu tablicy. int licz [10], i; for (i =0;i <100; i ++) licz [i]=i; (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 8 / 37
Funkcje Funkcje to podstawowe części składowe każdego programu w języku C. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 9 / 37
Funkcje Funkcje to podstawowe części składowe każdego programu w języku C. Ogólna postać definicji funkcji to: typ zwracany nazwa funkcji (list parm){ ciało funkcji } (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 9 / 37
Funkcje Funkcje to podstawowe części składowe każdego programu w języku C. Ogólna postać definicji funkcji to: typ zwracany nazwa funkcji (list parm){ ciało funkcji } Funkcja może zwrócić dane dowolnego typu z wyjątkiem tablic. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 9 / 37
Funkcje Funkcje to podstawowe części składowe każdego programu w języku C. Ogólna postać definicji funkcji to: typ zwracany nazwa funkcji (list parm){ ciało funkcji } Funkcja może zwrócić dane dowolnego typu z wyjątkiem tablic. Pustą listę parametrów specyfikujemy słowem kluczowym void. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 9 / 37
Funkcje Funkcje to podstawowe części składowe każdego programu w języku C. Ogólna postać definicji funkcji to: typ zwracany nazwa funkcji (list parm){ ciało funkcji } Funkcja może zwrócić dane dowolnego typu z wyjątkiem tablic. Pustą listę parametrów specyfikujemy słowem kluczowym void. Prototyp funkcji - deklaracja funkcji: void f (int i, int j, float k); void f (int i, j, float k); BŁĄD (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 9 / 37
Funkcje Żadna funkcja nie może odwołać się bezpośrednio do kodu innej funkcji inaczej niż przez jej wywołanie. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 10 / 37
Funkcje Żadna funkcja nie może odwołać się bezpośrednio do kodu innej funkcji inaczej niż przez jej wywołanie. Nie można użyć instrukcji goto aby wskoczyć do środka innej funkcji. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 10 / 37
Funkcje Żadna funkcja nie może odwołać się bezpośrednio do kodu innej funkcji inaczej niż przez jej wywołanie. Nie można użyć instrukcji goto aby wskoczyć do środka innej funkcji. Zmienne zdefiniowane wewnątrz funkcji oraz parametry formalne to zmienne lokalne. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 10 / 37
Funkcje Żadna funkcja nie może odwołać się bezpośrednio do kodu innej funkcji inaczej niż przez jej wywołanie. Nie można użyć instrukcji goto aby wskoczyć do środka innej funkcji. Zmienne zdefiniowane wewnątrz funkcji oraz parametry formalne to zmienne lokalne. Niestatyczne zmienne lokalne nie mogą zachowywać wartości pomiędzy wywołaniami funkcji. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 10 / 37
Funkcje Żadna funkcja nie może odwołać się bezpośrednio do kodu innej funkcji inaczej niż przez jej wywołanie. Nie można użyć instrukcji goto aby wskoczyć do środka innej funkcji. Zmienne zdefiniowane wewnątrz funkcji oraz parametry formalne to zmienne lokalne. Niestatyczne zmienne lokalne nie mogą zachowywać wartości pomiędzy wywołaniami funkcji. Funkcje mają zasięg pliku. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 10 / 37
Funkcje - zwracanie wartości Wszystkie funkcje, z wyjątkiem zadeklarowanych jako void, zwracają jedną wartość, określoną instrukcją return zgodną z typem funkcji. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 11 / 37
Funkcje - zwracanie wartości Wszystkie funkcje, z wyjątkiem zadeklarowanych jako void, zwracają jedną wartość, określoną instrukcją return zgodną z typem funkcji. Funkcje można podzielić na trzy rodzaje: (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 11 / 37
Funkcje - zwracanie wartości Wszystkie funkcje, z wyjątkiem zadeklarowanych jako void, zwracają jedną wartość, określoną instrukcją return zgodną z typem funkcji. Funkcje można podzielić na trzy rodzaje: obliczeniowe - sqrt(), sin(). (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 11 / 37
Funkcje - zwracanie wartości Wszystkie funkcje, z wyjątkiem zadeklarowanych jako void, zwracają jedną wartość, określoną instrukcją return zgodną z typem funkcji. Funkcje można podzielić na trzy rodzaje: obliczeniowe - sqrt(), sin(). operujące na informacjach i zwracające wartość w zależności od wyniku operacji malloc() //NULL lub adres przydzielonego obszaru pamięci. fclose() //0 powodzenie, EOF - błąd. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 11 / 37
Funkcje - zwracanie wartości Wszystkie funkcje, z wyjątkiem zadeklarowanych jako void, zwracają jedną wartość, określoną instrukcją return zgodną z typem funkcji. Funkcje można podzielić na trzy rodzaje: obliczeniowe - sqrt(), sin(). operujące na informacjach i zwracające wartość w zależności od wyniku operacji malloc() //NULL lub adres przydzielonego obszaru pamięci. fclose() //0 powodzenie, EOF - błąd. funkcje typu void - (procedury): exit(), free(). (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 11 / 37
Funkcje - zwracanie wartości Wszystkie funkcje, z wyjątkiem zadeklarowanych jako void, zwracają jedną wartość, określoną instrukcją return zgodną z typem funkcji. Funkcje można podzielić na trzy rodzaje: obliczeniowe - sqrt(), sin(). operujące na informacjach i zwracające wartość w zależności od wyniku operacji malloc() //NULL lub adres przydzielonego obszaru pamięci. fclose() //0 powodzenie, EOF - błąd. funkcje typu void - (procedury): exit(), free(). zmienna = fun(); // przypisujemy zmiennej wynik, który zawraca funkcja. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 11 / 37
Funkcje - zwracanie wartości Wszystkie funkcje, z wyjątkiem zadeklarowanych jako void, zwracają jedną wartość, określoną instrukcją return zgodną z typem funkcji. Funkcje można podzielić na trzy rodzaje: obliczeniowe - sqrt(), sin(). operujące na informacjach i zwracające wartość w zależności od wyniku operacji malloc() //NULL lub adres przydzielonego obszaru pamięci. fclose() //0 powodzenie, EOF - błąd. funkcje typu void - (procedury): exit(), free(). zmienna = fun(); // przypisujemy zmiennej wynik, który zawraca funkcja. Funkcja int printf(const char * format [, arg,...]) zwraca liczbę wypisanych znaków. Wartości zwracane przez funkcję mogą być ignorowane. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 11 / 37
Instrukcje skoku - return Ogólna postać instrukcji return to: (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 12 / 37
Instrukcje skoku - return Ogólna postać instrukcji return to: return wyrażenie; (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 12 / 37
Instrukcje skoku - return Ogólna postać instrukcji return to: return wyrażenie; wyrażenie występuje tylko wtedy, gdy z deklaracji funkcji wynika, że ma zostać zwrócona wartość. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 12 / 37
Instrukcje skoku - return Ogólna postać instrukcji return to: return wyrażenie; wyrażenie występuje tylko wtedy, gdy z deklaracji funkcji wynika, że ma zostać zwrócona wartość. Instrukcja return z określoną wartością może wystąpić jedynie w funkcji, która nie jest typu void. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 12 / 37
Instrukcje skoku - return Ogólna postać instrukcji return to: return wyrażenie; wyrażenie występuje tylko wtedy, gdy z deklaracji funkcji wynika, że ma zostać zwrócona wartość. Instrukcja return z określoną wartością może wystąpić jedynie w funkcji, która nie jest typu void. Instrukcji return używa się aby powrócić z funkcji. Instrukcja powoduje przekazanie sterowania do punktu, w którym miało miejsce wywołanie funkcji. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 12 / 37
Instrukcje skoku - return Ogólna postać instrukcji return to: return wyrażenie; wyrażenie występuje tylko wtedy, gdy z deklaracji funkcji wynika, że ma zostać zwrócona wartość. Instrukcja return z określoną wartością może wystąpić jedynie w funkcji, która nie jest typu void. Instrukcji return używa się aby powrócić z funkcji. Instrukcja powoduje przekazanie sterowania do punktu, w którym miało miejsce wywołanie funkcji. W C99 (C++) instrukcja return w funkcji niebędącej typu void musi zwrócić wartość. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 12 / 37
Instrukcje skoku - return Ogólna postać instrukcji return to: return wyrażenie; wyrażenie występuje tylko wtedy, gdy z deklaracji funkcji wynika, że ma zostać zwrócona wartość. Instrukcja return z określoną wartością może wystąpić jedynie w funkcji, która nie jest typu void. Instrukcji return używa się aby powrócić z funkcji. Instrukcja powoduje przekazanie sterowania do punktu, w którym miało miejsce wywołanie funkcji. W C99 (C++) instrukcja return w funkcji niebędącej typu void musi zwrócić wartość. W C89 jeśli funkcja z definicji zwraca wartość, to w dobrym stylu jest zadbanie, aby jakaś wartość została zwrócona. Jeśli nie określi się wartości funkcja zwróci śmieci. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 12 / 37
Funkcje - przekazywanie argumentów W różnych językach programowania argumenty do funkcji mogą być przekazywane: (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 13 / 37
Funkcje - przekazywanie argumentów W różnych językach programowania argumenty do funkcji mogą być przekazywane: przez wartość, (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 13 / 37
Funkcje - przekazywanie argumentów W różnych językach programowania argumenty do funkcji mogą być przekazywane: przez wartość, przez referencję. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 13 / 37
Funkcje - przekazywanie argumentów W różnych językach programowania argumenty do funkcji mogą być przekazywane: przez wartość, przez referencję. Argumenty przekazane przez wartość są kopiowane do parametrów formalnych. Zmiany wartości parametrów formalnych nie mają wpływu na wartości argumentów. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 13 / 37
Funkcje - przekazywanie argumentów W różnych językach programowania argumenty do funkcji mogą być przekazywane: przez wartość, przez referencję. Argumenty przekazane przez wartość są kopiowane do parametrów formalnych. Zmiany wartości parametrów formalnych nie mają wpływu na wartości argumentów. W przypadku przekazania przez referencje, adres argumentu jest kopiowany do parametru formalnego. Wewnątrz funkcji odwołanie do faktycznej wartości realizowane jest za pomocą adresu. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 13 / 37
Funkcje - przekazywanie argumentów W różnych językach programowania argumenty do funkcji mogą być przekazywane: przez wartość, przez referencję. Argumenty przekazane przez wartość są kopiowane do parametrów formalnych. Zmiany wartości parametrów formalnych nie mają wpływu na wartości argumentów. W przypadku przekazania przez referencje, adres argumentu jest kopiowany do parametru formalnego. Wewnątrz funkcji odwołanie do faktycznej wartości realizowane jest za pomocą adresu. W języku C argumenty przekazywane są przez wartość. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 13 / 37
Funkcje - przekazywanie argumentów W różnych językach programowania argumenty do funkcji mogą być przekazywane: przez wartość, przez referencję. Argumenty przekazane przez wartość są kopiowane do parametrów formalnych. Zmiany wartości parametrów formalnych nie mają wpływu na wartości argumentów. W przypadku przekazania przez referencje, adres argumentu jest kopiowany do parametru formalnego. Wewnątrz funkcji odwołanie do faktycznej wartości realizowane jest za pomocą adresu. W języku C argumenty przekazywane są przez wartość. W języku C możemy symulować przekazywanie przez referencję, przekazując przez wartość wskaźnik do zmiennej, zamiast samej zmiennej. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 13 / 37
Funkcje - przekazywanie argumentów W języku C argumenty przekazywane są przez wartość. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 14 / 37
Funkcje - przekazywanie argumentów W języku C argumenty przekazywane są przez wartość. Przykład: int sq(int t){ t*=t; printf ("in sq t = %d\n",t); return t; } int main ( void ){ int t =10; printf ("%d * %d = %d\n", t, t, return 0; } sq(t)); (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 14 / 37
Funkcje rekurencyjne W języku C funkcja może wywołać samą siebie. W takim przypadku na stosie powstaje nowy zestaw zmiennych lokalnych, a wykonanie kodu zaczyna się od początku z nowym zestawem wartości. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 15 / 37
Funkcje rekurencyjne W języku C funkcja może wywołać samą siebie. W takim przypadku na stosie powstaje nowy zestaw zmiennych lokalnych, a wykonanie kodu zaczyna się od początku z nowym zestawem wartości. Wywołanie rekurencyjne nie tworzy kopii funkcji. Nowe są jedynie wartości, na których działa kod. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 15 / 37
Funkcje rekurencyjne W języku C funkcja może wywołać samą siebie. W takim przypadku na stosie powstaje nowy zestaw zmiennych lokalnych, a wykonanie kodu zaczyna się od początku z nowym zestawem wartości. Wywołanie rekurencyjne nie tworzy kopii funkcji. Nowe są jedynie wartości, na których działa kod. Funkcje rekurencyjne przeważnie działają wolniej niż odpowiedniki iteracyjne. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 15 / 37
Funkcje rekurencyjne W języku C funkcja może wywołać samą siebie. W takim przypadku na stosie powstaje nowy zestaw zmiennych lokalnych, a wykonanie kodu zaczyna się od początku z nowym zestawem wartości. Wywołanie rekurencyjne nie tworzy kopii funkcji. Nowe są jedynie wartości, na których działa kod. Funkcje rekurencyjne przeważnie działają wolniej niż odpowiedniki iteracyjne. Rekurencja umożliwia prosty i jasny zapis niektórych algorytmów. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 15 / 37
Funkcje rekurencyjne W języku C funkcja może wywołać samą siebie. W takim przypadku na stosie powstaje nowy zestaw zmiennych lokalnych, a wykonanie kodu zaczyna się od początku z nowym zestawem wartości. Wywołanie rekurencyjne nie tworzy kopii funkcji. Nowe są jedynie wartości, na których działa kod. Funkcje rekurencyjne przeważnie działają wolniej niż odpowiedniki iteracyjne. Rekurencja umożliwia prosty i jasny zapis niektórych algorytmów. Bardzo głęboka rekurencja może spowodować przepełnienie stosu. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 15 / 37
Funkcje rekurencyjne - przykład - wieże Hanoi void hanoi ( int n, int s, int d, int p){ if(n >0) { hanoi (n -1,s,p,d); printf (" przesunac krazek z %d na %d\n",s,d); hanoi (n -1,p,d,s); } } int main ( void ){ printf ("5\n"); hanoi (5, 1, 3, 2); return 0; } (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 16 / 37
Wskaźniki Korzyści płynące ze wskaźników: (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 17 / 37
Wskaźniki Korzyści płynące ze wskaźników: wskaźniki umożliwiają funkcjom modyfikowanie swoich argumentów, (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 17 / 37
Wskaźniki Korzyści płynące ze wskaźników: wskaźniki umożliwiają funkcjom modyfikowanie swoich argumentów, wskaźniki są podstawą dynamicznej alokacji pamięci, (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 17 / 37
Wskaźniki Korzyści płynące ze wskaźników: wskaźniki umożliwiają funkcjom modyfikowanie swoich argumentów, wskaźniki są podstawą dynamicznej alokacji pamięci, wskaźniki umożliwiają realizację dynamicznych struktur danych: listy, drzewa, itp, (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 17 / 37
Wskaźniki Korzyści płynące ze wskaźników: wskaźniki umożliwiają funkcjom modyfikowanie swoich argumentów, wskaźniki są podstawą dynamicznej alokacji pamięci, wskaźniki umożliwiają realizację dynamicznych struktur danych: listy, drzewa, itp, wskaźniki pozwalają poprawić efektywność działania wielu procedur. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 17 / 37
Wskaźniki Wskaźnik to zmienna przechowująca adres innej zmiennej. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 18 / 37
Wskaźniki Wskaźnik to zmienna przechowująca adres innej zmiennej. Adres zmiennej to informacja o jej fizycznej lokalizacji w pamięci programu. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 18 / 37
Wskaźniki Wskaźnik to zmienna przechowująca adres innej zmiennej. Adres zmiennej to informacja o jej fizycznej lokalizacji w pamięci programu. Ogólna postać deklaracji wskaźnika: typ *nazwa; (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 18 / 37
Wskaźniki Wskaźnik to zmienna przechowująca adres innej zmiennej. Adres zmiennej to informacja o jej fizycznej lokalizacji w pamięci programu. Ogólna postać deklaracji wskaźnika: typ *nazwa; Typ podstawowy wskaźnika określa, na jakiego typu zmienne może on wskazywać. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 18 / 37
Wskaźniki Wskaźnik to zmienna przechowująca adres innej zmiennej. Adres zmiennej to informacja o jej fizycznej lokalizacji w pamięci programu. Ogólna postać deklaracji wskaźnika: typ *nazwa; Typ podstawowy wskaźnika określa, na jakiego typu zmienne może on wskazywać. Wszelkie obliczenia na wskaźnikach wykonuje się z uwzględnieniem typu podstawowego. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 18 / 37
Wskaźniki Wskaźnik to zmienna przechowująca adres innej zmiennej. Adres zmiennej to informacja o jej fizycznej lokalizacji w pamięci programu. Ogólna postać deklaracji wskaźnika: typ *nazwa; Typ podstawowy wskaźnika określa, na jakiego typu zmienne może on wskazywać. Wszelkie obliczenia na wskaźnikach wykonuje się z uwzględnieniem typu podstawowego. W przypadku deklaracji typu int*, kompilator zakłada, że dowolny adres wskazywany przez niego zawiera liczbę całkowitą - niezależnie od tego, co aktualnie zawiera wskazywany fragment pamięci. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 18 / 37
Wskaźniki Wskaźnik to zmienna przechowująca adres innej zmiennej. Adres zmiennej to informacja o jej fizycznej lokalizacji w pamięci programu. Ogólna postać deklaracji wskaźnika: typ *nazwa; Typ podstawowy wskaźnika określa, na jakiego typu zmienne może on wskazywać. Wszelkie obliczenia na wskaźnikach wykonuje się z uwzględnieniem typu podstawowego. W przypadku deklaracji typu int*, kompilator zakłada, że dowolny adres wskazywany przez niego zawiera liczbę całkowitą - niezależnie od tego, co aktualnie zawiera wskazywany fragment pamięci. Programista musi zagwarantować, że typ wskaźnika jest zgodny z typem zmiennej, na który wskazuje. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 18 / 37
Wskaźniki - inicjalizacja Wskaźnikowi, który nie zawiera poprawnego adresu należy nadać wartość NULL(zero). (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 19 / 37
Wskaźniki - inicjalizacja Wskaźnikowi, który nie zawiera poprawnego adresu należy nadać wartość NULL(zero). Język C gwarantuje, że pod zerowym adresem nie istnieje żadna zmienna. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 19 / 37
Wskaźniki - inicjalizacja Wskaźnikowi, który nie zawiera poprawnego adresu należy nadać wartość NULL(zero). Język C gwarantuje, że pod zerowym adresem nie istnieje żadna zmienna. Wskaźnik o wartości NULL nie wskazuje na żadną zmienną. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 19 / 37
Wskaźniki - inicjalizacja Wskaźnikowi, który nie zawiera poprawnego adresu należy nadać wartość NULL(zero). Język C gwarantuje, że pod zerowym adresem nie istnieje żadna zmienna. Wskaźnik o wartości NULL nie wskazuje na żadną zmienną. Przykład: int *pi; float *pf, fl; pi = NULL ; pf = &fl; * pi = 81; // BLEDNA INSTRUKCJA *pf = 12.89; (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 19 / 37
Wskaźniki - operatory Operator & zwraca adres w pamięci dla operandu. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 20 / 37
Wskaźniki - operatory Operator & zwraca adres w pamięci dla operandu. Operator * zwraca wartość zmiennej, znajdującej się pod adresem operandu. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 20 / 37
Wskaźniki - operatory Operator & zwraca adres w pamięci dla operandu. Operator * zwraca wartość zmiennej, znajdującej się pod adresem operandu. Każda lokalizacja w pamięci jest identyfikowana przez unikalny adres. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 20 / 37
Wskaźniki - operatory Operator & zwraca adres w pamięci dla operandu. Operator * zwraca wartość zmiennej, znajdującej się pod adresem operandu. Każda lokalizacja w pamięci jest identyfikowana przez unikalny adres. Każda lokalizacja w pamięci zawiera wartość. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 20 / 37
Wskaźniki - operatory Operator & zwraca adres w pamięci dla operandu. Operator * zwraca wartość zmiennej, znajdującej się pod adresem operandu. Każda lokalizacja w pamięci jest identyfikowana przez unikalny adres. Każda lokalizacja w pamięci zawiera wartość. Przykład: int i, *pi, *pj; i =9; pi = &i; pj = pi; *pj =123; Jaka jest wartość i, &i, pi, *pi, &pi? (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 20 / 37
Wskaźniki Wskaźnik typu void * to wskaźnik ogólnego przeznaczenia. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 21 / 37
Wskaźniki Wskaźnik typu void * to wskaźnik ogólnego przeznaczenia. Wskaźnik typu void * można przypisać dowolnemu innemu wskaźnikowi. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 21 / 37
Wskaźniki Wskaźnik typu void * to wskaźnik ogólnego przeznaczenia. Wskaźnik typu void * można przypisać dowolnemu innemu wskaźnikowi. Wskaźnikowi typu void * można przypisać dowolny inny wskaźnik. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 21 / 37
Wskaźniki Wskaźnik typu void * to wskaźnik ogólnego przeznaczenia. Wskaźnik typu void * można przypisać dowolnemu innemu wskaźnikowi. Wskaźnikowi typu void * można przypisać dowolny inny wskaźnik. void * pozwala zdefiniować parametr funkcji, która może przyjąć jako argument wskaźnik dowolnego typu. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 21 / 37
Wskaźniki Wskaźnik typu void * to wskaźnik ogólnego przeznaczenia. Wskaźnik typu void * można przypisać dowolnemu innemu wskaźnikowi. Wskaźnikowi typu void * można przypisać dowolny inny wskaźnik. void * pozwala zdefiniować parametr funkcji, która może przyjąć jako argument wskaźnik dowolnego typu. void * umożliwia dostęp pamięci (np. malloc), gdy przeznaczenie takiej pamięci nie jest jeszcze znane. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 21 / 37
Wskaźniki Wskaźnik typu void * to wskaźnik ogólnego przeznaczenia. Wskaźnik typu void * można przypisać dowolnemu innemu wskaźnikowi. Wskaźnikowi typu void * można przypisać dowolny inny wskaźnik. void * pozwala zdefiniować parametr funkcji, która może przyjąć jako argument wskaźnik dowolnego typu. void * umożliwia dostęp pamięci (np. malloc), gdy przeznaczenie takiej pamięci nie jest jeszcze znane. Nie można wykonywać operacji arytmetycznych na wskaźnikach typu void *. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 21 / 37
Arytmetyka wskaźników Operacje wskaźnikowe wykonywane są z uwzględnieniem typu podstawowego wskaźnika. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 22 / 37
Arytmetyka wskaźników Operacje wskaźnikowe wykonywane są z uwzględnieniem typu podstawowego wskaźnika. Na wskaźnikach można wykonywać tylko dwie operacje arytmetyczne: dodawanie i odejmowanie. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 22 / 37
Arytmetyka wskaźników Operacje wskaźnikowe wykonywane są z uwzględnieniem typu podstawowego wskaźnika. Na wskaźnikach można wykonywać tylko dwie operacje arytmetyczne: dodawanie i odejmowanie. Przykład: int tab [10]={1}; int *pt=null, * ptf = NULL ; pt = tab ;// pt = & tab [0]; ptf = pt + 5; // ptf = & pt; - BLAD - niezgodnosc typow *( pt + 3) = *pt + 3; *( pt + 4) = *( ptf - 2); *( pt + 1) = ptf - tab ; (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 22 / 37
Arytmetyka wskaźników # define SIZE 8... int i, itab [ SIZE ], * pit = itab ; double dtab [ SIZE ], * pdt = dtab ; printf (" %18 s %15 s\n", " int ", " double "); for ( i = 0; i < SIZE ; i ++) printf (" wsk + %d %10 p %10 p\n",i,pit +i,pdt +i); (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 23 / 37
Arytmetyka wskaźników # define SIZE 8... int i, itab [ SIZE ], * pit = itab ; double dtab [ SIZE ], * pdt = dtab ; printf (" %18 s %15 s\n", " int ", " double "); for ( i = 0; i < SIZE ; i ++) printf (" wsk + %d %10 p %10 p\n",i,pit +i,pdt +i); int double wsk + 0 : 0x7fff36430c60 0x7fff36430c10 wsk + 1 : 0x7fff36430c64 0x7fff36430c18 wsk + 2 : 0x7fff36430c68 0x7fff36430c20 wsk + 3 : 0x7fff36430c6c 0x7fff36430c28 wsk + 4 : 0x7fff36430c70 0x7fff36430c30 wsk + 5 : 0x7fff36430c74 0x7fff36430c38 wsk + 6 : 0x7fff36430c78 0x7fff36430c40 wsk (Wykład + 74) : 0x7fff36430c7c Tablice, funkcje, wskaźniki 0x7fff36430c48 - wprowadzenie 19 listopada 2018 23 / 37
Wskaźniki i tablice Pomiędzy wskaźnikami i tablicami istnieje ścisłe powiązanie. Nazwa tablicy bez indeksu to adres pierwszego elementu. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 24 / 37
Wskaźniki i tablice Pomiędzy wskaźnikami i tablicami istnieje ścisłe powiązanie. Nazwa tablicy bez indeksu to adres pierwszego elementu. Przykład: int tab [10]; int *p; p= tab ; (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 24 / 37
Wskaźniki i tablice Pomiędzy wskaźnikami i tablicami istnieje ścisłe powiązanie. Nazwa tablicy bez indeksu to adres pierwszego elementu. Przykład: int tab [10]; int *p; p= tab ; Aby odwołać się do elementu o indeksie 4 w tablicy tab można skorzystać z: tab[4] lub *(p+4). (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 24 / 37
Wskaźniki i tablice Pomiędzy wskaźnikami i tablicami istnieje ścisłe powiązanie. Nazwa tablicy bez indeksu to adres pierwszego elementu. Przykład: int tab [10]; int *p; p= tab ; Aby odwołać się do elementu o indeksie 4 w tablicy tab można skorzystać z: tab[4] lub *(p+4). Polecenie tab[4]=18 jest równoważne *(p+4)=18, jak również *(tab+4)=18 oraz p[4]=18. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 24 / 37
Czym są tablice? W języku C dla tablic przewidziano tylko 2 operacje: (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 25 / 37
Czym są tablice? W języku C dla tablic przewidziano tylko 2 operacje: określenie rozmiaru tablicy, (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 25 / 37
Czym są tablice? W języku C dla tablic przewidziano tylko 2 operacje: określenie rozmiaru tablicy, uzyskanie adresu pierwszego elementu tablicy (o indeksie zerowym). (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 25 / 37
Czym są tablice? W języku C dla tablic przewidziano tylko 2 operacje: określenie rozmiaru tablicy, uzyskanie adresu pierwszego elementu tablicy (o indeksie zerowym). Wszystkie pozostałe operacje są w istocie realizowane na wskaźnikach, nawet jeśli zapis sugeruje co innego, np. tab[i]. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 25 / 37
Czym są tablice? W języku C dla tablic przewidziano tylko 2 operacje: określenie rozmiaru tablicy, uzyskanie adresu pierwszego elementu tablicy (o indeksie zerowym). Wszystkie pozostałe operacje są w istocie realizowane na wskaźnikach, nawet jeśli zapis sugeruje co innego, np. tab[i]. W języku C nazwa tab odnosi się do adresu elementu tablicy tab[] o indeksie zero w każdym kontekście, z wyjątkiem jednego, kiedy to występuje jako argument operatora sizeof. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 25 / 37
Czym są tablice? W języku C dla tablic przewidziano tylko 2 operacje: określenie rozmiaru tablicy, uzyskanie adresu pierwszego elementu tablicy (o indeksie zerowym). Wszystkie pozostałe operacje są w istocie realizowane na wskaźnikach, nawet jeśli zapis sugeruje co innego, np. tab[i]. W języku C nazwa tab odnosi się do adresu elementu tablicy tab[] o indeksie zero w każdym kontekście, z wyjątkiem jednego, kiedy to występuje jako argument operatora sizeof. Zapis sizeof tab - reprezentuje rozmiar całej tablicy, a nie rozmiar wskaźnika jednego z jej elementów. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 25 / 37
Czym są tablice? *tab = 18 - przypisujemy wartość elementowi o indeksie 0. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 26 / 37
Czym są tablice? *tab = 18 - przypisujemy wartość elementowi o indeksie 0. *(tab + 5) = 18 - przypisujemy wartość elementowi o indeksie 5. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 26 / 37
Czym są tablice? *tab = 18 - przypisujemy wartość elementowi o indeksie 0. *(tab + 5) = 18 - przypisujemy wartość elementowi o indeksie 5. *(tab + 5) = 18 - działa tak samo jak *(5 + tab) = 18. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 26 / 37
Czym są tablice? *tab = 18 - przypisujemy wartość elementowi o indeksie 0. *(tab + 5) = 18 - przypisujemy wartość elementowi o indeksie 5. *(tab + 5) = 18 - działa tak samo jak *(5 + tab) = 18. tab[5] = 18 - przypisujemy wartość elementowi o indeksie 5. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 26 / 37
Czym są tablice? *tab = 18 - przypisujemy wartość elementowi o indeksie 0. *(tab + 5) = 18 - przypisujemy wartość elementowi o indeksie 5. *(tab + 5) = 18 - działa tak samo jak *(5 + tab) = 18. tab[5] = 18 - przypisujemy wartość elementowi o indeksie 5. tab[5] = 18 - działa tak samo jak 5[tab]=18. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 26 / 37
Czym są tablice? *tab = 18 - przypisujemy wartość elementowi o indeksie 0. *(tab + 5) = 18 - przypisujemy wartość elementowi o indeksie 5. *(tab + 5) = 18 - działa tak samo jak *(5 + tab) = 18. tab[5] = 18 - przypisujemy wartość elementowi o indeksie 5. tab[5] = 18 - działa tak samo jak 5[tab]=18. Notacja 5[tab] = 18 - działa, ale nie powinna być stosowana. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 26 / 37
Tablice i wskaźniki Tablice to nie wskaźniki choć są blisko z nimi związane. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 27 / 37
Tablice i wskaźniki Tablice to nie wskaźniki choć są blisko z nimi związane. char tab[] i char *p to to samo tylko w przypadku parametrów formalnych funkcji. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 27 / 37
Tablice i wskaźniki Tablice to nie wskaźniki choć są blisko z nimi związane. char tab[] i char *p to to samo tylko w przypadku parametrów formalnych funkcji. Deklaracja char tab[6] przydziela miejsce na 6 znaków i wiąże ten obszar z nazwą tab. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 27 / 37
Tablice i wskaźniki Tablice to nie wskaźniki choć są blisko z nimi związane. char tab[] i char *p to to samo tylko w przypadku parametrów formalnych funkcji. Deklaracja char tab[6] przydziela miejsce na 6 znaków i wiąże ten obszar z nazwą tab. Deklaracja char *p przydziela miejsce na 1 wskaźnik. Wskaźnik może wskazywać: (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 27 / 37
Tablice i wskaźniki Tablice to nie wskaźniki choć są blisko z nimi związane. char tab[] i char *p to to samo tylko w przypadku parametrów formalnych funkcji. Deklaracja char tab[6] przydziela miejsce na 6 znaków i wiąże ten obszar z nazwą tab. Deklaracja char *p przydziela miejsce na 1 wskaźnik. Wskaźnik może wskazywać: na pojedynczą zmienną typu char, (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 27 / 37
Tablice i wskaźniki Tablice to nie wskaźniki choć są blisko z nimi związane. char tab[] i char *p to to samo tylko w przypadku parametrów formalnych funkcji. Deklaracja char tab[6] przydziela miejsce na 6 znaków i wiąże ten obszar z nazwą tab. Deklaracja char *p przydziela miejsce na 1 wskaźnik. Wskaźnik może wskazywać: na pojedynczą zmienną typu char, na dowolny indeks w tablicy typu char, (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 27 / 37
Tablice i wskaźniki Tablice to nie wskaźniki choć są blisko z nimi związane. char tab[] i char *p to to samo tylko w przypadku parametrów formalnych funkcji. Deklaracja char tab[6] przydziela miejsce na 6 znaków i wiąże ten obszar z nazwą tab. Deklaracja char *p przydziela miejsce na 1 wskaźnik. Wskaźnik może wskazywać: na pojedynczą zmienną typu char, na dowolny indeks w tablicy typu char, nigdzie - wskaźnik pusty. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 27 / 37
Tablice i wskaźniki Przykład: char tab[]= hello ; char *p = world ; (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 28 / 37
Tablice i wskaźniki Przykład: char tab[]= hello ; char *p = world ; Jak przetłumaczyć x[3]??? (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 28 / 37
Tablice i wskaźniki Przykład: char tab[]= hello ; char *p = world ; Jak przetłumaczyć x[3]??? tab[3] - weź adres tablicy tab dodaj do niego 3 i pobierz znak, (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 28 / 37
Tablice i wskaźniki Przykład: char tab[]= hello ; char *p = world ; Jak przetłumaczyć x[3]??? tab[3] - weź adres tablicy tab dodaj do niego 3 i pobierz znak, p[3] - weź wartość wskaźnika p, dodaj do niej 3 i pobierz znak. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 28 / 37
Tablice i wskaźniki Przykład: char tab[]= hello ; char *p = world ; Jak przetłumaczyć x[3]??? tab[3] - weź adres tablicy tab dodaj do niego 3 i pobierz znak, p[3] - weź wartość wskaźnika p, dodaj do niej 3 i pobierz znak. Gdzie znajduje się x[3]??? (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 28 / 37
Tablice i wskaźniki Przykład: char tab[]= hello ; char *p = world ; Jak przetłumaczyć x[3]??? tab[3] - weź adres tablicy tab dodaj do niego 3 i pobierz znak, p[3] - weź wartość wskaźnika p, dodaj do niej 3 i pobierz znak. Gdzie znajduje się x[3]??? tab[3] - znak odległy o 3 miejsca od początku obiektu o nazwie tab, (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 28 / 37
Tablice i wskaźniki Przykład: char tab[]= hello ; char *p = world ; Jak przetłumaczyć x[3]??? tab[3] - weź adres tablicy tab dodaj do niego 3 i pobierz znak, p[3] - weź wartość wskaźnika p, dodaj do niej 3 i pobierz znak. Gdzie znajduje się x[3]??? tab[3] - znak odległy o 3 miejsca od początku obiektu o nazwie tab, p[3] - znak odległy o 3 miejsca od obiektu wskazywanego przez p. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 28 / 37
Arytmetyka wskaźników Co inkrementuje *ptr++? (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 29 / 37
Arytmetyka wskaźników Co inkrementuje *ptr++? Operatory *, ++ mają łączność prawostronną. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 29 / 37
Arytmetyka wskaźników Co inkrementuje *ptr++? Operatory *, ++ mają łączność prawostronną. Konstrukcja *ptr++ inkrementuje ptr (i zwraca wartość wskazywaną przez pierwotną wartość wskaźnika). (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 29 / 37
Arytmetyka wskaźników Co inkrementuje *ptr++? Operatory *, ++ mają łączność prawostronną. Konstrukcja *ptr++ inkrementuje ptr (i zwraca wartość wskazywaną przez pierwotną wartość wskaźnika). Aby zwiększyć o jeden obiekt wskazywany przez ptr, należy użyć (*ptr)++. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 29 / 37
Arytmetyka wskaźników Co inkrementuje *ptr++? Operatory *, ++ mają łączność prawostronną. Konstrukcja *ptr++ inkrementuje ptr (i zwraca wartość wskazywaną przez pierwotną wartość wskaźnika). Aby zwiększyć o jeden obiekt wskazywany przez ptr, należy użyć (*ptr)++. wyrażenie wartość wyrażenia inkrementacja *p++ lub *(p++) *p przed ++ p (*p)++ *p przed ++ *p *++p lub *(++p) *p po ++ p ++*p lub ++(*p) *p po ++ *p (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 29 / 37
Wskaźniki - typowe błędy Przykład: int main ( void ){ int x, *p; x = 10; * p = x; // blad p nie zostal zainicjowany. return 0; } (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 30 / 37
Wskaźniki - typowe błędy Przykład: int main ( void ){ int x, *p; x = 10; * p = x; // blad p nie zostal zainicjowany. return 0; } Program umieści wartość 10 w nieznanym obszarze pamięci, ponieważ wskaźnik p nigdy nie otrzymał wartości i nie wiadomo na co wskazuje. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 30 / 37
Wskaźniki - typowe błędy Błąd Naruszenie ochrony pamięci (segmentation fault (sygnał SIGSEGV)) wskazuje, że wystąpiła próba dostępu do adresu spoza pamięci przydzielonej dla programu. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 31 / 37
Wskaźniki - typowe błędy Błąd Naruszenie ochrony pamięci (segmentation fault (sygnał SIGSEGV)) wskazuje, że wystąpiła próba dostępu do adresu spoza pamięci przydzielonej dla programu. Przykład: int * ptr = NULL ; * ptr = 1; const char *s = " hello world "; // error : assignment of read - only location * s *s = H ; (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 31 / 37
Wskaźniki - typowe błędy Przykład: int main ( void ){ int x, *p; x = 10; p = x; // bledne przypisanie powinno byc p =& x printf ("%d", *p); } return 0; (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 32 / 37
Problemy ze wskaźnikami Błędny wskaźnik trudno znaleźć, gdyż wskaźnik sam w sobie nie jest problemem. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 33 / 37
Problemy ze wskaźnikami Błędny wskaźnik trudno znaleźć, gdyż wskaźnik sam w sobie nie jest problemem. Problem bierze się stad, że używając niepoprawnego wskaźnika, zapisujemy lub odczytujemy dane z nieznanego obszaru pamięci. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 33 / 37
Problemy ze wskaźnikami Błędny wskaźnik trudno znaleźć, gdyż wskaźnik sam w sobie nie jest problemem. Problem bierze się stad, że używając niepoprawnego wskaźnika, zapisujemy lub odczytujemy dane z nieznanego obszaru pamięci. Odczytując dane, dostajemy śmieci. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 33 / 37
Problemy ze wskaźnikami Błędny wskaźnik trudno znaleźć, gdyż wskaźnik sam w sobie nie jest problemem. Problem bierze się stad, że używając niepoprawnego wskaźnika, zapisujemy lub odczytujemy dane z nieznanego obszaru pamięci. Odczytując dane, dostajemy śmieci. Zapisując dane, możemy zamazać kod programu lub dane. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 33 / 37
Funkcje - przekazywanie przez referencję W języku C możemy symulować przekazywanie przez referencję, przekazując przez wartość wskaźnik (adres do zmiennej), zamiast samej zmiennej. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 34 / 37
Funkcje - przekazywanie przez referencję W języku C możemy symulować przekazywanie przez referencję, przekazując przez wartość wskaźnik (adres do zmiennej), zamiast samej zmiennej. Przykład: void swap ( int *x, int *y){ int temp = *x; *x = *y; *y = temp ; } int main ( void ){ int i=20, j =29; swap (&i, &j); } return 0; (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 34 / 37
Funkcje - przekazywanie tablic W języku C nie można (i nie trzeba) przekazać do funkcji całej tablicy. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 35 / 37
Funkcje - przekazywanie tablic W języku C nie można (i nie trzeba) przekazać do funkcji całej tablicy. Do funkcji można przekazać tylko i wyłącznie adres do pierwszego elementu tablicy, podając nazwę tablicy bez indeksu. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 35 / 37
Funkcje - przekazywanie tablic W języku C nie można (i nie trzeba) przekazać do funkcji całej tablicy. Do funkcji można przekazać tylko i wyłącznie adres do pierwszego elementu tablicy, podając nazwę tablicy bez indeksu. Przykład: int main ( void ){ int tab [10]; func ( tab ); return 0; } (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 35 / 37
Funkcje - przekazywanie tablic W języku C nie można (i nie trzeba) przekazać do funkcji całej tablicy. Do funkcji można przekazać tylko i wyłącznie adres do pierwszego elementu tablicy, podając nazwę tablicy bez indeksu. Przykład: int main ( void ){ int tab [10]; func ( tab ); return 0; } 3 sposoby deklaracji funkcji func(): void func ( int *x); void func ( int x [10]) ; void func ( int x []) ; (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 35 / 37
Funkcje - przekazywanie tablic W języku C nie można (i nie trzeba) przekazać do funkcji całej tablicy. Do funkcji można przekazać tylko i wyłącznie adres do pierwszego elementu tablicy, podając nazwę tablicy bez indeksu. Przykład: int main ( void ){ int tab [10]; func ( tab ); return 0; } 3 sposoby deklaracji funkcji func(): void func ( int *x); void func ( int x [10]) ; void func ( int x []) ; Wewnątrz funkcji func() wyrażenie sizeof x zwraca rozmiar wskaźnika, nie tablicy. (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 35 / 37
Funkcje - przekazywanie tablic W języku C nie można (i nie trzeba) przekazać do funkcji całej tablicy. Do funkcji można przekazać tylko i wyłącznie adres do pierwszego elementu tablicy, podając nazwę tablicy bez indeksu. Przykład: int main ( void ){ int tab [10]; func ( tab ); return 0; } Wewnątrz funkcji func() wyrażenie sizeof x zwraca rozmiar wskaźnika, nie tablicy. Rozmiar tablicy musimy przekazać jawnie: void func ( int *x, int roz ); void func ( int x [10], int roz ); void func ( int x[], int roz ); (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 36 / 37
Funkcje - przekazywanie tablic Przykład: # define SIZE 10 int sump ( int * start, int * end ) { int total = 0; while ( start < end ) total += * start ++; return total ; }... int tab [ SIZE ] = {20,10,5,39,4,16,19,26,31,20}; int sum = sump ( tab, tab + SIZE ); (Wykład 4) Tablice, funkcje, wskaźniki - wprowadzenie 19 listopada 2018 37 / 37