21.Prednaska

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

úlohy | cvičenie


Smerník

Smerník (po anglicky pointer) je špeciálny typ, ktorý slúži na odkazovanie sa na iné premenné. Hodnotou smerníka je teda adresa (referencia) nejakej inej premennej. Premenná typu smerník, t.j. premenná, pomocou ktorej sa odkazujeme na inú premennú, musí byť zadeklarovaná rovnako ako každá iná premenná. Smerník zaberá v pamäti 4 bajty rovnako ako typ Integer (lebo adresy v počítači sú 4-bajtové) a rovnako ako iné lokálne premenné aj tieto majú pri štarte podprogramu nedefinovanú hodnotu.

Každá smerníková premenná sa môže v jednom momente odkazovať len na jednu premennú a to nie hocijakého typu, ale len niektorého konkrétneho typu. Tento odkazovaný typ určíme pri deklarovaní smerníkovej premennej (to ešte neznamená, že už je v tejto premennej nastavený odkaz na nejakú hodnotu). Smerníkový typ definujeme znakom ^ (strieška), za ktorým nasleduje identifikátor nejakého existujúceho typu - to bude ten typ, na ktorého premennú sa bude môcť tento odvolávať. Napr.

type
  PInteger = ^Integer;

označuje smerníkový typ, pomocou ktorého sa budeme môcť odvolávať na nejaké celočíselné premenné. Za znakom ^ môžeme zapísať len identifikátor typu, napr.

type
  PReal = ^Real;
  PChar = ^Char;
  PPoint = ^TPoint;

Takto definovaný smerníkový typ zvykneme označovať identifikátorom začínajúcim znakom P - tým sa tieto typy odlišujú od iných nami definovaných typov, ktoré zvykneme označovať začiatočným písmenom T.

Nie je dovolené, za smerníkový znak ^ písať nepriamu definíciu nejakého typu, napr. nasledujúce zápisy nie sú správne

type
  PRecord = ^record
    X, Y: Integer;
  end;
  PSet = ^set of Byte;
  PInterval = ^1..100;
  PArray = ^array [1..5] of Byte;

Smerníková premenná môže obsahovať adresu nejakej inej premennej. Použijeme operátor @, ktorého hodnotou je adresa (odkaz) na premennú. Tento odkaz je smerníkového typu na typ premennej. Napr.:

var
  I: Integer;
  SI: ^Integer;
begin
  I := 13;
  SI := @I;
  SI^ := 37;
  SI^ := SI^ * 2;

Premenná SI je typu smerník a môže odkazovať iba na celočíselný typ Integer (t.j. na ľubovoľné premenné typu Integer). Príkazom SI := @I; sme do premennej SI priradili odkaz na premennú I, čo znamená, že keď teraz budeme nepriamo pracovať s premennou, na ktorú odkazuje SI, budeme vlastne pracovať s premennou I. Práca s premennou, na ktorú odkazuje smerník sa zapisuje znakom ^, ktorý nasleduje za smerníkovou premennou, t.j. SI^ je momentálne teraz práca s premennou I. Preto príkazom SI^ := 37; priradíme do premennej I 37 a SI^ := SI^ * 2; zdvojnásobí obsah I, t.j. v I je teraz už hodnota 74.

...

Obsahom premennej I je nejaká celočíslená hodnota (napr. 74), obsahom premennej SI je nejaký smerník, t.j. adresa v pamäti, kde sa nachádza iná premenná (napr. adresa premennej I). Celočíselné premenné vieme vypisovať napr. pomocou Write, typ smerník sa takto vypísať nedá, hoci je tiež 4-bajtový rovnako ako typ Integer. Ak by sme predsa len chceli vidieť túto hodnotu (adresu do operačnej pamäte), môžeme smerník pretypovať pomocou funkcie Integer() napr. takto

var
  I: Integer;
  SI: ^Integer;
begin
  I := 13;
  WriteLn('hodnota premennej I = ', I);
  SI := @I;
  WriteLn('hodnota premennej SI^ = ', SI^);
  WriteLn('adresa premennej I = ', Integer(SI), ' ', IntToHex(Integer(SI), 8));

Funkcia IntToHex prevedie celé číslo na znakový reťazec v šestnástkovej sústave. Funkcia má ešte aj druhý parameter, ktorý označuje počet cifier šestnástkového zápisu. Výpis môže vyzerať asi takto:

hodnota premennej I = 13
hodnota premennej SI^ = 13
adresa premennej I = 4345856 00425000

