Puntatore (programmazione)

In programmazione, il puntatore[1] è un tipo di dato che rappresenta l'indirizzo di memoria che contiene una data variabile, o in generale un oggetto oppure una struttura dati.
Descrizione
[modifica | modifica wikitesto]Tipi di puntatore
[modifica | modifica wikitesto]Nei linguaggi tipizzati, ogni puntatore ha un tipo ben definito, derivato dal tipo dell'oggetto puntato. Così, l'indirizzo di memoria di una variabile di tipo "numero intero" si dirà essere di tipo "puntatore a numero intero", e questo sarà considerato dal linguaggio come un tipo distinto da "puntatore a carattere" o altri tipi puntatore. Il tipo dell'oggetto puntato viene spesso detto tipo base del puntatore (con terminologia analoga a quella usata per gli array). I tipi puntatori possono essere impiegati anche nella dichiarazione di variabili (o in altri contesti analoghi). Per esempio, nel linguaggio C
int n;
char c;
dichiara n come variabile di tipo int (numero intero) e c come char (carattere);
int *pn;
char *pc;
dichiara pn come "puntatore a intero" e pc come "puntatore a carattere". Questi due tipi sono considerati dal linguaggio come distinti e (almeno in linea di principio, dato che nella pratica entrambi contengono un valore numerico indicante l'indice dello slot di memoria puntato) incompatibili; un assegnamento come
pc = pn;
verrà segnalato dal compilatore come errore.
Puntatore null
[modifica | modifica wikitesto]Ogni linguaggio fornisce un valore speciale che può essere assegnato a una variabile di tipo puntatore per indicare che essa non punta a nessun oggetto. Questo valore viene generalmente detto NULL, e spesso corrisponde al valore "0" (che di norma non rappresenta un indirizzo di memoria valido).
Puntatori non validi
[modifica | modifica wikitesto]Per "puntatore non valido" si intende in genere una variabile di tipo puntatore non inizializzata, ovvero alla quale non è mai stato assegnato l'indirizzo di alcun oggetto. A seconda dei linguaggi e dei contesti, questo può comportare che la variabile contenga un valore "casuale" oppure il valore null.
La dereferenziazione di un puntatore "non valido" spesso genera un errore di sistema o un'eccezione. Nel caso peggiore (quello in cui il puntatore contiene un valore "casuale" che però, fortuitamente, corrisponde a una locazione di memoria), essa potrebbe portare a una violazione grave della coerenza interna della memoria del programma, con risultati imprevedibili e non raramente disastrosi. Per questo motivo l'uso scorretto di puntatori può portare a malfunzionamenti le cui cause sono molto difficili da individuare e correggere. Alcuni linguaggi tentano di limitare l'uso dei puntatori o addirittura di eliminarli completamente (un esempio in questo senso è Java); all'eliminazione dei puntatori deve corrispondere in genere l'introduzione di altri meccanismi che consentano di ottenere risultati analoghi a quelli per i quali si usano solitamente i puntatori (le limitazioni imposte da Java all'uso dei puntatori, per esempio, sono controbilanciate dal suo meccanismo di garbage collection).
Operazioni sui puntatori
[modifica | modifica wikitesto]Possiamo distinguere due tipi di operazioni tra i puntatori:
- La deferenziazione
- Le operazioni aritmetiche

