22.Prednaska

Z Pascal
Prejsť na: navigácia, hľadanie
22. Prednáška

úlohy | cvičenie

Dynamické premenné

Doteraz sme sa väčšinou stretali s premennými, ktorým hovoríme statické - ich veľkosť a adresa v pamäti boli určené už počas kompilácie. Statickými premennými sú buď globálne premenné alebo lokálne:

  • globálne premenné (premenné hlavného programu, resp. všetkých programových jednotiek) sú kompilátorom vyhradené v jednom dátovom segmente, tieto premenné automaticky vznikajú pri štarte programu a sú inicializované hodnotou 0;
  • lokálne premenné (aj hodnotové parametre) podprogramov sa automaticky vyhradia pri volaní podprogramu (automaticky sa zrušia pri ukončení podprogramov) ale ich veľkosť a pozícia v pamäti (t.j. v systémovom zásobníku) sa určí počas kompilácie - už vieme, že majú neinicializovanú hodnotu.

Statické premenné nemôžu počas behu zmeniť svoju veľkosť a ani adresu (počas tzv. Run Time) - o ich vytvorenie a rušenie sa stará systém (pri spustení programu, resp. podprogramu).

Na rozdiel od týchto statických premenných má Pascal aj mechanizmus na vytváranie dynamických premenných:

  • vytváranie a rušenie takýchto premenných je v rukách programátora - do programu musí zapísať príkazy na vytváranie a rušenie premenných,
  • kým takúto premennú programátor nevytvorí, premenná neexistuje a zrejme sa s ňou nedá ani pracovať,
  • počas behu programu (Run Time) sa špeciálne na to určenými príkazmi môžu vytvárať a rušiť, sú to tzv. dynamické premenné,
  • takéto premenné sa nevytvárajú ani v dátovom segmente programu ani v zásobníku ale v špeciálne na to určenom segmente, v ktorom budú všetky dynamické premenné - tento dátový segment nazývame heap (zriedkavejšie aj po slovensky ako halda), jeho veľkosť závisí od OS - často je to niekoľko 100 MB.

S niektorými dynamickými premennými sme už pracovali aj doteraz, aj tu bol v rukách programátora mechanizmus na vytváranie a rušenie takýchto premenných, ale zatiaľ sme na to takto nepozerali:

  • dynamické pole (napr. var A: array of Integer;) - premennú vytvoríme napr. pomocou SetLength(A, 10); a zrušíme napr. príkazom A := nil;
  • znakový reťazec (napr. var S: string;) - vytvoríme napr. pomocou S := 'abcd'; a zrušíme napr. S := '';
  • objekt (napr. var R: TRobot;) - vytvoríme pomocou R := TRobot.Create; a zrušíme pomocou R.Free;

Pri dynamických poliach a znakových reťazcoch má Free Pascal mechanizmus, pri ktorom vie pracovať aj s prázdnou premennou, t.j. hoci sme premennú zrušili, môžeme ju používať, napr. S := ''; S := S + '*';

Aby sme v našich programoch mohli pracovať s dynamickými premennými, ktoré budú vznikať a počas behu sa rušiť, budeme na to používať odkazy na premenné. Už vieme, že sú to smerníky hoci sme zatiaľ s nimi pracovali len v prípadoch, keď odkazovali na nejaké statické premenné.



Štandardné procedúry New a Dispose



Uvidíme, že smerníkové premenné sa najčastejšie využívajú na prístup k dynamickým premenným. Využijeme štandardnú procedúru New, ktorá vytvorí novú dynamickú premennú a jej odkaz priradí do smerníkovej premennej. A tiež štandardnú procedúra Dispose, ktorá má opačnú funkciu ako procedúra New: zruší dynamickú premennú, na ktorú bol odkaz prostredníctvom nejakého smerníka. Obe tieto procedúry majú jeden formálny var-parameter, ktorým musí byť smerníková premenná.



Procedúra New



Volanie vyzerá, napr. takto

var
  SI: ^Integer;
begin
  New(SI);

Týmto volaním sa vytvorila nová celočíselná premenná (zatiaľ má nedefinovaný obsah) a jej odkaz sa priradil do smerníkovej premennej SI. Teraz môžeme pracovať s touto novou premennou prostredníctvom smerníka, napr. jej priradiť hodnotu, alebo jej hodnotu vypísať, napr.

  SI^ := 37;
  WriteLn('hodnota novej premennej = ', SI^);