Ďalší príklad ukazuje použitie dvoch smerníkových premenných:

type
  PInteger = ^Integer;
  PReal = ^Real;
var
  I: Integer;
  SI: PInteger;
  R: Real;
  SR: PReal;
begin
  I := 13;
  R := 3.14;
  SI := @I;
  SR := @R;
  WriteLn('adresa premennej I = ', Integer(SI), ' ', IntToHex(Integer(SI), 8));
  WriteLn('adresa premennej R = ', Integer(SR), ' ', IntToHex(Integer(SR), 8));

Po spustení vyzerá výpis približne takto:

adresa premennej I = 4345856 00425000
adresa premennej R = 4345864 00425008

Uvedomte si, že premenná SI môže odkazovať len na celočíselné premenné a teda nesmie odkazovať napr. ani na reálnu premennú R a naopak, smerníková premenná SR môže odkazovať len na reálnu premennú a nie je dovolené priradiť do nej odkaz za celočíselnú premennú. Napr. obe nasledujúce priradenia sú chybné a kompilátor nás na to upozorní:

  SI := @R;
  SR := @I;

Smerníky môžeme medzi sebou aj porovnávať na rovnosť (musia ale odkazovať na ten istý typ). Napr.

type
  PInteger = ^Integer;
var
  I, J: Integer;
  SI, SJ: PInteger;
begin
  SI := @I;
  SJ := @J;
  WriteLn('adresa premennej I = ', Integer(SI), ' ', IntToHex(Integer(SI), 8));
  WriteLn('adresa premennej J = ', Integer(SJ), ' ', IntToHex(Integer(SJ), 8));
  SI^ := 13;
  SJ^ := 37;
  WriteLn('hodnota premennej I = ', I);
  WriteLn('hodnota premennej J = ', J);
  if SI = SJ then
    WriteLn('oba smerniky su rovnake')
  else
    WriteLn('oba smerniky su rozne');
  SJ := SI;
  WriteLn('priradili sme SJ := SI');
  if SI = SJ then
    WriteLn('oba smerniky su rovnake')
  else
    WriteLn('oba smerniky su rozne');

Vo výpise si všimnite, že najprv boli hodnoty oboch smerníkov SI a SJ rôzne a po priradení sa ich hodnoty rovnali:

adresa premennej I = 4345856 00425000
adresa premennej J = 4345860 00425004
hodnota premennej I = 13
hodnota premennej J = 37
oba smerniky su rozne
priradili sme SJ := SI
oba smerniky su rovnake

Odkazovať môžeme nielen na jednoduché premenné (Integer alebo Real), ale aj na záznamy, prvky polí a aj celé polia. Všimnite si spôsob práce so záznamom:

type
  TZaznam = record
    X, Y: Integer;
  end;
  PZaznam = ^TZaznam;
  PInteger = ^Integer;
var
  Z: TZaznam;
  SZ: PZaznam;
  SI: PInteger;
begin
  Z.X := 100;
  SZ := @Z;
  SZ^.Y := 200;
  WriteLn('zaznam: ', Z.X, ' ', Z.Y);
  WriteLn('zaznam: ', SZ^.X, ' ', SZ^.Y);       // oba výpisy budú rovnaké
  SI := @Z.Y;
  SI^ := 155;
  WriteLn('zaznam: ', Z.X, ' ', Z.Y);
  SI := @SZ^.X;
  SI^ := 122;
  WriteLn('zaznam: ', Z.X, ' ', Z.Y);

V tomto príklade sme najprv vytvorili odkaz SZ na celý záznam Z a ďalej sme pracovali s položkami záznamu, napr. SZ^.X, SZ^.Y (čo je v tomto prípade to isté ako Z.X, Z.Y). Potom sme vyvtorili odkaz len na jednu položku záznamu (premennú Z.Y) a nepriamo sme pracovali s touto premennou (priradili sme do nej 155). Na záver sme vytvorili odkaz na premennú SZ^.X, čo je vlastne premenná Z.X, a priradili sme do nej hodnotu 122. Výpis teda vyzerá takto:

zaznam: 100 200
zaznam: 100 200
zaznam: 100 155
zaznam: 122 155

Ďalší príklad ukazuje spôsob práce s celým poľom a aj samostatným prvkom poľa:

type
  TPole = array [1..10] of Integer;
  PPole = ^TPole;
  PInteger = ^Integer;
var
  Pole: TPole;
  SPole: PPole;
  I: Integer;
  SI: PInteger;
