Podstawy programowania 1 Krzysztof Grudzień kgrudzi@kis.p.lodz.pl Wykład nr 2 1
Plan spotkań Wskaźniki Tablice jednowymiarowe & wska źniki. Programowanie w C. Wikibooks 2
Co to jest wskaźnik?? Wskaźnik (ang. pointer) jest to specjalny rodzaj zmiennej. Zapisuje się w nim adres w pamięci komputera do zmiennej, na którą wskazuje ten wskaźnik. Zmienne wskazywane mogą być pojedynczymi zmiennymi, tablicami, strukturami i funkcjami. 3
Deklaracja wskaźnika int* pint_01 = NULL; oraz int *pint_01 = NULL; są równoważne. wskaźnik należy zawsze zainicjalizować przynajmniej adresem pustym NULL Wskaźnik można następnie zainincjalizować adresem zmiennej odpowiedniego typu, w tym przypadku integer: int izm_01 = 43; pint_01 = &izm; 4
Gdzie wykorzystywane są wskaźniki? Praca z tablicami. Funkcje zmiana wartości przesyłanych argumentów. Dostęp do specjalnych komórek pamięci. Rezerwacja obszarów pamięci. 5
Przykład printf( %d\n, izm_01); printf( %d\n, &izm_01);//%x printf( %d\n, &pint_01); printf( %d\n, pint_01); printf( %d\n, *pint_01); 6
Przykład 7
Przykład 8
Rzeczy ważne Wskaźnik, który pokazuje na obiekt jednego typu, nie może być wykorzystany do pokazywania na obiekt innego typu. int *wi,*wj; int i,j; wi=&i; i=5; *wi=5; j=7; j=*wi; wi=&j; wj=wi; Sama deklaracja wskaźnika nie powoduje, że wskaźnik wskazuje na konkretny obiekt. 9
Wskaźnik typu void wskaźnika bez podania typu obiektu, na jaki wskazuje. Może być użyty do wskazywania na obiekty dowolnego typu. void *pv; 10
Wskaźnikowi typu void można przypisać wskaźnik dowolnego (niestałego) typu. Działanie odwrotne wymaga operatora rzutowania void *wv; int *wi; float *wf; wv=wi; //teraz wskaźnik wv wskazuje na ten //sam obiekt (typu int), //na który wskazuje wskaźnik wi wv=wf; wi=wf //kompilator zasygnalizuje błąd!! wi=(int *)wf; //wykorzystanie rzutowania wf=(float *)wv; //wykorzystanie rzutowania 11
Zastosowanie wskaźników do tablic int *wsk=null; //definicja wskaźnika int tab[10]; //definicja tablicy wsk=&tab[indeks]; //ustawienie //wskaźnika na 0 9 //elemencie tablicy //o indeksie indeks wsk=&tab[0]; wsk=tab; instrukcje równoważne wsk=&tab[indeks]; wsk=wsk+ind; wsk += ind; przesunięcie wskaźnika o ind pozycji 12
Przykład 13
14
15
Dodanie do wskaźnika liczby całkowitej ind powoduje, że wskaźnik pokazuje o ind elementów dalej w tablicy; niezależnie od tego, jakiego typu są elementy tablicy. 16
Nazwa tablicy & wskaźnik Nazwa tablicy jest jednocześnie adresem jej zerowego elementu. Nazwa tablicy jest stałym wskaźnikiem do jej zerowego elementu. float *wsk; float tab[10]; wsk=tab; //wsk=&tab[0]; //możliwe jest //przypisanie wsk++;//ok tab++; //niemożliwa jest instrukcja 17
tab[ind]; odwołanie się do wartości elementu tablicy o nr ind adres *(tab+ind); Ustalenie adresu komórki przesuniętej o ind elementów w stosunku do początku tablicy i podanie wartości tam znajdującego się elementu 18
*(pint++) *(tab++) 19
Wskaźniki w argumentach funkcji void fun(float f) { f /= 3.3; } void main() { float fvar = 13.3; } fun(fvar); printf( %f\n, fvar); //?? 20
Wskaźniki w argumentach funkcji float fun(float *f) { *f /= 3.3; } void main() { float fvar = 13.3; fun(&fvar); printf( %f\n, fvar); // 4.03 } 21
Jak wygląda wysyłanie argumentów do funkcji przez wartość? void fun(float f) { f /= 3.3; } fun(fvar); 13.3 - kopia kopia zmiennej fvar 13.3 22
Jak wygląda wysyłanie argumentów do funkcji przez wartość? void fun(float *f) { *f /= 3.3; } element spod adresu 127 fun(&fvar); adres 127 - kopia kopia adresy zmiennej fvar 23
24
25
Przesyłanie tablic do funkcji #define ROZMIAR 10 long sumuj(int tab[], int n); int main() { int kulki[rozmiar]={1,44,5,23,22,47,7,6,90,11}; long wynik; wynik=sumuj(kulki,rozmiar); printf("calkowita liczba kulek wynosi: %ld. \n", wynik); printf("rozmiar tablicy kulki wynosi %d bajtow\n", sizeof kulki); system("pause"); return 0; } long sumuj(int tab[], int n) { int i; long suma=0; for(i=0;i<n;i++) suma+=tab[i]; } printf("rozmiar tablicy tab wynosi %d bajtow \n", sizeof tab); return suma; 26
uwagi Język C nie pozwala na przekazywanie tablic jako argumentów funkcji tab[i] i *(tab+i) równoważne Przekazując nazwę tablicy jako argument, przesyłamy do funkcji adres pierwszego elementu tablicy 27
Argumenty wskaźnikowe long sumuj(int *poczatek, int *koniec) { long suma=0; while(poczatek<koniec) { suma+=*poczatek; poczatek++; } return suma; }?? Jak wywołać funkcję?? 28
wynik=sumuj(kulki, kulki+rozmiar); suma+=*poczatek; poczatek++; suma+=*początek++; suma+=*(początek++); 29
void f1(int *pi, int rozm); void f2(int *pi, int rozm); void f3(int t[], int rozm); void main(){ int tab[5]={1,2,3,4,5}; f1(tab,5); f2(tab,5); f3(tab,5); } void f2(int *pi, int rozm){ printf("\nfunkcja f1\t ); for(int i=0;i<rozm;i++) print( %f\t,pi[i]); } void f3(int t[], int rozm){ printf("\nfunkcja f3\t ); for(int i=0;i<rozm;i++) print( %f\t,t[i])); } void f1(int *pi, int rozm) { printf("\nfunkcja f1\t ); for(int i=0;i<rozm;i++) printf( %f\t,*(pi++)); } 30
Istnieje wybór między korzystaniem notacji tablicowej lub wskaźnikowej Tablicowa: widać, że przetwarzamy tablicę podobna notacja do innych języków Wskaźnikowa: Bliższa językowi maszynowemu wydajniejszy kod 31
Działania na wskaźnikach Przypisanie pint=&a; pint=tab; Pobranie wartości *pint; uzyskanie adresu wskaźnika &pint; Zwiększenie/Zmniejszenie wskaźnika pint++; pint--; Odejmowanie a = pint1- pint2; A co z nazwa tablicy?? 32
Wskaźnik do stałych a stały wskaźnik Wskaźniki do stałych mogą zawierać adresy dowolnych zmiennych i mogą być modyfikowane w programie, ale nie można za ich pomocą modyfikować zmiennych wskazywanych. Stały wskaźnik to wskaźnik, który zawsze pokazuje na to samo. Wskaźnik tego typu musi być zainicjowany w miejscu definicji - tak jak każda stała. W programie nie można już modyfikować jego wartości. int zm = 10; int * const w = &zm; Za pomocą wskaźnika stałego można jednak modyfikować zawartość zmiennej wskazywanej, ale tylko tej, której adresem wskaźnik został zainicjowany. const int stala = 10; const int *wsk_st; 33
const int st = 4; int zm = 10; int * const w = &zm; int * const x = &st; const int * const x1 = &st; int i = 7; int * const wi = &i; int * const pz = &zm; *wi +=8; wi = &zm; 34
Łańcuchy znaków tablica jednowymiarowa char tab[20]; char *wsk=null; wsk=tab; 35
int main() { char tabc[20]="test"; char *pchar="test_wsk"; printf("%d - %s\n", sizeof(tabc),tabc); printf("%d - %s\n", sizeof(pchar), pchar); system("pause"); return 0; } 36
Definiowanie łańcucha Użycie stałej łańcuchowej Użycie tablicy typu char Użycie wskaźnika do char Użycie tablicy łańcuchów znaków 37
Stała łańcuchowa Ciąg znaków zakończonych znakiem \0 Stałe łańcuchowe należą do klasy statycznej jedna kopia, istnieją przez cały czas działania programu 38
Tablica znaków char tab[]= test ; char tab[]={ t, e, s, t, \0 }; rozróżnia tablicę znaków od łańcucha znaków tab --> &tab[0] *tab tab[0] *(tab+1) tab[1] 39
Przykład char tab[]= Jestem Jan ; char* pchar[]= Jestem Adam for(i=0;i<6;i++) putchar(tab[i]); putchar(pchar[i]); Jestem while(*pchar!= \0 ) putchar(*(pchar++)); Jestem Adam pchar=tab; tab=pchar; tab[3]= k ; *(tab+3)= k ; 40
41
Wczytywanie łańcuchów - scanf pobiera jedno słowo do napotkania znaku niedrukowanego %5s wczyta określoną liczbę znaków bądź napotka znak niedrukowany 42
funkcja scanf() zwraca liczbę odczytanych pozycji lub EOF dla końca pliku 43
Wczytywanie łańcuchów - gets Pobieranie znaków z wejścia, aż do napotkania \n \0 44
gets() char pchar=null; pchar = gets(imie); łańcuch znaków w tablicy imie wskaźnik na pierwszy element przekazywany do wskaźnika pchar. błąd odczyty pchar == NULL 45
fgets() kontrola przepełnienia tablicy?? char tab[3]; gets(tab) JANEK?? fgets: odczyt MAX 1 znaków fgets(tab, MAX, stdin); pobiera znak nowej linii 46
puts() Wyświetla dane od podane adresu aż do napotkania znaku \0 47
fputs pobiera 2 argumenty fgets(imie,stdin) nie dodaje znaku nowej linii do danych wyjściowych 48
Funkcje do obsługi łańcuchów znaków strlen() zwraca długość łańcucha znaków strlen(imie); Biblioteka: #include <string.h> char tabc[20]="test"; do { i++; 4 } while(i<strlen(tabc)); 49
strcat & strncat Łączenie łańcuchów znaków tabc==tabc+tabd Co z przekroczeniem rozmiaru?? 50
strncat(tabc,tabd,10); Skopiuje max. 10 znaków Kopiuje, aż do napotkania znaku \0 51
strcmp & strncmp Porównanie łańcuchów znaków tabc==tabd strcmp(tabc,tabd); Tylko porównanie adresów wpisów while(strcmp(pytanie, odp)); Porównuje tylko do napotkania znaku \0 strcmp( A, A ); zwraca 0 strcmp( A, B ); zwraca -1 strcmp( B, A ); zwraca 1 52
Jak porównać litery? If( a < b ) zamiana na kody ASCII char ch= m ; If (ch== w ) 53
strncmp strncmp(tabc,tabd,3); Porównuje łańcuchy, do 3 znaku, albo przerywa wcześniej gdy jest niezgodność. 54
Kopiowanie łańcuchów strcpy() & strncpy() char * strcpy ( char * destination, const char * source ); char tab1[]= test1 ; char tab2[]= test2 ; char* p1; char* p2; p1=tab1; p2=tab2; p1=p2; // jaki wynik operacji?? strcpy(p1,p2); 55
http://www.cplusplus.com/reference/cstring/strncpy/ char * strncpy ( char * destination, const char * source, size_t num ); 56
islower() - int islower ( int c ); 57
58