Ak už predtým bola v tejto premennej priradená nejaká hodnota (odkaz na nejakú premennú), tak táto hodnota sa príkazom New zabúda. Aj smerníková premenná (tak ako aj každá iná) môže obsahovať jedinú hodnotu a každé ďalšie priradenie do tejto premennej starú hodnotu zabúda. So smerníkmi je to o to horšie, že ak v ňom máme uchovaný odkaz na nejakú dynamickú premennú, tak priradením inej hodnoty do tohto smerníka strácame možnosť pracovať s touto dynamickou premennou a už nikdy sa k nej nedostaneme. Týmto môžeme stratiť nielen nejaké údaje, ale aj časť pamäte, ktorá nám neskôr môže niekde chýbať. Napr.

var
  SI: ^Integer;
begin
  New(SI);
  SI^ := 37;
  New(SI);
  SI^ := 13;

V programe sa postupne vytvorili dve dynamické premenné: najprv prvá a do nej sa priradila hodnota 37, potom druhá a do nej sa priradila hodnota 13. Tým, že sme smerník SI použili aj pre odkaz na druhú premennú, pôvodne zapamätaný odkaz na premennú s 37 sa zabúda (táto premenná stále existuje) a až sa k nej nikdy nedostaneme.

Činnosť príkazu New(Smernik), pre var Smernik: ^Typ; môžeme zhrnúť takto:

  1. zabudne pôvodnú hodnotu premennej Smernik,
  2. vo voľnej časti pamäti (heap) vyhradí úsek veľkosti SizeOf(Typ), t.j. toľko bajtov, koľko bude zaberať táto nová dynamická premenná
    • vždy je to trochu viac (závisí od organizácie správy pamäti, ktorá sa stará o heap),
  3. do premennej Smernik priradí adresu tejto novej dynamickej premennej.

Začiatočníci niekedy robia takúto chybu:

var
  S1, S2: ^Integer;
begin
  New(S1);
  S1^ := 17;
  New(S2);
  S2 := S1;

Pravdepodobne v programe chceli dosiahnuť, aby druhá dynamická premenná (prístupná cez S2) mala rovnakú hodnotu ako prvá premenná (prístupná cez S1). V tomto prípade sa príkazom New(S2) vytvorila nová dynamická premenná, a hneď ďalším príkazom S2 := S1; sa adresa na ňu zahodila a teraz máme v S2 rovnakú adresu ako v S1. Pričom táto druhá premenná (vytvorená New(S2)) stále existuje, v pamäti má vyhradené miesto, ale stratili sme na ňu prístup. Program by mal správne vyzerať asi takto:

var
  S1, S2: ^Integer;
begin
  New(S1);
  S1^ := 17;
  New(S2);
  S2^ := S1^;



Procedúra Dispose



Štandardná procedúra Dispose slúži na rušenie dynamickej premennej. Procedúra má jeden formálny var-parameter, ktorým musí byť smerníková premenná. V tejto premennej musí byť odkaz na nejakú dynamickú premennú (vytvorenú pomocou New).

Činnosť príkazu Dispose(Smernik), pre var Smernik: ^Typ; môžeme zhrnúť takto:

  1. zaradí do voľnej pamäte (heap) premennú Smernik^,
  2. premenná Smernik má odteraz nedefinovanú hodnotu a preto by sme s touto hodnotou nemali ďalej referencovať (kým do nej nepriradíme inú vhodnú hodnotu),
    • všetky smerníky, ktoré odkazovali na túto istú dynamickú premennú, majú odteraz tiež nedefinovanú hodnotu

Dve dynamické premenné celé číslo:

var
  S, P: ^Integer;
  I: Integer;
begin
  New(S);
  S^ := 0;
  for I := 1 to 10 do
  begin
    New(P);
    P^ := I * I;
    S^ := S^ + P^;
    Dispose(P);
  end;
  Writeln('sucet = ', S^);
  Dispose(S);

Pomocná premenná P v tomto príklade je len na ilustráciu použitia New a Dispose. Program postupne vytvorí a aj zruší 11 dynamických premenných.



Príklady smerníkov na štruktúry



Dynamický záznam:

type
  TZaznam = record
    X, Y: Integer;
  end;
var
  Z: ^TZaznam;
begin
  New(Z);
  Z^.X := 100;
  Z^.Y := 200;
  with Z^ do
    Image1.Canvas.MoveTo(X, Y);
  Inc(Z^.X, 100);
  Dec(Z^.Y, 50);
  Image1.Canvas.LineTo(Z^.X, Z^.Y);


