Ukazatel
K pokročilému programování v jazyce C patří práce s ukazately. Můžeme je použít jako parametry ve funkcích, při práci s polem, při dynamické alokaci paměti atd.
Ukazatel je proměnná jako ostatní, pouze hodnota v ní uložená má jiný význam, než jsme byli zvyklí dosud. V jazyce C je ukazatel přísně typový, t.j. deklarujeme ho jako ukazatel na určitý datový typ. Obsahem ukazatele je adresa v paměti. Při práci s ukazatelem nás ve většině případů zajímá hodnota, uložená na dané adrese.
Proměnná uk je ukazatel. Hodnota v něm uložená je 25. Jedná se o adresu, na které je uložená hodnota, se kterou budeme dále pracovat. Na absolutní adrese 25 je hodnota 18. Ukazatel uk ukazuje na hodnotu 18, ale sám má hodnotu 25.
Poznámka: Absolutní adresa proměnné uk není pro nás v programu většinou důležitá.
Příklady deklarace ukazatelů:
int *uk1, cislo = 5; //ukazatel na cele cislo
float *uk2; //ukazatel na realnou hodnotu
FILE *f; //promenna pro praci se souborem
Ukazatel po své deklaraci neukazuje na žádnou proměnnou (může tam být náhodná adresa), je třeba ho nastavit, jinak s ním nesmíme pracovat. Nastavení ukazatele můžeme provést např. adresním operátorem následovně:
uk = &cislo;
Uvedený příkaz nastaví hodnotu ukazatele uk1 na adresu proměnné cislo. Pokud chceme pracovat s hodnotou, na kterou ukazatel ukazuje (v našem případě 5), použijeme v programu zápis *uk1.
V jazyce C je v stdio.h definována konstanta NULL, která představuje prázdný (nulový) ukazatel. Můžeme ho použít při testování ukazatelů.
Dynamické přidělování paměti
V předchozí části jsme si přiblížili zápis ukazatelů v programu. Pro shrnutí připomenu, že ukazatel obsahuje vždy adresu místa paměti, s kterým chceme pracovat.
S pamětí pro proměnné můžeme pracovat staticky nebo dynamicky. Statický způsob je ten, kde používáme statické proměnné libovolných datových typů ve funkcích - když proměnnou deklarujeme, automaticky se přidělí paměť podle datového typu. Tato proměnná je v paměti, dokud nezanikne (do ukončení bloku nebo funkce, kde byla deklarována). Při dynamickém způsobu žádáme o paměť v průběhu programu podle toho, jak to potřebujeme. Když zjistíme, že potřebujeme např. pole o velikosti 100, požádáme o přidělení paměti pro 100 prvků. Podstatné je, že často nevíme, jestli budeme potřebovat prostor pro 10 nebo 1000 informací. Význam ukazatelů je zřejmý právě při dynamické práci s pamětí.
Při dynamické práci s pamětí žádáme o přidělení paměti v průběhu programu. K tomu použijeme funkci malloc(). Funkce má jeden parametr a to velikost požadované paměti (v Bytech). Funkce vrací ukazatel na začátek paměti, která nám byla přidělena.
float *uk; //ukazatel na realnou hodnotu
//prideleni pameti pro n realnych cisel - jde o dynamicke pole
uk = (float*) malloc (n * sizeof(float)) ;
//kontrola, jestli pamet byla pridelena
if( uk == NULL)
{
printf("Chyba - Pamet nebyla pridelena")
return -1;
}
Součástí dynamické práce s pamětí je samozřejmě i skutečnost, že když už paměť nepotřebujeme, uvolníme ji. K tomu použijeme funkci free(), její použití vidíme na následujícím příkladu.
free(uk); //uvolnění paměti pro ukazatel uk z predchoziho prikladu
uk = NULL; //"vynulování" ukazatele