A. Considerații teoretice
Pe un calculator compatibil IBM PC o adresă de memorie este reprezentată pe patru octeți (două cuvinte), doi pentru adresa segmentului (din considerente de arhitectură hardware, memoria este împărțită în "felii" numite segmente) și doi octeți pentru deplasamentul (distanța sau offset-ul) de la începutul segmentului.
În limbajul PASCAL o astfel de adresă se declară ca în exemplul următor:
type adresa = ^<tip_variabila_alocata_dinamic>;
var p: adresa; ... begin ... new(p); ...
... r := p; { r de tipul adresa } new(p); { o noua alocare din heap } ...
Pentru a "reintroduce" în heap zona ocupată de o variabilă dinamică, de care nu mai este nevoie, trebuie cunoscută adresa ei de început și lungimea. Acestea se află memorate în pointerul care indică zona respectivă, precum și în tipul variabilei. Pentru eliberarea zonei de memorie se folosește procedura standard dispose.
Este recomandabil ca toți pointerii din program care nu indică spre o zona alocată din heap să fie setați pe valoarea nil (cuvânt rezervat PASCAL, care înseamnă pointer spre nicăieri).
B. Exemple
program liste1; uses crt; type ptr = ^nod; nod = record nr: integer; urm: ptr; end; ConvPtr = record ofs: word; seg: word; end; var n: integer; r: ptr; op: char; procedure Initializari; begin n := 0; r := nil end; function Hexa (x: word): string; const CifreH: array[0..15] of char = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); var s: string; begin s := ''; repeat s := CifreH[x mod 16] + s; x := x div 16; until x = 0; Hexa := '$' + s end; procedure ScrieOAdresa(p: ptr); begin if p = nil then write(' nil') else write(' ', Hexa(ConvPtr(p).Seg), ':', Hexa(ConvPtr(p).Ofs)) end; procedure ScrieNod(p: ptr); begin write('Adresa '); ScrieOAdresa(p); write(' : nr= ', p^.nr:1, ' , urm='); ScrieOAdresa(p^.urm); writeln; delay(1000); end; procedure ScrieLista; var q: ptr; begin write('Radacina= '); ScrieOAdresa(r); writeln; q := r; while q <> nil do begin ScrieNod(q); q := q^.urm; end; writeln; end; function NodNou: ptr; var p: ptr; begin new(p); n := n + 1; with p^ do begin nr := n; urm := nil end; write('S-a alocat nodul: '); delay(1000); ScrieNod(p); delay(1000); NodNou := p; end; procedure InserIncep; var nnod: ptr; begin writeln('Inserare la inceput...'); nnod := NodNou; nnod^.urm := r; write('nnod^.urm:=r; Noul nod: '); ScrieNod(nnod); delay(1000); r := nnod end; procedure InserSf; var nnod, q: ptr; begin writeln('Inserare la sfarsit...'); nnod := NodNou; if r = nil then r := nnod else begin q := r; while q^.urm <> nil do q := q^.urm; q^.urm := nnod end; end; function CautaNod(NumarNod: integer): ptr; var q: ptr; begin q := r; while (q <> nil) and (q^.nr <> NumarNod) do q := q^.urm; if q = nil then begin writeln('Nodul cautat nu exista.'); delay(1000) end; CautaNod := q; end; procedure Ins(numar: integer); var nnod, q, q1: ptr; begin q := CautaNod(Numar); if q = nil then InserSf else begin write('Nodul q^: '); ScrieNod(q); nnod := NodNou; new(q1); write('new(q1) - '); ScrieNod(q1); q1^ := q^; write('q1^=q^ - '); ScrieNod(q1); nnod^.urm := q1; write('nnod^.urm:=q1 '); ScrieNod(nnod); q^ := nnod^; end; end; procedure Inserare; var op: integer; begin writeln; writeln(' 0 = inserare la INCEPUTUL listei'); writeln('-1 = inserare la SFARSITUL listei'); writeln(' n = inserarea INAINTEA nodului "n"'); write('Optiunea: '); readln(op); case op of 0: InserIncep; -1: InserSf; else Ins(op) end; end; procedure SterIncep; var ps: ptr; begin writeln('Stergere la inceputul listei...'); ps := r; r := ps^.urm; dispose(ps); writeln('dispose(ps);'); delay(1000) end; procedure SterSf; var q1, ps: ptr; begin writeln('Stergere la sfarsitul listei...'); q1 := r; while q1^.urm^.urm <> nil do q1 := q1^.urm; ps := q1^.urm; q1^.urm := nil; dispose(ps); writeln('dispose(ps);'); delay(1000) end; procedure Ster(q: ptr); var ps: ptr; begin writeln('Stergere in interiorul listei...'); ps := q^.urm; q^ := ps^; dispose(ps); writeln('dispose(ps);'); delay(1000) end; procedure Stergere; var nn: integer; q: ptr; begin write('Stergeti nodul nr. '); readln(nn); q := CautaNod(nn); if q <> nil then begin write('Nodul q^: '); ScrieNod(q); delay(1000); if q = r then SterIncep else if q^.urm = nil then SterSf else Ster(q) end; end; begin { Programul Principal } Initializari; writeln('Lista initiala este: '); ScrieLista; delay(2000); repeat writeln; writeln('I = Inserare'); writeln('S = Stergere'); writeln('T = Stop'); write('Optiunea: '); op := readkey; writeln(op); case op of 'I','i': Inserare; 'S','s': Stergere; end; if op in ['I', 'i', 'S', 's'] then begin writeln('Lista a devenit:'); ScrieLista; delay(2000); end; until op in ['T','t']; end.
Click aici pentru sursa completă (ex09_1.pas)
Radacina = <adresa primului nod> Adresa <adr. prim. nod>: nr= <nr de ord.>, urm= <adr. urm. nod> ... Adresa <adr. ultim. nod>: nr= <nr de ord.>, urm= nil
În practică se obișnuiește ca adresele de memorie să se afișeze în hexazecimal; în acest scop se folosește funcția Hexa, care returnează șirul de cifre hexazecimale, precedat de '$', corespunzător unui număr.
Se atrage atenția asupra modului în care poate fi afișat "conținutul" unui pointer - adresa spre care indică acesta: se utilizează facilitatea de conversie de tip oferita de TurboPASCAL, prin care o variabila de tip pointer este transformată într-o variabilă formată din două cuvinte (word). O instrucțiune de genul:
write(<variabila pointer>);
Programul oferă următoarele opțiuni:
C. Teme