Dynamické jednorozmerné pole:

type
  TPole = array [1..10] of Real;
var
  P: ^TPole;
  I: Integer;
begin
  New(P);
  Write('zadaj prvky pola: ')
  for I := 1 to 10 do
    Read(P^[I]);
  ReadLn;
  for I := 9 downto 1 do
    P^[I] := P^[I] + P^[I+1];


Problém s veľkým poľom ako lokálnou premennou:

type
  TPole = array [1..100000000] of Integer;
 
procedure Test;
var
  P: TPole;
begin
  P[1] := 1;
end;

Takéto pole chce vzniknúť na zásobníku počas volania tejto procedúry - systém má ale problém s tak veľkým poľom. Preto zadefinujme veľké pole v lokálnej premennej pomocou smerníka. Volanie tejto testovacej procedúry už prejde.

type
  TPole = array [1..100000000] of Integer;
 
var
  N: Integer;
 
procedure Test;
var
  P: ^TPole;
begin
  New(P);
  Inc(N);
  P^[1] := N;
  WriteLn(P^[1], '. procedura Test');
  // Dispose(P);
end;
 
 begin
  while True do
    Test;
end.

Problém vznikne, ak sa toto veľké pole pred koncom procedúry neuvoľňuje (chýba volanie Dispose). Program vtedy po niekoľkých prechodoch spadne na správe "Out of memory". Takto ale môžete otestovať veľkosť heapu ...


Ďalší príklad ilustruje funkciu, ktorá vracia smerník. Táto funkcia generuje náhodnú hodnotu:

type
  PInteger = ^Integer;
 
function Daj: PInteger;
begin
  if Random(6) = 0 then
    Result := nil
  else
  begin
    New(Result);
    Result^ := Random(100);
  end;
end;


Smerník na objekt:

type
  TTrieda = class
    A: Integer;
    constructor Create(AA: Integer);
  end;
 
constructor TTrieda.Create(AA: Integer);
begin
  A := AA;
end;
 
var
  S: ^TTrieda;
begin
  New(S);
  S^ := TTrieda.Create(8);
  Writeln('hodnota = ', S^.A);
  S^.Free;
  Dispose(S);
end;


Vytvoríme jednorozmerné pole smerníkov (každý prvok poľa je smerník na množinu):

type
  TMnozina = set of Byte;     // 32 bajtov
 
  TPole = array [1..1000] of ^TMnozina;
                // 4000 bajtov -- inak bez ^ by bolo 32000 bajtov
var
  Data: TPole;
  I: Integer;
begin
  for I := 1 to 1000 do
    New(Data[I]);   // vytvorilo sa 1000 nedefinovaných množín
  for I := 1 to 1000 do
    Data[I]^ := [Random(256)];
...
  for I := 1 to 1000 do
    Dispose(Data[I]);
  // uvoľnený heap môže systém ďalej v tomto projekte používať
end;

Príklady jedno- a dvoj-rozmerných polí smerníkov:

type
  TPole = array [1..10] of Integer;
  PPole = ^TPole;
  TPole2 = array [1..20] of TPole;      // obyčajné 2-rozmerné pole
  PPole2 = ^TPole2;
  TPole2PPole = array [1..20] of TPPole;
var
  A: TPole2PPole;
  B: PPole2;
  I, J: Integer;
begin
  for I := 1 to 20 do
    New(A[I]);
  for I := 1 to 20 do
    for J := 1 to 10 do
      A[I]^[J] := I + J;
  New(B);
  for I := 1 to 20 do
    for J := 1 to 10 do
      B^[I][J] := I + J;
...
end;


Smerník, ktorý odkazuje na pole:

type
  TSPole = array [1..10] of ^Integer;      // pole smerníkov na Integer
  PSPole = ^TSPole;                        // smerník na pole smerníkov
  TPolePSPPole = array [1..20] of PSPole;  // pole smerníkov na pole smerníkov
  PPolePSPPole = ^TPolePSPPole;            // smerník na pole smerníkov na pole smerníkov
var
  C: TPolePSPPole;
  D: PPolePSPPole;
  I, J: Integer;