begin
  SPole := @Pole;
  for I := 1 to High(SPole^) do
    SPole^[I] := I;
  for I := 1 to High(Pole) do
    Write(Pole[I], ' ');
  WriteLn;
  WriteLn('adresa premennej Pole    = ', Integer(SPole), ' ', IntToHex(Integer(SPole), 8));
  SI := @Pole[5];
  SI^ := 55;
  SI := @Pole[1];
  SI^ := 11;
  for I := 1 to High(SPole^) do
    Write(SPole^[I], ' ');
  WriteLn;
  WriteLn('adresa premennej Pole[1] = ', Integer(SI), ' ', IntToHex(Integer(SI), 8));

Výpis vyzerá nejako takto:

1 2 3 4 5 6 7 8 9 10
adresa premennej Pole    = 4345856 00425000
11 2 3 4 55 6 7 8 9 10
adresa premennej Pole[1] = 4345856 00425000

Všimnite si že adresa celého poľa a adresa jeho prvého prvku sú rovnaké.

Typ smerník môže byť využitý aj pre typ formálneho parametra podprogramu. Napr.

type
  PInteger = ^Integer;
 
procedure Zmen(S: PInteger);
begin
  S^ := 123;
end;

Procedúra Zmen dostáva ako konštantný parameter adresu nejakej celočíselnej premennej a výsledkom je zmena obsahu tejto premennej. Uvedomte si, že napriek tomu, že parameter nie je typu var-parameter, zmení sa hodnota nejakej premennej, ako keby táto bola naozaj var-parameter. Rovnaký efekt, ale bez smerníka by sme vedeli dosiahnuť zápisom:

procedure Zmen(var I: Integer);
begin
  I := 123;
end;

Ak by sme mali celočíselnú premennú X, nasledujúce dve volania by mali úplne rovnaký efekt:

var
  X: Integer;
  SX: PInteger;
begin
  Zmen(@X);
  Zmen(X);

Prvé volanie Zmen(@X); zavolá prvú verziu Zmen s parametrom typu smerník na celé číslo. Druhé volanie Zmen(X); zavolá druhú verziu Zmen s var-parametrom typu celé číslo. Rovnaký efekt by malo aj takéto volanie:

  SX := @X;
  Zmen(SX);

Podobne je to aj s dvoma verziami procedúry, ktorá vymieňa hodnoty dvoch celočíselných premenných:

procedure Vymen(PA, PB: PInteger);
var
  T: Integer;
begin
  T := PA^;
  PA^ := PB^;
  PB^ := T;
end;
 
procedure Vymen(var A, B: Integer);
var
  T: Integer;
begin
  T := A;
  A := B;
  B := T;
end;

Premenné do tejto procedúry pošleme buď poslaním ich adries: Vymen(@I, @J); alebo ako var-parametre: Vymen(I, J);. Totiž v skutočnosti sa var-parameter v Pascale realizuje posielaním adresy premennej, ktorá je skutočným parametrom. V tele procedúry sa potom s takýmto parametrom pracuje trochu inak: kompilátor tu generuje kód pre prácu s adresou, použitím tzv. nepriamej adresácie. Preto sa niekedy var-parametrom hovorí aj parameter volaný adresou. V niektorých programovacích jazykoch existuje len jeden spôsob posielania parametrov (hodnotový parameter, parameter volaný hodnotou), ale vďaka smerníkom sa dajú zabezpečiť aj parametre volané adresou.



Konštantný smerník nil



Konštanta nil je špeciálna hodnota, ktorú môžeme priradiť do ľubovoľnej smerníkovej premennej. Používa sa vtedy, keď chceme rozlíšiť stav, že niečo je v smerníku priradené (odkazuje na nejakú premennú) a stav, že tam zatiaľ nič priradené nie je. Táto univerzálna smerníková konštanta sa teda môže priradiť do ľubovoľného smerníka a tiež môžeme ľubovoľný smerník otestovať, či obsahuje práve túto hodnotu. Okrem toho všetky globálne smerníkové premenné (aj stavové premenné objektov) majú automaticky túto hodnotu ako svoju inicializačnú. Konštantu nil priraďujeme napr. takto

  Smernik := nil;

a preto môžeme túto premennú ďalej testovať, napr. takto

  if Smernik = nil then
    Smernik := @Premenna;

alebo

  if Smernik <> nil then
    Smernik^ := 157;

Pomocou relačných operátorov (=, <>) môžeme porovnávať aj smerníky navzájom, ale len za predpokladu, že oba odkazujú na ten istý typ. Napr.

