A1PRG - Programování – Seminář Ing. Michal Ukazatele a pole 10 Verze
Agenda Ukazatele Nulový ukazatel Obecný ukazatel Aritmetika ukazatelů Dynamické přidělování paměti
Ukazatel Při dosavadní práci s proměnnými použity tzv. statické proměnné. Ukazatel (Pointer) je proměnná, která představuje adresu v paměti, na které je uložena skutečná hodnota.
Ukazatel Ukazatel je proměnná Neobsahuje hodnotu, ale pouze paměťovou adresu Zajímá nás hodnota ležící na adrese, kterou definuje Každý ukazatel ukazuje na určitý datový typ (ukazatel na celé číslo, …)
Ukazatel Pojmy: Adresa ukazatele Obsah ukazatele / Hodnota ukazatele Hodnota na níž ukazatel ukazuje
Operátory Operátor reference Operátor:& Význam:Vrací adresu proměnné Operátor dereference Operátor:* Význam:Vrací obsah zadané adresy
Příklad 1 PříkazObsah na adrese 10 (&i)20 (&p_i1)30 (&p_i2) i = 1; 1?? p_i1 = &i; 110? *p_i1 = 2; 210? i = *p_i1 + 1; 310? p_i2 = &p_i1; int i; int *p_i1; int *p_i2;
Příklad 2 #include "stdafx.h" #include int _tmain(int argc, _TCHAR* argv[]) { int i, j, *p_i; scanf("%d %d",&i,&j); p_i = (i > j) ? &i : &j; printf("Vetsi je %d na adrese %p",*p_i,p_i); getch(); return 0; }
Nulový ukazatel Symbolická konstanta NULL Lze přiřadit libovolnému ukazateli bez ohledu na datový typ Označení, že ukazatel „neukazuje nikam“
Nulový ukazatel Příklad: Otevření neexistujícího souboru (v případě, že soubor neexistuje, vrací funkce hodnotu NULL): FILE *f; f = fopen(″soubor.txt″,″r″); if (f == NULL) printf(″Soubor neexistuje″);
Obecný ukazatel Generický ukazatel na typ void Po správném přetypování může ukazovat na data libovolného typu
Obecný ukazatel void *p; int a = 5; double b = 2.8e36; p = &a; * (int *) p = 7; p = &b; * (double *) p = 12.83;
Příklad Funkce pro záměnu dvou proměnných void zamen(int *p_i, int *p_j) { int pom; pom = *p_i; *p_i = *p_j; *p_j = pom; }
Aritmetika ukazatelů Součet (a rozdíl) ukazatele a celého čísla Rozdíl ukazatelů Porovnání ukazatelů
Aritmetika ukazatelů Součet (a rozdíl) ukazatele a celého čísla: Přičtením celého čísla k ukazateli vzniká ukazatel nový. Nový ukazatel bude ukazovat o N adres dále. Pokud ukazatel bude ukazovat na prvek struktury, která v paměti zabírá 10 B, přičtením 1 bude nový ukazatel ukazovat o 10 B dále. Př. int *p_i; p_i = p_i + 1;
Aritmetika ukazatelů Rozdíl ukazatelů: Vrací počet údajů, které leží mezi prvním a druhým ukazatelem. Rozdíl ukazatelů má smysl například u polí Porovnání ukazatelů (==): Vrací hodnotu 1, pokud ukazatele ukazují na stejné místo v paměti. U polí možno použít i další relační operátory.
Dynamické přidělování paměti Umožňuje uživateli řídit přidělování paměti Paměť je přidělována z tzv. hromady (heap) Problém: přidělování paměti tak, aby nedošlo ke kolizi s ostatními daty. Přidělení paměti pomocí funkce malloc(). Uvolnění paměti pomocí funkce free().
Dynamické přidělování paměti Funkce malloc() Rezervace paměti Jediný parametr typu unsigned int – počet bytů Návratová hodnota: ukazatel na typ void – obsahuje adresu prvního prvku v paměti Je vhodné přetypovat na potřebný datový typ Není-li v paměti dostatek místa pro přidělení žádaného úseku, vrací hodnotu NULL
Dynamické přidělování paměti Funkce free() Uvolnění paměti Parametrem je ukazatel na typ void
Dynamické přidělování paměti Příklad: int *p_i; if ((p_i = (int *)malloc(sizeof(int))) == NULL) { printf("Nedostatek pameti!"); }else{ printf("Zadejte celociselnou hodnotu: "); scanf("%d", p_i); printf("Zadana hodnota: %d",*p_i); free(p_i); }
Dynamické přidělování paměti Funkce calloc() Alokace paměti pro určitý počet prvků dané velikosti Parametry: Počet prvků Velikost jednoho prvku - počet bytů Návratová hodnota: ukazatel na typ void – obsahuje adresu prvního prvku v paměti
Dynamické přidělování paměti Funkce calloc() Srovnání s funkcí malloc() malloc ( n * size ); calloc ( n, size );
Pole „Struktura“ složená se stejných prvků Jednotlivé prvky indexujeme od 0 Př.: int x[10]; x[0] = 10; for (int i = 0; i < 10; i++) { x[i] = i; }
Statické pole Nevýhoda: nutno zadat konstantní rozměr pole Př.: int x[10]; x[0] = 10; for (int i = 0; i < 10; i++) { x[i] = i; }
Dynamické pole Možnost zadat rozměr pole na základě proměnné. Definice pomocí malloc() (popř. calloc()) Př.: int *x; x = (int *) malloc(10*sizeof(int)); for (int i = 0; i < 10; i++) { *(x+i) = i; }
Statické / dynamické pole AkceStatické poleDynamické pole Definice int x[5];int *x; x = malloc(5*sizeof(int)) Naplnění n-tého prvku pole hodnotou x[n] = 5;*(x + n) = 5; Adresa n-tého prvku (např. u příkazu scanf) scanf("%d",&x[n]);scanf("%d",(x+n)); Uvolnění paměti free(x)
Vícerozměrná pole Jazyk C umožňuje definici pole s vyšší dimenzí než 1. Dvourozměrné pole: int x[10][10]; for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { x[i][j] = 0; }
Vícerozměrná pole Trojrozměrné pole: int x[10][10][10]; for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { for (int k = 0; k < 10; k++) { x[i][j][k] = 0; }
Vícerozměrná pole Statické pole int pole[2][2]; Po celou dobu má rozměr 2x2 Polostatické pole int *pole[2]; pole[0] = (int *)malloc(4*sizeof(int)); pole[1] = (int *)malloc(8*sizeof(int)); Počet řádků neměnná, každý řádek má různý počet prvků
Vícerozměrná pole Dynamické pole int **pole; pole = (int **) malloc(2*sizeof(int *)); pole[0] = (int *)malloc(4*sizeof(int)); pole[1] = (int *)malloc(8*sizeof(int)); Zcela flexibilní
Vícerozměrná pole Transformace dvourozměrného pole na jednorozměrné int *pole; int r = 3; int s = 2; pole = (int *)malloc(r*s*sizeof(int)); //přístup k pole[2][1] *(pole + (2*s + 1)) = 5;
Inicializace pole Hodnoty uvádíme ve složených závorkách int x[3] = {2, 3, 5}; int y[] = {1, 2}; Pokud v inicializaci uvedeme méně prvků, zbylé jsou inicializovány na 0 int x[3] = {2, 3}; Na druhou stranu není možné uvést prvků více: int y[2] = {1, 2, 4};
Inicializace pole Vícerozměrné pole int x[][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };
A1PRG-s10. Ukazatele a pole Děkuji za pozornost Ing. Michal Heczko 218/U3 Prezentace k dispozici na