begin
  for I := 1 to 20 do             // SizeOf(C) = 20*4
     New(C[I]);
  for I := 1 to 20 do             // SizeOf(C[I]) = 4
    for J := 1 to 10 do           // SizeOf(C[I]^) = 10*4
    begin
      New(C[I]^[J]);
      C[I]^[J]^ := I + J;
    end;
  New(D);
  for I := 1 to 20 do             // SizeOf(D) = 4; SizeOf(D^) = 20*4
    New(D^[I]);
  for I := 1 to 20 do             // SizeOf(D^[I]) = 4
    for J := 1 to 10 do           // SizeOf(D^[I]^) = 10*4
    begin
      New(D^[I]^[J]);
      D^[I]^[J]^ := I + J;
    end;
  ...
end;


Záznamy, polia a smerníky:

type
  TPole = array [1..10] of Integer;
  PPole = ^TPole;
  TZaznam = record
    X: TPole;
    Y: PPole;
    Z: array [1..10] of ^Integer;
  end;
  PZaznam = ^TZaznam;
  TPolePZaznam = array [1..20] of PZaznam;
  PPolePZaznam = ^TPolePZaznam;
var
  A: PZaznam;
  B: TPolePZaznam;
  C: PPolePZaznam;
  I, J: Integer;
begin
  New(A);
  for I := 1 to 20 do
    New(B[I]);
  New(C);
  for I := 1 to 20 do
    New(C^[I]);
  for I := 1 to 20 do
  begin
    for J := 1 to 10 do
      C^[I]^.X[J] := I + J;
    New(C^[I]^.Y);
    for J := 1 to 10 do
      C^[I]^.Y^[J] := I + J;
    for J := 1 to 10 do
      New(C^[I]^.z[J]);
    for J := 1 to 10 do
      C^[I]^.z[J]^ := I + J;
  end;
...
end;

Postupne prečítame premennú C^[I]^.Y^[J] - zistíme, či je zapísaná správne a akého je typu:

C              // je smerník na TPolePZaznam
C^             // je pole s prvkami PZaznam
C^[I]          // je smerník na TZaznam
C^[I]^         // je záznam TZaznam
C^[I]^.Y       // je smerník na TPole
C^[I]^.Y^      // je pole s prvkami Integer
C^[I]^.Y^[J]   // je celočíselná premenná



Smerník na smerník



Nasledujúci príklad len ilustruje nezvyčajné použitie smerníkov:

type
  PInt = ^Integer;
  PPInt = ^PInt;
  PPPInt = ^PPInt;
var
  I: PInt;
  J: PPInt;
  K: PPPInt;
begin
  New(I);
  I^ := 123;
 
  New(J);
  New(J^);
  J^^ := 345;
 
  New(K);
  New(K^);
  New(K^^);
  K^^^ := 567;


Netypový smerník - typ Pointer

Pomocou netypového smerníka nemôžeme vytvárať dynamické premenné procedúrou New, lebo táto by nevedela, koľko bajtov zaberá takáto premenná. Pre vyhradenie pamäte pre netypový smerník môžeme použiť štandardnú procedúru, resp. funkciu GetMem. Na uvoľnenie dynamickej premennej môžeme použiť štandardný podprogram FreeMem. Príklad ilustruje použitie týchto procedúr:

var
  P: Pointer;
  SR: ^Real;
begin
  GetMem(P, 8);
  SR := P;
  SR^ := 3.14;
  FreeMem(P);

GetMem môžeme volať aj ako funkciu, napr.

  P := GetMem(8);

GetMem funguje analogicky ako New:

  • volanie GetMem(Smerník, počet_bajtov) pre zadaný smerník vyhradí dynamickú premennú zadanej veľkosti
  • takto môžeme vyhradiť pamäť aj pre typovú smerníkovú premennú, napr. GetMem(SI, 4), resp. GetMem(SI, SizeOf(SI^))

Typovému smerníku môžeme vyhradiť aj viac pamäte, ako zaberá samotný typ. Potom vďaka smerníkovej aritmetike môžeme pracovať s celým poľom:

var
  SI, S: PInteger;
  I: Integer;
begin
  GetMem(SI, 100 * SizeOf(Integer));
  for I := 0 to 99 do
    (SI + I)^ := Sqr(I + 1);
  S := SI;
  for I := 0 to 99 do
  begin
    Write(S^, ' ');
    Inc(S);
  end;
  WriteLn;
  FreeMem(SI);

