Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
Guida Pascal - Appendice 9 I puntatori

Guida Pascal

Capitolo 28° - Appendice 9 I puntatori

<< Precedente Prossimo >>
I puntatori sono molto utilizzati in linguaggi come il C, C++. Al contrario, nel Pascal, trovano poche applicazioni pratiche, se non nelle librerie precompilate, in partcolare in quelle che descrivono le procedure e le funzioni generali del TVision (il Pascal ad oggetti). Sebbene appunto, il loro uso sia ristratto nell'ambito di questo linguaggio, ritengo che ,per completezza, debba essere trattato comunque.

Cos'è un puntatore?
Un puntatore è una variabile che contiene l'indirizzo di memoria di un altro dato, ossia contiene un codice che identifica univocamente una delle celle di memoria usate per racchiudere le variabili di un programma. Come ogni altra variabile, i puntatori possono essere di più tipi: integer, real, string, char ecc... Il perchè risiede nel fatto che ogni tipo di dato (anche quelli derivati, come i record, gli enumeratori, i set ecc...) occupa una spazio diverso nella memoria fisica nel computer: ci sono i tipi che occupano 4 bytes (integer), altri che ne occupano 8, altri 16, altri 3 e così via. Tramite un puntatore si può conoscere anche il valore di una variabile.

L'uso dei puntatori
I puntatori si dichiarano mediante il contrutto type, che abbiamo già ampiamente visto.

type
IntegerPointer=^Integer

var B:IntegerPointer


In questo pezzo di codice si è dichiarato un tipo di puntatore chiamato IntegerPointer, che 'punta' (ossia contiene un indirizzo di memoria) ad un intero. Anche se questa è versione più usata, esiste anche una sintassi contratta di dichiarare una variabile come puntatore:

var B:^Integer


In questo caso si è dichiarata la variable B come puntatore ad un intero.

Un semplice programma per vedere l'uso dei puntatori:
Program Puntatori;
uses crt;

type IntPoint=^Integer;

var B:IntPoint;

begin
    New(B);
    B^:=34;
    writeln('La variabile B punta ad una cella di memoria contenente',B^);
    readln
end.


La procedura new(p:pointer) alloca un'area di memoria abbastanza grande da contenere un valore dello stesso tipo del puntatore passato come parametro: in questo caso alloca 4 bytes per contenere un intero.
L'uso del ^ dopo la variabile puntatore ci dice che non stiamo assegnando un indirizzo al puntatore, bensì un valore alla cella di memoria puntata. Perciò B^ è come se fosse una normalissima variabile di tipo Integer.

Un uso più specifico dei puntatori è illustrato in questo programma:
Program Puntatori2;
uses crt;
var a,b:integer;
    c:^integer;

begin
    clrscr;
    new(c);
    a:=56;
    b:=98;
    c:=@a;
    writeln('Ora la cella di memoria puntata da c contiene ',c^);
    c:=@b;
    writeln('Ora invece contiene ',c^);
    readln
end.


L'output prodotto dal programma sarà:

Ora la cella di memoria puntata da c contiene 56
Ora invece contiene 98


Usando l'operatore @ davanti ad un qualsiasi tipo di variabile si ottiene l'indirizzo di quella variabile. Quindi con las sintassi c:=@a abbiamo assegnato a c l'indirizzo in memoria di a, ed ora il puntatore c punta ad a (ossia contiene il suo indirizzo di memoria). Infatti si è visto che, scrivendo c:=@a, la variabile c^ contiene il valore di a, mentre con c:=@b la variabile c^ contiene il valore di b.
Perchè questo? Perchè quando si usa c^, il programma legge l'indirizzo contenuto in c, si 'reca' a quell'indirizzo e 'preleva' il valore contenuto in quella cella di memoria, quindi lo restituisce.

Tutto quello che abbiamo visto fin'ora, può essere fatto con tutti i tipi di variabile, anche derivati. Un esempio:

Program Puntatori3;
uses crt;

type
   valori=record
   val1,val2:real;
end;

var a,b:valori;
    c:^valori;

begin
    clrscr;
    new(c);
    a.val1:=56.87;
    a.val2:=23.76;
    b.val1:=98.32;
    b.val2:=2.4e5;
    c:=@a;
    writeln('Ora la cella di memoria puntata da c contiene ',c^.val1:4:2,' e ',c^.val2:4:2);
    c:=@b;
    writeln('Ora invece contiene ',c^.val1:4:2,' e ',c^.val2:6:1);
    readln
end.


L'output prodotto sarà:

Ora la cella di memoria puntata da c contiene 56.87 e 23.76
Ora invece contiene 98.32 e 240000.0


Da notare è che l'operatore ^ si usa sempre dopo la variabile puntatore, non dopo il campo del record:

c^.val1 (*Giusto*)
c.val1^ (*Sbagliato*)


Ma se avessimo avuto il record scritto in questo modo:

type
   valori=record
   val1,val2:real;
   val3:^real;


Sarebbe stato lecito scrivere:

(*...*)
c^.val3:=@b.val1;
writeln('La cella di memoria puntata dal c^.val3 contiene ',c^.val3^:4:2);


E avrebbe prodotto in output:

La cella di memoria puntata dal c^.val3 contiene 98.32


Per concludere i puntatori costituiscono uno strumento potente, ma solo se li si sa usare bene.
<< Precedente Prossimo >>
A proposito dell'autore

C#, TypeScript, java, php, EcmaScript (JavaScript), Spring, Hibernate, React, SASS/LESS, jade, python, scikit, node.js, redux, postgres, keras, kubernetes, docker, hexo, etc...