var
  I: Integer;
  S1, S2: ^Integer;
begin
  S1 := @I;
  S1^ := 37;
  S2 := S1;           // môžeme priradiť, lebo je to rovnaký typ smerníkov
  Inc(S1^, 2);
  if (S1 <> S2) and (S2 <> nil) then
    S2^ := S2^ + 2;

V nasledujúcom príklade bude kompilátor hlásiť chybu:

var
  I: Integer;
  R: Real;
  S1: ^Integer;
  S2: ^Real;
begin
  S1 := @I;
  S1^ := 37;
  // S2 := S1;      // nemôžeme
  S2 := @R;
  S2^ := 37;
  if S1^ = S2^ then
    WriteLn('rovnake hodnoty');
  if S1 = S2 then                           // toto je chyba
    WriteLn('rovnake smerniky');


Smerníková aritmetika

Nasledujúci program ukazuje použitie smerníkov pri práci s prvkami poľa:

var
  Pole: array [1..10] of Integer;
  I: Integer;
  P: PInteger;
begin
  for I := 1 to 10 do
  begin
    P := @Pole[I];
    P^ := I * I;
  end;

Táto časť programu len komplikovaným spôsobom priraďuje nejaké hodnoty do desiatich prvkov poľa. Keď si ale uvedomíte, ako sa postupne mení hodnota smerníka P, môžeme uvažovať aj o inom riešení. Smerník P najprv ukazuje na prvý prvok poľa, potom na druhý prvok, ktorý je na adrese o 4 bajty ďalej, potom na tretí, ktorý je 4 bajty ďalej od druhého atď. Ak by sme teda ešte pred samotným cyklom do P priradili smerník na prvý prvok a potom by sme mali v cykle možnosť zväčšovať tento smerník na adresu nasledovného prvku, riešenie by vyzeralo veľmi zaujímavo. Na posúvanie smerníka môžeme využiť známu štandardnú procedúru Inc:

var
  Pole: array [1..10] of Integer;
  I: Integer;
  P: PInteger;
begin
  P := @Pole[1];      // adresa prvého prvku poľa
  for I := 1 to 10 do
  begin
    P^ := I * I;
    Inc(P);               // adresa nasledovného prvku. t.j. pripočíta 4 bajty
  end;

Všimnite si použitie procedúry Inc(P), čo je vlastne to isté, ako priradenie P := P + 1. Tomuto hovoríme smerníková aritmetika. Operácie + a - majú pre smerníky inú interpretáciu, ako pre čísla a množiny (a + pre reťazce). Ak máme P1 a P2 dva smerníky rovnakého typu, patom:

  • P1 + číslo referencuje prvok poľa, ktorý je posunutý o číslo prvkov dopredu oproti prvku, na ktorý odkazuje P1,
  • P1 - číslo referencuje prvok poľa, ktorý je posunutý o číslo prvkov späť oproti prvku, na ktorý odkazuje P1,
  • P1 - P2 označuje počet prvkov poľa, ktorý je medzi prvkami, na ktoré odkazujú P1 a P2.

Ďalší príklad ilustruje referencovanie nasledovného prvku poľa. Ak P je smerník na nejaký prvok poľa, potom P^ je hodnota tohto prvku a (P + 1)^ je hodnota nasledovného prvku.

var
  P: ^Real;
  A: array [1..100] of Real;
  I: Integer;
begin
  P := @A[1];
  P^ := 1;
  for I := 2 to 100 do
  begin
    (P + 1)^ := P^ + 1 / I;
    P := P + 1;        // posun na ďalší prvok o 8 bajtov
  end;
  repeat
    WriteLn(P^:13:10);
    Dec(P);
  until P = @A[1];

Táto časť programu najprv zaplní všetky prvky poľa postupne hodnotami: 1, 1+1/2, 1+1/2+1/3, 1+1/2+1/3+1/4, ... Potom tieto hodnoty vypíše v poradí od posledného až po druhý (výpis skončí, keď smerník referencuje prvý prvok poľa).

Uvedomte si, že pri práci s prvkami poľa nie pomocou indexov, ale pomocou smerníkov, kompilátor nemá žiadnu možnosť kontrolovať pretečenie indexov a vďaka tomu môžu vzniknúť chyby, ktoré sa veľmi ťažko odhaľujú.

Ďalší príklad ukazuje použitie smerníka pri inicializácii dvojrozmerného poľa:

