- 0 Discussione
-
I Puntatori
Indice |
Introduzione
Modifica
Ebbene sì, i puntatori esistono anche in D, sono identici a quelli del linguaggio C/C++. L'unica differenza è che in D, non è necessario utilizzarli per ogni cosa.
NOTA
Questa sezione è dedicata a chi non ha mai avuto a che fare con i puntatori, chi conosce già
queste cose può benissimo saltare questa parte
Cos'è un puntatore??
Modifica
I puntatori sono dei tipi speciali che rappresentano un indirizzo di memoria, e puntano a un qualunque tipo di dato, sia esso un tipo nativo (es. int, float, bool) oppure un oggetto (es. struttura o classe)
In sostanza un puntatore è la rappresentazione astratta di un indirizzo di memoria.
Utilizzo dei puntatori
Modifica
Dichiarazione
Modifica
Un puntatore si dichiara in maniera molto simile alle variabili, chi conosce il C/C++, può notare che si dichiarano allo stesso modo:
int* pInt; //Dichiarazione di un puntatore di tipo 'int'
E' sufficiente aggiungere il simbolo '*' dopo il tipo.
Associare l'indirizzo di una variaible ad un puntatore
Modifica
Una delle operazioni classiche dei puntatori, e associarlo ad un indirizzo di una variabile (si dice: Far Puntare Un Puntatore)
int num = 45; //Dichiaro una variabile di tipo 'int' chiamata 'num' //Puntatore di tipo int int* pNum = # //'pNum' punta all'indirizzo di 'num'
Sappiamo che il tipo seguito dal simbolo'*' sta a significare che quella variabile è un puntatore (in questo caso si dice puntatore di tipo int). Il simbolo '&' posto prima del nome della variabile sta a significare l'indirizzo di...; in questo caso l'indirizzo della variabile num.
In conclusione possiamo dire: La variabile "pNum" punta all'indirizzo di "num". Nel paragrafo successivo vedremo come modificare il valore di una variabile utilizzando un puntatore al posto di modificarla direttamente.
L'illustrazione del sorgente con uno scherma sarebbe la seguente:
Dereferenziare un puntatore
Modifica
Come possiamo sapere a cosa sta puntando un puntatore?? E' molto semplice, basta dereferenziare una variabile-puntatore e per accesso al valore cui punta. Per dereferenziare si mette il simbolo '*' prima del nome della variabile-puntatore da dereferenziare, riferendoci all'esempio precedente:
int num = 45; //Classica variabile int* pNum = # //Ci faccio puntare un puntatore int numVal = *pNum; //Ora abbiamo accesso al valore puntato da 'pNum' (ovvero: 45)
Utilità dei puntatori
Modifica
La domanda probabilmente sorge spontanea: A cosa mi possono avere i puntatori??. All'inizio probabilmente penserete che siano qualcosa di superfluo o non indispensabile, ma in certi casi, sono l'unico modo per fare determinate operazioni, anche se non abbiamo visto ancora le strutture, anticipo i tempi, per far vedere cosa possono fare i puntatori:
//Struttura 'Point'
struct Point
{
int x;
int y;
}
int main(string[] args)
{
int[2] intArray; //Array di due elementi
//Assegno i due elementi
intArray[0] = 25;
intArray[1] = 30;
/* Se volessimo che quei due valori fossero trattati come due membri di una struttura Point
* possiamo creare un puntatore di tipo 'Point' che punti all'inizio dell'array e 'come per magia'
* avremo una struttura Point, con x = 25, e y = 30.
*/
Point* pPoint; //Puntatore di tipo Point
//DOBBIAMO FARE IL CAST ESPLICITO
//In stile C/C++
pPoint = cast(Point*)&intArray;
//...o utilizzando le proprietà del D.
pPoint = cast(Point*)intArray.ptr;
writefln("x: %d", pPoint.x);
writefln("y: %d", pPoint.y);
}
Output: x: 25 y: 30
Abbiamo 'trasformato' un array di due elementi in una struttura 'Point', ora la domanda sorge spontanea: cosa abbiamo fatto effettivamente??
NOTA IMPORTANTE
Il tipo int è grande 4 bytes, e sulla ram i valori sono 'rivoltati' quindi ad esempio, il
numero 25 è visto: 25 00 00 00
E' molto semplice, in memoria un array è semplicemente una sequenza di bytes, quindi fisicamente il nostro array è disposto nel seguente modo:
E' sufficiente ricavare l'indirizzo di dove inizia l'array, per farci puntare un puntatore di un qualunque tipo; questo è valido sempre.
Puntatori void*
Modifica
Come sappiamo il tipo void sta a significare nulla, questo tipo, però applicato ai puntatori da vita al tipo void* ovvero: puntatore a un tipo non definito. E' possibile effettuare il cast in qualunque altro tipo puntatore.
NOTA IMPORTANTE
Quando utilizziamo il token '&' su una variabile-puntatore, viene restituito SEMPRE un puntatore
di tipo void* ed ecco spiegato il motivo per cui ci vuole SEMPRE un cast esplicito, è
impossibile usare il puntatore di tipo void* senza prima specificare esplicitamente a che
tipo di dato punterà