Program najprv vyhradí dynamickú premennú veľkosti 100 celých čísel (400 bajtov), pričom na prvé z nich odkazuje smerník SI. Ku ďalším číslam sa dostaneme buď zápisom (SI + I)^ alebo pomocným smerníkom S, ktorý posúvame pomocou Inc. Pascal správne pochopí, keď namiesto (SI + I)^ zapíšeme SI[I]. Toto zvláda pre všetky typové smerníky.


Reprezentácie rôznych typov

Niektoré z doteraz používaných typov sú reprezentované pomocou dynamickej pamäti a smerníkov. Uvedieme niekoľko informácií o dynamických poliach, znakových reťazcoch a inštanciách tried.



Dynamické polia



Sú reprezentované smerníkom na jednorozmerné pole (v dynamickej pamäti heap). Deklarácia dynamického poľa zatiaľ nealokuje žiadnu pamäť. Vtedy má pole nedefinovanú dĺžku (mali by sme napr. priradiť nil).

Volanie SetLength vyhradí pamäť (niečo ako GetMem): ak už premenná mala vyhradené nejaké pole, tak toto sa automaticky uvoľní (niečo ako FreeMem).

Ak X a Y sú premenné rovnakého typu dynamické pole, potom X := Y spôsobí, že X referencuje na to isté pole ako Y (netreba alokovať pamäť pre X). Pascal si teraz pamätá, že na toto pole sa odkazuje dvomi premennými a pamäť uvoľní, až keď sa zmenia referencie oboch polí. Pre dynamické polia nepoužívajte ani procedúry New, GetMem a pod. a ani operátor ^. Pozrite nasledujúci príklad:

var
  A, B: array of Integer;
begin
  SetLength(A, 4);
  A[0] := 1;
  B := A;           // teraz sú obe polia na tom istom mieste v pamäti
  B[0] := 2;        // aj hodnotou A[0] je 2
  SetLength(B, 3);  // teraz sú obe polia v pamäti na rôznych miestach

Všimnite si posledný príkaz SetLength(B, 3), ktorý z poľa B uberie jeden prvok. Vďaka tomuto sa pre B vyhradí nová pamäť, pričom prvé tri prvky budú mať obe tieto polia rovnaké.

Pri porovnávaní premenných typu dynamické pole sa porovnávajú ich referencie a nie hodnoty polí (ako pri statických poliach). Napr.

var
  A, B: array of Integer;
begin
  SetLength(A, 1);
  SetLength(B, 1);
  A[0] := 2;
  B[0] := 2;
  if A = B then ...

Porovnanie A = B vráti False ale test A[0] = B[0] vráti True. Na skrátenie dynamického poľa sa môže použiť aj funkcia Copy, napr. A := Copy(A, 5, 10); - funguje rovnako, ak so znakovými reťazcami.

Premenná typu dynamické pole zaberá 4 bajty - je to smerník na dynamicky alokované pole v heap. Buď je to nil alebo je to smerník na blok pamäti, ktorý je o 8 bajtov dlhší ako vyhradená veľkosť poľa:

  • 4 bajty použité ako počítadlo referencií
  • 4 bajty na počet prvkov poľa (Length)
  • za tým nasledujú prvky poľa

Viacrozmerné dynamické pole je reprezentované úplne rovnako -- je to dynamické pole smerníkov na dynamické polia.



Znakové reťazce



Znakové reťazce (t.j. štandardný typ string) sú podobné dynamickým poliam: tiež sú to smerníky na polia znakov. Podobne sa pamätá aj počet referencií a aktuálna dĺžka reťazca (Length). Za posledným znakom v poli je vždy #0 (hoci tento sa nedá indexovať). Vďaka tomu je použiteľný aj ako #0 ukončený reťazec. Prázdny reťazec je uchovaný ako nil (ale napriek tomu do stringovej premennej nemôžeme priradiť nil). Nemôžeme používať ani New ani Dispose a ani iné procedúry správy pamäti. Teraz by ste už mohli správne rozumieť tomuto príkladu:

var
  S: string;
begin
  S := 'ahoj pascal';
  WriteLn('dlzka = ', StrLen(@S[1]));



Inštancie tried



Každá objektová premenná, t.j. inštancia nejakej triedy, je v skutočnosti smerník na dynamicky alokovaný blok pamäti. Treba na to myslieť pri porovnávaní aj priraďovaní, napr.

C := Image1.Canvas; // zapamätám si smerník na objekt
if C.Pen = Form1.Canvas.Pen then ... // tu netestujem, či majú rovnaké pero