var
  P: PInteger;
  Pole: array [1..5, 1..5] of Integer;
  I, J: Integer;
begin
  P := @Pole[1, 1];                 // adresa prvého prvku poľa
  for I := 1 to 25 do
  begin
    P^ := I;
    Inc(P);
  end;
  for I := 1 to 5 do
  begin
    for J := 1 to 5 do
      Write(Pole[I, J]: 3);
    WriteLn;
  end;

Uvedomte si, že ak máme zadeklarované pole s dolnou hranicou indexu od 0:

var
  Pole: array [0..99] of TPrvok;
  P: ^TPrvok;
  I: Integer;
begin
  P := @Pole[0];

potom zápis P[I] je to isté ako (P + I)^. Zamyslite sa, ako by sa to zapísalo pre pole, ktorého dolná hranica indexu nie je 0? Vedeli by ste pomocou smerníka na prvý prvok dvojrozmerného poľa A vyjadriť prístup k prvku A[I, J]?


Znakové reťazce ukončené #0

Znakové reťazce ukončené #0 (null-terminated strings) sú veľmi podobné znakovým reťazcom v jazykoch C a C++. Niekedy ich potrebujeme poznať pri práci s niektorými podprogramami operačného systému (niekedy ich vyžadujú ako parametre niektorých procedúr nižšej úrovne).

Tieto reťazce sú postupnosti znakov vždy ukončené znakom #0. Pre tieto postupnosti sa nepamätá momentálna dĺžka (ako u string), ale, ak ju budeme potrebovať zistiť, musíme postupne pozrieť reťazec znak za znakom a hľadať prvý výskyt #0. Tieto reťazce najčastejšie uchovávame v jednorozmernom poli s dolnou hranicou 0, napr. TFileName = array [0..259] of Char;. Free Pascal pre to poskytujú preddefinovaný typ PChar (smerník na postupnosť znakov, t.j. ^Char).

Mnohé štandardné procedúry a funkcie, ktoré pracujú s typom string, dokážu pracovať aj s takýmito reťazcami. Napr. aj Read, ReadLn, Str, Val, Write, WriteLn, ... Samozrejme, že s týmito reťazcami môžeme pracovať aj úplne rovnako ako s inými poliami znakov. Okrem toho Free Pascal poskytuje aj množinu špeciálnych funkcií pre takéto reťazce, napr.

  • StrCat zreťazenie: k prvému reťazcu pridá na koniec druhý, napr. StrCat(P1, P2)
  • StrComp porovnanie dvoch reťazcov, výsledkom je buď -1, 0, 1
  • StrCopy skopírovanie do pamäte pre reťazec, nejaký iný reťazec
  • StrLen vráti dĺžku reťazca
  • StrPos vráti smerník na prvý výskyt podreťazca P2 v reťazci P1, alebo nil, ak taký podreťazec neexistuje, napr. StrPos(P1, P2)

Aj pre PChar sa často využíva smerníková aritmetika, napr.

var
  P, Q: PChar;
begin
  P := 'milujem programovanie';
  Q := P;
  while Q^ <> #0 do
  begin
    Q^ := UpCase(Q^);
    Inc(Q);          // posun na nasledujúci znak reťazca
  end;
  WriteLn(P);
  ReadLn;
end.

Pozrite, ako rozdielne vníma Pascal pole znakov a reťazec ukončený #0:

var
  Pole: array [1..100] of Char;
  Smernik: PChar;
begin
  Pole := 'Free Pascal';
  WriteLn('Pole: "', Pole, '"');
  Smernik := @Pole;                      // alebo Smernik := @Pole[1];
  WriteLn('PChar: "', Smernik, '"');
  WriteLn('pocet znakov = ', StrLen(Smernik));

