C/Vettori e puntatori/Puntatori
Wikibooks, manuali e libri di testo liberi.
I puntatori, in C, sono uno strumento molto potente e utile, ma sono anche frequente causa di errori insidiosi.
Un puntatore è una variabile che contiene l'indirizzo di memoria di un'altra variabile (il puntatore x punta alla variabile y).
Indice |
[modifica] Sintassi
[modifica] Dichiarazione
Un puntatore si dichiara nel seguente modo:
int *a;
Si noti l'asterisco prima del nome del puntatore.
int *a, b;
Il precedente codice non genera due puntatori, ma uno solo, a. La variabile b è semplicemente un intero, perché l'operatore * vale soltanto per una variabile. Qualora si desideri dichiarare più variabili di tipo puntatore, l'asterisco va ripetuto per ciascuna di esse:
int *a, *b; // sia a che b sono puntatori a variabile intera
È possibile creare array di puntatori:
int *a[5];
crea un array di cinque puntatori ad intero. Per maggiori informazioni vedere la sezione sugli array.
[modifica] Assegnamento
Prima di utilizzare un puntatore, bisogna assegnarlo ad un indirizzo di memoria, ovvero fare in modo che esso punti ad una variabile.
int *a; int b; b=10; a=&b;
Questo codice fa puntare il puntatore a alla variabile b. È importante notare che a non contiene il valore 10, ma l'indirizzo di memoria della variabile b, ottenuto tramite l'operatore &.
È anche possibile fare in modo che un puntatore punti alla stessa variabile puntata da un altro puntatore:
int *a, *c; int b; b=10; a=&b; c=a; // c punta a b
[modifica] Accesso
Dopo aver dichiarato e assegnato un puntatore ad una variabile, è possibile usarlo.
int *a, *b; int c; c=10; a=&c; b=a; printf("La variabile c, puntata da a, vale %d, mentre la stessa variabile puntata da b vale %d.", *a, *b);
Questo codice stamperà due volte il numero 10.
[modifica] Aritmetica dei puntatori
È possibile addizionare o sottrarre ad un puntatore un valore intero. Questo farà in modo che il puntatore punti alla cella di memoria immediatamente successiva.
Se un intero occupa 2 byte, allora se si somma 1 al puntatore che contiene l'indirizzo 100, questo non conterrà 101, ma 102. Questo appunto perché si assume che un intero occupi 2 byte.
Al contrario, se si sottrae 1, il puntatore conterrà il valore 98.
Inoltre, è possibile calcolare la differenza tra due puntatori per capire quante celle di memoria ci sono fra i due. È possibile anche confrontarli per capire se puntano allo stesso indirizzo o meno.
if (p1 == p2) printf("p1 e p2 puntano allo stesso indirizzo di memoria."); else printf("p1 e p2 puntano a due differenti indirizzi di memoria.");
L'aritmetica dei puntatori permette anche l'interscambiabilità tra puntatori e vettori.
[modifica] Puntatori a funzioni
È possibile far puntare un puntatore ad una funzione, in modo che essa possa essere chiamata attraverso il puntatore. Anche le funzioni, come le variabili, hanno un indirizzo di memoria.
Il seguente esempio definisce, assegna e utilizza un puntatore a funzione:
#include <stdio.h> int doubleof(int x) { return x*2; } int main(void) { int (*funz)(int); funz=doubleof; printf("Il doppio di 2 è %d", funz(2)); return 0; }
Si noti che il tipo del puntatore "funz" è uguale al tipo dalla funzione "doubleof". Il tipo di una funzione è costituito dalla sequenza dei tipi dei parametri e dal tipo di ritorno. Quindi per assegnare un indirizzo di una funzione a un puntatore a funzione è necessario che la funzione e il puntatore abbiano lo stesso numero di parametri, che i parametri corrispondenti abbiano lo stesso tipo, e il tipo di ritorno sia lo stesso.
Da notare inoltre che in questo caso non è stato usato l'operatore di referenziazione & come negli esempi precedenti, infatti, i nomi delle funzioni sono già dei puntatori.
[modifica] Puntatori a puntatori
È possibile definire anche puntatori ad altri puntatori che potrebbero a loro volta puntare a puntatori ecc.
char **lista; char a[]="prova 1"; char b[]="prova 2"; char c[]="prova 3"; lista = malloc (3*sizeof(char*)); *lista=a; *(lista+1)=b; *(lista+2)=c; printf ("Tre prove %s %s %s",*lista,*(lista+1),*(lista+2));