Dynamické premenné
        
        Premenné  
 Globálne premenné:  
 * vzniknú pri spustení programu 
 * existujú počas behu programu 
 * zanikajú pri skočení programu 
 * počas kompilácie sa rozhodne, kde v pamäti budú takéto premenné umiestnené.  
 Lokálne premenné (a parametre):  
 * vznikajú pri zavolaní funkcie 
 * existujú počas vykonávania funkcie 
 * zaniknú pri skončení funkcie 
 * vznikajú v časti pamäte, ktorej hovoríme zásobník.  
 Veľkosť (počet bajtov) globálnej a lokálnej premennej je určená už počas kompilácie programu.  
 Niekedy je výhodné, ak môžeme riadiť vznikanie a zanikanie premenných a to hlavne takých, ktoré:  
 * nemajú v čase kompilácie programu presne stanovenú veľkosť 
 * počas behu programu menia svoju veľkosť (zoznamy) 
 * v pamäti zaberajú veľa miesta (veľké objekty, štruktúry, obrázky), a pritom potrebujeme iba na určitú dobu.  
 Dynamické premenné:  
 * ich vznik a zánik riadime pomocou príkazov 
 * vytvoríme ju v okamihu, keď premennú potrebujeme 
 * zrušíme ju, keď už premennú nepotrebujeme 
 * vznikajú v časti pamäte, ktorú nazývame halda (anglicky heap).   
 Dynamické premenné  
 Pri kompilácii sa nedá presne určiť, kde v pamäti dynamická premenná vznikne - aká bude jej adresa. Preto pri práci s dynamickými premennými používame smerníky, ktoré na dynamické premenné ukazujú:  
 float *p; // smerník na premennú typu float 
 p=new float; // vytvoríme premennú typu float a jej adresu uložíme do smerníka p 
 *p=3.14; // teraz môžeme pracovať s dynamickou premennou *p (priradíme hodnotu) 
 Caption=FloatToStr(*p); 
 delete p; // zrušíme dynamickú premennú  
 * Operátor new nájde v halde voľné miesto, na ktorom vytvorí dynamickú premennú uvedeného typu. Výsledkom operátora je smerník na novovzniknutú dynamickú premennú. 
 * S dynamickou premennou ďalej pracujeme pomocou smerníka. 
 * Operátor delete zruší dynamickú premennú - uvoľní v halde pamäťové miesto. Od tohto okamihu smerník ukazuje na neexistujúcu premennú (pozor, v smerníku nebude hodnota NULL).  
 Pozn.: z dôvodu kompatibility typov nasledujúce neskompilujeme: 
 p=new int; … chyba 
 Smerník na premennú typu float nie je kompatibilný so smerníkom na premennú typu int - výsledkom operácie new int je smerník na celočíselná premenná.   
 Pravidlá a odporúčania pri práci s dynamickou premennou  
 1. Po zrušení dynamickej premennej už s touto premennou nesmieme pracovať - čiže, nesmieme:  
 p=new float; 
 delete p; 
 Caption=FloatToStr(*p); ... premenná, ktorá bola na adrese p už neexistuje  
 Kompilátor príkazy preloží, ale chyba sa vyskytne až pri vykonávaní posledného príkazu, ktorý zisťuje obsah už neexistujúcej premennej (uvoľnené pamäťové miesto sa použije na niečo iné).  
 2. Nesmieme vykonať viacnásobné zrušenie jednej dynamickej premennej:  
 p=new float; 
 delete p; // zrušíme premennú *p 
 delete p; ... nesmieme zrušiť neexistujúcu premennú  
 Podobne, ako v predchádzajúcom príklade, aj tieto príkazy sa skompilujú, avšak chyba sa môže prejaviť až pri behu programu.  
 Treba si zapamätať pravidlo:  
 Každú premennú vytvorenú príkazom new musíme zrušiť príkazom delete.  
 3. Ak je šanca, že v programe budeme rušiť tú istú dynamickú premennú na viacerých miestach, potom používame nasledovnú možnosť: 
 p=new float; 
 ... 
 delete p; // zrušíme premennú *p 
 p=NULL; // smerník neukazuje na žiadnu premennú 
 ... 
 delete p; // ak p ukazuje na dynamickú premennú, týmto príkazom ju zrušíme, ak je p==NULL, nič sa nestane 
 p=NULL;  
 4. V programoch môžeme použiť smerník aj viackrát:  
 p=new float; 
 delete p; 
 p=new float; 
 delete p;  
 5. Dávajte si pozor na nasledujúce:  
 p=new float; 
 p=new float; // ... stratili sme adresu predchádzajúcej dynamickej premennej 
 delete p; 
 ... teraz už nesmieme vykonať: delete p ... predchádzajúcim príkazom sme dynamickú premennú, na ktorú smerník p ukazoval, už zrušili.   
 Príklady s dynamickými premennými  
 Objekt ako dynamická premenná:  
 TKor *k; 
 k=new TKor; // vytvoríme objekt 
 k->dp(100); 
 delete k; // zrušíme objekt  
 Pole smerníkov:  
 int i,*a[100]; // a je pole smerníkov na celé čísla 
 for (i=0; i<100; i++) a[i]=new int; // vytvoríme 100 dynamických premenných 
 for (i=0; i<100; i++) *a[i]= ... ; // až teraz môžeme s jednotlivými dynamickými premennými pracovať 
 for (i=0; i<100; i++) delete a[i]; // zrušíme všetky dynamické premenné  
 Štruktúra, ktorá obsahuje smerníky:  
 struct TTest { // zadefinujeme štruktúru TTest 
 char znak; // znak 
 int *cislo; // smerník na číslo 
 };  
 Príklad 1.: 
 TTest X, Y; 
 X.znak='a'; 
 X.cislo=new int; 
 *X.cislo=1234; 
 Y=X; 
 delete X.cislo;  
 Teraz už nesmieme: 
 delete Y.cislo 
 lebo smerník Y.cislo už ukazuje na neexistujúcu premennú.  
 Príklad 2.: rušenie viacerých dynamických premenných: 
 TTest *Z; 
 Z=new TTest; // Z ukazuje na dynamickú premennú typu TTest 
 Z->cislo=new int; // Z->cislo ukazuje na dynamickú premennú typu int 
 Z->znak='a'; 
 *Z->cislo=0; 
 // tu niečo robíme ... 
 delete Z->cislo; // najskôr uvoľníme dynamickú premennú, na ktorú ukazuje Z->cislo 
 delete Z; // až potom uvoľnime dynamickú premennú, na ktorú ukazuje Z  
 Dynamické premenné nesmieme rušiť v takomto poradí: 
 delete Z; 
 delete Z->cislo; ... lebo Z už ukazuje na neexistujúcu dynamickú premennú   
 Dynamicky vytvorené pole  
 V C++ môžeme pomocou operátora new vytvoriť aj viacero dynamických premenných rovnakého typu, ktoré ležia v pamäti za sebou, a teda tvoria pole. Pole, ktoré takto vznikne, nazveme dynamicky vytvorené pole: 
 int i,*p; 
 p=new int[10]; 
 // vznikne 10 celočíselných premenných, ktoré sú v pamäti uložené za sebou - to je pole 
 // premenná p ukazuje na 0. prvok poľa 
 for (i=0; i<10; i++) p[i] = ... ; 
 delete[] p; // zrušíme celé pole (všetkých 10 premenných)  
 Dynamické pole ako zoznam: 
 TKor *zoz=NULL; // smerník na zoznam - na začiatok poľa korytnačiek 
 int poc=0; // počet prvkov v zozname  
 void __fastcall TForm1::Timer1Timer(TObject *Sender) 
 { 
 for (int i=0; i<poc; i++) { 
 zoz[i].dp(1); 
 zoz[i].vl(random(30)); 
 } 
 }  
 void __fastcall TForm1::FormDestroy(TObject *Sender) 
 { 
 delete[] zoz; 
 }  
 void __fastcall TForm1::Image1MouseDown(TObject *Sender, TMouseButton Button, 
 TShiftState Shift, int X, int Y) 
 { 
 TKor *pom; // zadeklarujeme pomocný smerník 
 pom=new TKor[poc+1]; // vytvoríme nové pole 
 for (int i=0; i<poc; i++) // skopírujeme prvky pôvodného zoznamu 
 pom[i]=zoz[i]; 
 pom[poc].Inic(Image1, X, Y); // inicializujeme novú korytnačku 
 pom[poc].Farba=TColor(random(0x1000000)) ; 
 delete[] zoz; // pôvodné pole zrušíme 
 zoz=pom; // zmeníme smerník tak, aby ukazoval na nové pole 
 poc++; 
 }   
 Zhrnutie  
 * s dynamickou premennou pracujeme pomocou smerníka 
 * dynamickú premennú vytvoríme: smerník = new typ 
 * dynamickú premennú zrušíme: delete smerník 
 * dynamické pole vytvoríme: smerník = new typ[dĺžka] 
 * dynamické pole zrušíme: delete[] smerník