Prvý výpis WriteLn medzi úvodzovkami vypíše 100 znakov, pričom prvých 11 je reťazec Free Pascal a zvyšné sú prázdne znaky (s kódom #0), ktoré sa vypíšu ako medzery. Druhý výpis je už ako Reťazec ukončený #0, t.j. PChar. V tomto prípade sa vypíše len týchto prvých 11 znakov, lebo ďalším znakom v poli je #0 a ten označuje koniec reťazca. V ďalšom riadku sa vypíše počet znakov reťazca, teda 11. Všimnite si aj priradenie Pole := 'Free Pascal'; Takto sa priradí všetkých 100 prvkov poľa, pričom pole sa doplní znakom #0.

Pomocou StrLen zisťujeme počet znakov reťazca, t.j. prvý výskyt znaku #0. Takto môžeme zistiť nielen koniec reťazca, ale aj adresu v poli, od ktorej môžeme do tohto poľa dopísať ďalší reťazec:

var
  Pole: array [1..100] of Char;
  S, S1: PChar;
begin
  Pole := 'Free Pascal';
  S := @Pole;
  S1 := S + StrLen(S) + 1;   // adresa tesne za #0
  StrCopy(S1, 'Lazarus');
  WriteLn('prvy: "', S, '"');
  WriteLn('druhy: "', S1, '"');
  WriteLn('Pole: "', Pole, '"');

V samotnom poli sú teraz dva reťazce, ktoré sú oddelené znakom #0. Smerník S ukazuje na začiatok poľa (prvý znak poľa), smerník S1 ukazuje tesne za tento prvý reťazec, za znak #0. Tam sa nachádza druhý reťazec. Posledný výpis vypisuje celé pole, kde sa vypíšu oba reťazce.

Ďalší príklad ukazuje, ako načítaný reťazec v premennej Pole rozbijeme na krátke reťazce na základe výskytu medzier. Pole PC bude obsahovať smerníky na začiatky týchto krátkych reťazcov.

var
  Pole: array [1..100] of Char;
  S: PChar;
  I, J: Integer;
  PC: array [1..20] of PChar;    // adresy do premennej Pole, kde začínajú podreťazce
begin
  Write('>');
  ReadLn(Pole);
  S := @Pole;
  I := 0;
  while (S <> nil) and (S^ <> #0) do
  begin
    Inc(I);
    PC[I] := S;
    S := StrPos(S, ' ');
    if S <> nil then
    begin
      S^ := #0;                 // do premennej Pole sme na koniec slova namiesto ' ' dali #0
      Inc(S);
    end;
  end;
  for J := 1 to I do
    WriteLn(PC[J]);


Netypový smerník - typ Pointer

Všetky doterajšie smerníky boli referenciami na presne zadaný typ:

type
  PSmernik = ^Typ;

Potom priraďovanie a referencovanie smerníkových premenných bolo prísne kontrolované kompilátorom Pascalu:

  • priradiť do smerníkovej premennej môžeme len hodnotu rovnakého smerníkového typu,
  • referencovaním získavame prístup k odkazovanej premennej a tá je práve definovaného typu.

Pascal umožňuje pracovať aj so smerníkmi, ktoré nemajú určený typ premennej, na ktorú odkazujú (tzv. netypový smerník). Používame na to identifikátor typu Pointer, napr.

var
  P: Pointer;

definuje smerníkovú premennú P, ktorá môže obsahovať referenciu na premennú ľubovoľného typu. S takouto referencovanou premennou ale nemôžeme pracovať podobne ako pri typových smerníkoch, lebo Pascal pre zápis P^ nevie povedať, akého je typu.

Pre netypové smerníky platí, že sú kompatibilné so všetkými smerníkovými typmi. Napr. bude fungovať aj

var
  I: Integer;
  P: Pointer;
  SI: PInteger;
  SR: ^Real;
begin
  SI := @I;
  P := SI;
  SR := P;

V tejto časti programu sa smerník na celé číslo SI priradil do netypového smerníka P. Táto hodnota sa potom priradila do smerníka SR na reálne číslo. Takýto štýl programovania je veľmi nebezpečný a pri neopatrnom používaní môžete spôsobiť spadnutie programu.

V ďalšom príklade 8-bajtové reálne číslo priradíme do 8-bajtového poľa:

var
  Pole: array [0..7] of Byte;
  P: Pointer;
  SR: ^Real;
begin
  P = @Pole;
  SR := P;
  SR^ := 3.14;
  for I := 0 to 7 do
    Write(IntToHex(Pole[I], 2), ' ');

Aj s netypovým smerníkom (Pointer) môžeme pracovať ako s konkrétnym typom. Môžeme využiť pretypovanie. Buď pretypujeme smerníkovú premennú, alebo jej odkaz, napr.

var
  I: Integer;
  P: Pointer;
begin
  P := @I;
  Integer(P^) := 10;
  WriteLn(PInteger(P)^);

Priradenie Integer(P^) := 10 pretypuje referenciu (premennú, na ktorú sa odkazuje) na typ Integer. V príkaze WriteLn vypisujeme hodnotu PInteger(P)^, t.j. pretypujeme netypový smerník P na typový smerník na celé číslo a potom týmto smerníkom ďalej referencujeme.


späť | ďalej