Deferenziazione
[modifica | modifica wikitesto]L'operazione fondamentale che si può eseguire su un valore di tipo puntatore viene detta dereferenziazione (dereferencing) oppure operazione di risoluzione del riferimento; è rappresentata da un operatore unario che, applicato a un puntatore, produce come risultato l'oggetto puntato. Così, con riferimento all'esempio della sezione precedente,
*pn = 3;
(" * " è il simbolo dell'operatore di dereferenziazione), assegna "3" alla variabile intera puntata da pn.
Un'altra operazione piuttosto comune relativa ai puntatori (non fornita da tutti i linguaggi) consente di ottenere un puntatore a una data variabile, ovvero calcolarne l'indirizzo; l'operatore corrispondente (anch'esso unario) viene spesso detto "operatore indirizzo-di". In C e in C++ questo operatore è rappresentato dal simbolo "&":
pn = &n;
assegna al puntatore pn l'indirizzo della variabile n. Finché pn manterrà tale valore, qualsiasi uso del puntatore dereferenziato, come
*pn = 4;
avrà effetto sulla variabile n puntata da pn.
Alcuni linguaggi (in particolare della famiglia del C) forniscono un insieme supplementare di operazioni sui valori di tipo puntatore, pensati soprattutto per la navigazione all'interno di array; essi vanno sotto il nome di aritmetica dei puntatori.
I puntatori possono essere usati anche per chiamare funzioni, in tal caso si parla di puntatori a funzione[1.1]. Supponiamo di avere 2 funzioni:
int f1(double);
int f2(double);
allora è possibile creare un puntatore a funzione in questa maniera:
int (*pfunz)(double);
A questo punto, si può decidere di far puntare il puntatore pfunz o alla prima funzione f1, o alla seconda funzione f2:
if (condizione)
pfunz = f1;
else
pfunz = f2;
Per invocare la funzione, basta dereferenziare il puntatore:
int ris = *pfunz(4.2);
Tutto questo meccanismo è valido solo se le funzioni hanno lo stesso tipo di ritorno e lo stesso numero di parametri dello stesso tipo.
Aritmetica dei puntatori
[modifica | modifica wikitesto]Nei linguaggi di programmazione, l'espressione aritmetica dei puntatori si riferisce a un insieme di operazioni aritmetiche applicabili sui valori di tipo puntatore. Tali operazioni hanno lo scopo di consentire un alto livello di flessibilità nell'accesso a collezioni di dati omogenei conservati in posizioni contigue della memoria (per esempio array). L'aritmetica dei puntatori è tipica del linguaggio C ed è stata mantenuta in alcuni linguaggi derivati (è presente per esempio in C++ ma non in Java).
Aritmetica dei puntatori nel linguaggio C[1.2]
[modifica | modifica wikitesto]L'aritmetica dei puntatori del C è basata su tre operatori fondamentali, accompagnati da un certo numero di altri operatori la cui semantica è derivata da quella degli operatori principali:
+: operatore binario di somma di un puntatore e un intero- derivato:
++: operatore unario di autoincremento di un puntatore - derivato:
+=: operatore di assegnamento con somma
- derivato:
-: operatore binario di differenza fra due puntatori-: operatore binario di sottrazione di un intero da un puntatore- derivato:
--: operatore unario di autodecremento di un puntatore - derivato:
-=: operatore di assegnamento con differenza
- derivato:
Operatore di somma di un puntatore e un intero
[modifica | modifica wikitesto]Definizione
[modifica | modifica wikitesto]L'operatore di somma di puntatore e intero richiede un operando di tipo puntatore e un operando di tipo intero. Il risultato della somma è l'indirizzo dato dal puntatore incrementato del risultato della moltiplicazione dell'intero specificato per la dimensione (sizeof) del tipo base del puntatore espressa in byte. Per esempio, se p è un puntatore al tipo intero int (int *p) di valore 1000 (p=1000), e se la dimensione di un int è due byte, p+1 vale 1002, p+2 vale 1004, e in generale p+n vale 1000+n*2.
Significato
[modifica | modifica wikitesto]L'operazione di somma fra puntatore e intero è significativa nel caso in cui il puntatore contenga l'indirizzo di una cella di un array di dati del tipo base del puntatore. Infatti, se p (puntatore a intero) contiene l'indirizzo della prima cella di un array di interi, p+1 produce l'indirizzo della seconda cella, p+2 l'indirizzo della terza, e via dicendo. L'aritmetica dei puntatori quindi introduce una sintassi alternativa rispetto a quella tradizionale (basata su indicizzazione) per accedere agli elementi di un array.
Operatore di differenza fra due puntatori
[modifica | modifica wikitesto]Definizione
[modifica | modifica wikitesto]L'operatore di differenza fra puntatori richiede due operandi entrambi di tipo puntatore, aventi tipo base omogeneo (per esempio due puntatori a intero, due puntatori a carattere, e via dicendo). Il risultato della differenza è la differenza aritmetica fra i due indirizzi specificati dai puntatori, divisa per la dimensione del tipo base. Per esempio, se p contiene 1002 e q contiene 1000, ed entrambi sono puntatori a int, e la dimensione degli int è 2, allora q-p vale 1.
Significato
[modifica | modifica wikitesto]L'operazione di differenza fra puntatori è significativa se i due operandi contengono gli indirizzi di due celle diverse del medesimo array, e se il tipo base dell'array coincide con quello dei due puntatori. In questo caso, infatti, la differenza fra i due puntatori corrisponde al numero di celle dell'array che separano la cella puntata dal puntatore di valore minore da quella del puntatore di valore maggiore.
Operatore di sottrazione di un intero da un puntatore
[modifica | modifica wikitesto]Definizione
[modifica | modifica wikitesto]L'operazione di sottrazione di un intero da un puntatore prevede un operando sinistro di tipo puntatore e un operando destro di tipo intero. Il risultato (analogamente al caso della somma) è il valore del puntatore decrementato del risultato della moltiplicazione dell'intero per la dimensione del tipo base del puntatore. Per esempio, se p è un puntatore a int di valore 1000, e la dimensione di un int è 2, p-1 vale 998.
Significato
[modifica | modifica wikitesto]Sotto le stesse condizioni descritte sopra per la somma, l'operazione di sottrazione di un intero da un puntatore consente di ricavare l'indirizzo di una cella di un array precedente a quella puntata dal puntatore su cui viene applicata la sottrazione.
Operatore di autoincremento e autodecremento di un puntatore
[modifica | modifica wikitesto]Nel linguaggio C, le operazioni di autoincremento e autodecremento di un puntatore, come quelle di autoincremento e autodecremento di numeri interi, rappresentano una forma particolare di somma e sottrazione. Esse sono definite dal seguente effetto:
x++incrementaxdi 1, e produce il valore dixprima dell'incremento++xincrementaxdi 1, e produce il valore dixdopo l'incrementox--decrementaxdi 1, e produce il valore dixprima del decremento--xdecrementaxdi 1, e produce il valore dixdopo il decremento
Tenute ferme queste definizioni, il significato di questi operatori nel caso il loro operando sia un puntatore si ricava dalla definizione di somma di puntatore e intero e di sottrazione di un intero da un puntatore.
Altri operatori
[modifica | modifica wikitesto]Le regole descritte sopra si applicano in C anche ad altri due operatori, definiti in termini degli operatori + e -:
p+=ncorrisponde ap=p+np-=ncorrisponde ap=p-n
Nota sull'overloading
[modifica | modifica wikitesto]Tutti gli operatori descritti sopra hanno, in C e nei linguaggi derivati, un significato anche nel caso gli operandi siano dati numerici non di tipo puntatore. Il fatto che lo stesso simbolo acquisisca significati (leggermente) diversi in funzione del tipo dei suoi operandi può considerarsi un caso di overloading degli operatori.
Applicazioni
[modifica | modifica wikitesto]L'uso di puntatori è spesso necessario per costruire strutture dati dinamiche (dalla forma non prevedibile a priori e/o variabile nel tempo) come grafi, alberi, liste e così via.
Un'altra applicazione classica dei puntatori consiste nel simulare il passaggio di parametri per riferimento in quei linguaggi che dispongono solo di passaggio di parametri per valore.
Note
[modifica | modifica wikitesto]Voci correlate
[modifica | modifica wikitesto]Altri progetti
[modifica | modifica wikitesto]
Wikibooks contiene testi o manuali sul puntatore
Wikiversità contiene risorse sul puntatore
Wikimedia Commons contiene immagini o altri file sul puntatore
Collegamenti esterni
[modifica | modifica wikitesto]- puntatore, su Treccani.it – Enciclopedie on line, Istituto dell'Enciclopedia Italiana.
- (EN) Denis Howe, pointer, in Free On-line Dictionary of Computing. Disponibile con licenza GFDL
| Controllo di autorità | GND (DE) 4285887-2 |
|---|