Jsou deklarované mimo těla funkcí.
Existují po celou dobu běhu programu (vznikají při jeho spuštění, zanikají při jeho ukončení).
Deklarované uvnitř bloku (mezi {}, např. v těle funkce).
Existují jen po dobu provádění příkazů daného bloku (vznikají, když program vstoupí do bloku, zanikají při jeho ukončení).
Jsou uložené v paměti na zásobníku (stack).
Vytvoříme je operátorem new v místě programu, kde je potřebujeme.
Zrušíme je operátorem delete ve chvíli, kdy je přestaneme potřebovat.
Jsou uložené v části paměti zvané halda (heap).
Nemají jméno, mají definovaný typ a víme, kde přesně se v paměti nachází (známe adresu).
Na obsah proměnné se budeme odkazovat ukazatelem.
Při spuštění programu se jeho .EXE soubor umístí do paměti.
Program se skládá z kódového a datového segmentu.
Program požádá OS o další paměť pro zásobník (stack) a haldu (heap).
V programech, které jsme tvořili dříve, byla veškerá potřebná paměť určena již před spuštěním programu, a to definováním potřebných proměnných. Mohou však nastat případy, kdy lze potřebnou paměť programu určit až za běhu. Například když potřebná paměť závisí na vstupu od uživatele. Pro tyto případy potřebují programy dynamicky alokovat paměť, k čemuž použijeme operátory new a delete.
Jaký je rozdíl mezi klasickou proměnnou a dynamickou proměnnou?
Pro běžné proměnné, jako je int a, char str[10] atd., je paměť alokována a dealokována automaticky. U dynamických proměnných je zodpovědností programátora, aby paměť dealokoval, pokud již není potřeba. Pokud programátor paměť nedealokuje, způsobí tím únik paměti (paměť se nedealokuje, dokud se program neukončí).
Dynamickou proměnnou vytvoříme pomocí operátoru new.
Za new následuje datový typ, v případě pole také počet prvků v hranatých závorkách [].
Operátor new vrací ukazatel na začátek nového bloku alokované paměti pro danou proměnnou.
Syntax:
ukazatel = new datový_typ;
ukazatel = new datový_typ[počet_prvků];
Příklad:
int *prom;
prom = new int;
//Lze zapsat i jako:
int *prom = new int;
Systém dynamicky alokuje místo pro prvek typu int, vrátí ukazatel na tento prvek a uloží jej do proměnné prom (ukazatel).
Jelikož je prom ukazatel, lze k hodnotě proměnné, na kterou ukazuje, přistupovat pomocí výrazu *prom.
Např.: *prom = 120;
Příklad:
int *prom;
prom = new int[5];
//Lze zapsat i jako:
int *prom = new int[5];
V tomto případě systém dynamicky alokuje místo pro pět prvků typu int, vrátí ukazatel na první prvek posloupnosti a uloží jej proměnné prom (ukazatel).
Proto nyní prom ukazuje na platný blok paměti s prostorem pro pět prvků typu int.
Jelikož je prom ukazatel, lze k prvnímu prvku, na který ukazuje, přistupovat buď pomocí výrazu prom[0], nebo výrazu *prom (oba jsou ekvivalentní). K druhému prvku lze přistupovat buď pomocí výrazu prom[1], nebo *(prom+1), atd.
Nejdůležitějším rozdílem je, že velikost běžného pole musí být konstantní výraz, a proto musí být jeho velikost určena v okamžiku návrhu programu, před jeho spuštěním.
Dynamická alokace paměti prováděná pomocí new umožňuje přidělit paměť za běhu pomocí libovolné proměnné hodnoty jako velikosti.
Dalším rozdílem je, že normální pole jsou dealokována kompilátorem (pokud je pole lokální, pak je dealokováno při ukončení funkce).
Dynamicky alokovaná pole musí dealokovat programátor, nebo jsou dealokována až při ukončení programu.
Ve většině případů je dynamicky alokovaná paměť potřebná pouze v určitých částech programu; jakmile již není potřeba, měli bychom paměť uvolnit, aby byla opět k dispozici pro další požadavky. K tomuto slouží operátor delete.
Syntax:
delete ukazatel;
delete[] ukazatel;
První příkaz uvolňuje paměť alokovanou pro jedenu proměnnou,
druhý příkaz uvloňuje paměť, která byla alokována pro pole.
Příklad:
int *p = new int;
//práce s datovou proměnnou
delete p;
Abychom měli v haldě místo pro další dynamické proměnné.
Abychom "čtenářům" (spolupracovníkům) našeho programu naznačili, že již tyto proměnné opravdu nepotřebujeme.
Programátor si musí ve svých programech udržovat pořádek. Ten, kdo se ve svých programech sám nevyzná, je nepoužitelný pro týmovou práci!
Místo, které doposud zabírala dynamická proměnná, na kterou ukazuje ukazatel p, je nabídnuto k vytváření nových dynamických proměnných.
Volání funkce delete p; na obrázku operační paměti vůbec nic nezmění.
Dynamická proměnná s hodnotou 32 je sice zrušena a její místo je nabídnuto k vytváření nových dynamických proměnných, ale:
Hodnota 32 v paměti zatím zůstává.
Ukazatel p stále ukazuje do stejných míst.
Programátor již dynamickou proměnnou nesmí použít! Už mu to místo nepatří a za chvíli se tam klidně objeví něco jiného.
Hodnotu proměnné typu ukazatel můžeme přiřadit do jiné proměnné stejného typu.
Výstup:
11
Příkaz r = p; lze provést jen s přetypováním.
Rozdíl mezi příkazy s = p; a *s = *p;
Do proměnné typu ukazatel (libovolného typu) lze přiřadit speciální hodnotu NULL.
Význam hodnoty NULL: ukazatel nikam neukazuje!
p = NULL; s = NULL;
Programátor si tím poznačuje, že ukazatel momentálně neukazuje na žádnou dynamickou proměnnou.
Používá se při tvorbě dynamických datových struktur.
Porovnávání hodnoty ukazatelů: Lze porovnat dva ukazatele na rovnost nebo nerovnost, abychom zjistili, zda ukazují na stejnou paměťovou adresu.
2. Porovnání hodnot ukazatelů na NULL: Můžeme také porovnávat ukazatele s hodnotou NULL, abychom zjistili, zda jsou ukazatele neinicializované.
3. Porovnání ukazatelů na různé typy: Nelze přímo porovnávat ukazatele na různé datové typy, protože typ ukazatele ovlivňuje interpretaci paměťové adresy.
4. Ukazatele na dynamické objekty: Pokud máme dvě dynamické proměnné a chceme porovnat jejich obsah, tak musíme porovnávat obsah, na který ukazatele odkazují, nikoli samotné ukazatele.
Vytvoř program, který požádá uživatele o zadání 10 celých čísel. Po jejich zadání se na obrazovku vypíše jejich aritmetický průměr.
V programu můžeš nadefinovat jen proměnné typu ukazatel! Tedy všechny další potřebné proměnné musí být vytvořeny dynamicky.
Žrout paměti: Napiš program, který bude opakovaně "do nekonečna" vytvářet nové dynamické proměnné a vracet ukazatel stále do jediné proměnné. Průběžně vypisuj, kolik dynamických proměnných jsi již vyrobil. Co se asi stane, až v haldě žádné volné místo nebude?