Kurz C++, Lekce 3
Jiří Pipošiar, 7.6.2003

Co jsou to ukazatele
Ukazatele, jak už název napovídá, na něco ukazují. Můžou ukazovat na různé proměnné, objekty nebo dokonce i na funkce. Ukazatel je sám o sobě 32bitová proměnná(na systémech Windows), jehož hodnota je adresa nějakého jiného objektu. No a adresou se rozumí nějaké číslo, které reprezentuje určitou pozici v operační paměti počítače.
V reálném módu (v systému MS-DOS) je adresa reprezentována jako segment:offset, a lze ji zapsat jako 0x15FB:FF11. Obě části mají po 2Bytech.
Naproti tomu v chráněném módu (charakteristický pro systémy Windows) je uložena v podobě selektor:offset. Selektor je 2Bytový index v tabulce adres, je to obdoba segmentu, pouze zde je to index do tabulky s adresami segmentů. Offset má 4Byty a je to posun vůči začátku segmentu. V tomto módu se používá pouze offset adresy.

Jednoduchý ukazatel lze vytvořit například takto:

int* pNumber = NULL; //Vytvori ukazatel
int number = 100;
pNumber = &number;//Priradi mu adresu promenne number
cout <<"Promenna number ma hodnotu " << number
     << " a jeji adresa je " << &number <<endl;

cout <<"Promenna pNumber ma hodnotu " << pNumber
     <<" a jeji adresa je " <<&pNumber
     <<"\nA hodnota v promenne na kterou ukazuje je "
     <<*pNumber;


Teď si to postupně vysvětlíme. Tak na prvním řádku vytváříme ukazatel. Děje se to tak, že za typ proměnné umístíme znak hvězdičky (*). To upozorní překladač že se nebude jednat o obyčejnou proměnnou, ale o ukazatel. Proč mu ale hned přiřazujeme nějakou hodnotu, a proč je to zrovna NULL? NULL je samo o sobě makro definující nulu(0). No a děje se tak proto, abychom zabranili možným pozdějším problémům (kterým se ale v tomto přehledném příkladu snad ani nelze dopustit) jako např. přiřazení hodnoty do neinicializovaného ukazatele.
Pokud bychom totiž vynechali přiřazení oné nuly, byla by poté v tomto ukazateli opět nespecifikovatelná hodnota. Takže tento ukazatel by pak mohl ukazovat skoro kamkoli, třeba do paměti sloužící jinému programu. Kdybychom pak chtěli pomocí tohoto ukazatele zkusit změnit hodnotu v proměnné, na kterou měl ukazovat (avšak neukazuje), došlo by k tomu nejhoršímu - mohla by se přepsat pamět jiného běžícího procesu a pokud by na to Windows nebo jiný systém nepřišel a nezastavil to, tak by onen program(proces) mohl začít pracovat záhadně a hlavně nesprávně.
Na dalším řádku vytváříme obyčejnou celočíselnou proměnnou, jejíž hodnotu hned nastavíme na 100.
No a konečně přicházíme k tomu důležitému - inicializaci ukazatele správnou adresou. Jak je vidět, adresu jakéhokoli objektu lze zjistit tak, že před něj umístíme znak "&". Od teď ukazatel pNumber ukazuje na proměnnou number.
Na dalších řádcích si jen ověřujeme, zda to tak opravdu je. Pokud program přeložite a spustíte, uvidíte že hodnota ukazatele je opravdu schodná s adresou proměnné number. Také je zde vidět že i sám ukazatel je někde uložen, tedy má svoji vlastní adresu, která je odlišná od adresy number.

Pokud budete chtit zjistit nebo změnit hodnotu proměnné, na kterou ukazatel ukazuje, použijete operaci zvanou dereferencování ukazatele. Zní to strašlivě, ale je to jednoduché. Pouze před název ukazatele umístíte hvězdičku a je to. Takže potom pNumber bude adresa, ale *pNumber bude hodnota na této adrese uložená.

Konstantní ukazatele
Používá se v případě, pokud nechcete nebo aby se změnila adresa umístěná v ukazateli, neboli jeho hodnota. Umožňuje však změnit hodnotu proměnné na kerou ukazuje. To ho odlišuje od ukazatele na konstantu popsaném níže.
Konstantní ukazatel lze deklarovat takto:

int number = 1000;
int* const cpNumber = &number; //Vytvori konst. ukazatel
int hours = 24;

cpNumber = &hours;//CHYBA, snaha zmenit hodnotu konstanty
*cpNumber = 2000; //Toto je mozne

Pokud už se vám to začíná trochu plést, tak se ničeho neděste, zatim je to v pohodě. Uvidíte, za chvíli z toho asi budete mít hlavu jako pytel od banánů :)) Tohle bude jen procházka růžovým sadem. To pravé ořechové přijde až s ukazately na funkce ;)

Ukazatele na konstantu
Jak už sem zmínil výše, je to opak konstantního ukazatele. Zde se nesmí pomocí ukazatele měnit hodnota proměnné, na kterou ukazuje. Samotnou proměnnou však můžeme přímo změnit. A to, že se jedná o ukazatel na konstantu neznamená, že se nutně musí jednat jen o konstantu.
Uvedeme si menší příklad:

int money = 100;
const int cMonth = 12;
const int* pPointer = &money; //Vytvori ukaz. na konstantu
money = 200; //Toto funguje
*pPointer = 300; //Toto uz ale ne
pPointer = &cMonth; //Priradime adresu konstanty
cMonth = 200; //CHYBA, nelze menit hodnotu konstatny
*pPointer = 300; //Take chyba, jak jinak

Co když ale máme obyčejný ukazatel, a přiřadíme mu adresu konstanty? Tak toto překladač samozřejmě nesmí dovolit, a také nedovolí, protože pak bychom hodnotu této konstanty mohli pomocí tohoto ukazatele měnit.
Z výše uvedeného kódu ještě vyplývá, že opravdu ukazatel na konstantu nemusí nutně na konstantu ukazovat, jen se pomocí něho nesmí měnit její hodnota.

Kurz C++, Lekce 2 Seznam lekcí Kurz C++, Lekce 4