Ukazatele
Ukazatel, neboli pointer je proměnná se zvláštním významem. Neukládá běžné hodnoty, na které jsme zvyklí z jednoduchých datových typů, ale ukládá adresu jiné proměnné, datové struktury, nebo funkce.
Deklarace a datový typ ukazatele
Ukazatel je vždy svázán s určitým datovým typem. Není to jen "ukazatel", ale je to "ukazatel na", proto když deklarujeme ukazatel, uvádíme i datový typ proměnné, na kterou ukazuje. Proměnnou, která je ukazatelem, definujeme pomocí hvězdičky před jejím názvem.
dat_typ *identifikator;
Příklad: Deklarace ukazatele
int a; // Deklarace proměnné a
int *p1; // Deklarace ukazatele p1
// Stejně jako u jiných proměnných, není hodnota p1 definována
Operátory pro práci s ukazateli
Aby jsme mohli ukazatel prakticky využít, musíme do něj nejdříve uložit adresu na proměnnou určitého typu. Zároveň je přirozeně potřeba pracovat s hodnotou, která je uložena na místě, kam ukazatel fakticky ukazuje. K tomu slouží unární operátory reference (&) a dereference (*)
& | Reference - adresa | Získá adresu proměnné uvedené jako pravý operand |
* | Dereference - hodnota | Pracuje s hodnotou na kterou ukazuje ukazatel |
Příklad: Inicializace a přiřazení hodnot
int a;
int *p1 = &a; // Přiřazení adresy proměnné "a" do ukazatele p1
*p1 = 10; // Přiřazení hodnoty 10 do proměnné "a" skrze ukazatel
Aritmetické a logické operace s operátory
S ukazateli můžeme podobně jako s ostatními proměnnými provádět určité operace. Tyto operace jsou ale značně omezené a mají svůj specifický význam. Jejich využití je nejobvyklejší pri práci se sekvenčními daty, jako jsou obecná pole a řetězce.
Rozdíl ukazatelů stejného typu: | Získáme vzdálenost dvou ukazatelů v počtu položek typu, na který ukazatel ukazuje. Když si paměť představíme jako pole stejného typu, tak rozdíl ukazatelů je jako odečtení dvou indexů tohoto pole. |
Přičtení/odečtení celého čísla od ukazatele: | Celé číslo v tomto případě představuje počet položek, o které se ukazatel v paměti posune. Opět si můžeme ukazatel představit jako index do pole, a přičtení čísla jako sčítání dvou indexů. |
Porovnání dvou ukazatelů stejného typu: | Ukazatele stejného typu lze mezi sebou porovnávat pomocí relačních operátorů. |
Příklad: Vynulování pole
int arr[10];
int *polozka = arr; // arr odpovídá ukazateli na začátek pole
int *konec = polozka + 10; // konec ukazuje na položku za koncem pole (arr[10])
while (polozka < konec) { // Porovnání dvou ukazatelů
*polozka = 0; // Nastavení hodnoty položky na 0
polozka++; // Posun ukazatele o jednu položku
}
Null ukazatel
Null, nebo nil je speciální hodnota ukazatele, která znamená, že ukazatel neukazuje nikam. V jazyce C a C++ je to standardně ukazatel s hodnotou 0, nebo lze použít konstantu NULL definovanou např. v hlavičkovém souboru stdlib.h/cstdlib. Pokud zkusíme dereferencovat ukazatel s hodnotou NULL, dojde k běhové chybě známé jako "chyba segmentace".
Ukazatel typu void
Můžeme vytvořit ukazatel typu void, o takovém ukazateli říkáme, že je nespecifikovaného typu a velikosti. Hodí se jako univerzální ukazatel. V případě pokusu o dereferenci takového ukazatele nastane chyba. Abychom mohli využít hodnotu odkazovanou ukazatelem typu void, musíme tento ukazatel nejdříve přetypovat.