Všetky stavové premenné objektu sú uchované veľmi podobne ako položky v type záznam. Už vieme, že informácie o metódach sa ukladajú do tabuľky VMT (virtual method table) - táto tabuľka je jediná pre všetky inštancie jednej triedy (každá trieda má svoju VMT tabuľku). V pamäti pre objekt je len smerník na túto VMT. VMT okrem metód obsahuje aj iné informácie o inštancii, napr. informácie o dĺžke, triede a pod.

Asi by vám malo byť jasné, prečo je nezmysel namiesto R := TRobot.Create použiť R.Create. Premenná R je na začiatku nedefinované alebo má možno hodnotu nil a teda ňou sa nemôžeme odkazovať (referencovať) na metódu Create neexistujúcej inštancie.


Netypový formálny parameter

Podprogramy v Pascale môžu mať definované formálne parametre, ktoré nemajú uvedený typ. S takýmito parametrami ale treba v tele podprogramu pracovať špeciálnym spôsobom. Možností je niekoľko:

  • pretypovaním na konkrétny typ
  • pomocou direktívy absolute (je to pretypovanie počas deklarácií)
  • poslať ako netypový parameter do inej procedúry
    • napr. štandardná procedúra Move(odkiaľ, kam, koľko_bajtov)
    • alebo zápis, resp. načítanie do/z netypového súboru – budeme vidieť neskôr

Pozrime procedúru na výmenu obsahov dvoch ľubovoľných (rovnako veľkých) premenných:

procedure Vymen(var A, B; Dlzka: Integer);
var
  T: Pointer;
begin
  GetMem(T, Dlzka);
  Move(A, T^, Dlzka);
  Move(B, A, Dlzka);
  Move(T^, B, Dlzka);
  FreeMem(T);
end;

Použitie operátora @ a smerníkovej aritmetiky Inc:

procedure Dump(const A; Dlzka: Integer);
var
  P: ^Byte;
begin
  P := @A;
  while Dlzka > 0 do
  begin
    Write(IntToHex(P^, 2), ' ');
    Inc(P);
    Dec(Dlzka);
  end;
  WriteLn;
end;
 
var
  s: array [0..15] of Char;
  I: Integer;
begin
  s := 'Ahoj Pascal';
  Dump(S, SizeOf(S));
  I := 12345;
  Dump(I, SizeOf(I));
end;



Pretypovanie



Vyriešme Dump pomocou pretypovania:

procedure Dump(const A; Dlzka: Integer);
type
  TPole = array [1..MaxInt] of Byte;
var
  I: Integer;
begin
  for I := 1 to Dlzka do
    Write(IntToHex(TPole(A)[I], 2), ' ');
  WriteLn;
end;



Direktíva absolute



Táto direktíva je tiež veľmi nebezpečná (podobne ako pretypovanie). Už pri deklarovaní premennej označíme, že sa nachádza na mieste inej premennej:

procedure Dump(var A; Dlzka: Integer);
var
  P: array [1..MaxInt] of Byte absolute A;
  I: Integer;
begin
  for I := 1 to Dlzka do
    Write(IntToHex(P[I], 2), ' ');
  WriteLn;
end;



Správa pamäti



Správa pamäti (Memory management) sa stará o udržiavanie obsadených a uvoľnených častí dynamickej pamäti (heap). Pracujeme s ňou štandardnými procedúrami: New, Dispose, GetMem a FreeMem. Každý vyhradený pamäťový blok (napr. pomocou New) má dĺžku zaokrúhlenú na najbližší násobok 4 a obsahuje ešte 4-bajtovú hlavičku - táto obsahuje dĺžku bloku a iné stavové informácie.

Od správy pamäti sa môžeme dozvedieť niektoré užitočné informácie (napr. na ladenie problémových častí programu) pomocou funkcie GetHeapStatus. Napr.

  • GetHeapStatus.TotalAllocated - veľkosť použitej pamäte
  • GetHeapStatus.TotalFree - veľkosť voľnej pamäte

Detaily si pozrite v Helphe.

Rezervované slovo nil je špeciálna smerníková konštanta - vnútorne je reprezentovaná 4 bajtami s hodnotou 0.

Smerníkový operátor @premenná vráti smerník (referenciu - adresu) na danú premennú (neskôr uvidíme aj smerník na procedúru). Výsledkom je smerník typu ^Typ, ak je Typ typom premennej.


späť | ďalej