Una variabile puntatore è una variabile che contiene l’indirizzo di memoria di un’altra variabile. In C++, per conoscere l’indirizzo di una variabile,
è sufficiente far precedere al nome della variabile l’operatore &. Supponiamo che la variabile intera x, raffigurata nel riquadro di sinistra,
sia allocata all’indirizzo di memoria 7500. con l'istruzione
p_x=&x; la variabile p_x conterrà l’indirizzo della variabile x.
Per accedere al contenuto della cella il cui indirizzo è memorizzato in p_x è sufficiente far precedere alla variabile puntatore il carattere asterisco (*).
p_x = & x; *p_x = 20;
float vArray[20]; float *ptArray; ptArray=vArray; // equivale a: ptArray=&vArray[0];Per poter capire a cosa serve un puntatore, è necessario sapere che la memoria del calcolatore in cui possono risiedere le variabili è suddivisa in due parti:
In C++ (come in C) esistono i puntatori a funzione. Questi servono quando il programma deve scegliere quale funzione chiamare
fra diverse possibili. La scelta non é definita a priori ma dipende dai dati del programma stesso.
Questo processo si chiama late binding ("aggancio ritardato"): gli indirizzi delle funzioni da chiamare non vengono risolti
al momento della compilazione, come avviene normalmente (early binding) ma al momento dell'esecuzione.
Il C tratta i nomi delle funzioni come se fossero dei puntatori alle
funzioni stesse. Quindi, quando vogliamo assegnare ad un puntatore a funzione
l'indirizzo di una certa funzione dobbiamo effettuare un operazione
di assegnamento del nome della funzione al nome del puntatore a
funzione.
Un puntatori a funzione viene dichiarato in questo modo:
tipoR (*NomeFunz)(tipo1, tipo2, ... , tipoN );
Dichiara un puntatore a funzione NomeFunz che restituisce un puntatore a tipoR e che ha N argomenti di tipo: tipo1,...tipoN.
Le parentesi intorno al nome della funzione consentono la corretta interpretazione dell'istruzione.
Durante l'esecuzione del programma il puntatore a funzione deve essere assegnato (o inizializzato) con il nome di una funzione "vera",
che deve essere precedentemente dichiarata con gli stessi argomenti e lo stesso tipo di valore di ritorno dichiarato nel puntatore a funzione.
Continuando l'esempio precedente:
#include <stdio.h> #include <stdlib.h> int somma(int a, int b) { return a+b; } int differenza(int a, int b) { return a-b; } int prodotto(int a, int b) { return a*b; } int main() { int a, b, r; char op; int (*funz)(int,int); printf("Calcola: "); scanf("%d %c %d",&a,&op,&b); if (op=='+') funz=somma; else if (op=='-') funz=prodotto; else if (op=='*') funz=prodotto; else exit(0); r=(*funz)(a,b); // utilizzo il puntatore alla funzione // potevo scrivere anche: r=funz(a,b); printf("%d %c %d = %d",a,op,b,r); // metto in stop il programma prima della sua chiusura fflush(stdin); getchar(); return(0); }notare che i nomi delle funzioni e del puntatore vanno indicati da soli, senza i loro argomenti (e senza le parentesi). In una chiamata della funzione non è necessario deferenziare ovvero posso scrivere sia
(*pfunz)(12.3,"Ciao");oppure
pfunz(12.3,"Ciao");
In C++ (come in C) è consentito dichiarare anche array di puntatori a funzione, con questa sintassi:
tipoR (*NomeFunz[dim])(tipo1, tipo2, ... , tipoN );
#includeint quale(char c) { return ( (c=='+') ? 0 : ((c=='-') ? 1 : 2) ); } int somma(int a, int b) { return a+b; } int differenza(int a, int b) { return a-b; } int prodotto(int a, int b) { return a*b; } int main() { int a, b, r; char op; int (*funz[3])(int,int)={ somma , differenza , prodotto }; printf("Calcola: "); scanf("%d %c %d",&a,&op,&b); r=funz[quale(op)](a,b); // utilizzo il puntatore alla funzione //r=(*funz[quale(op)])(a,b); // utilizzo del puntatore dereferenziato printf("%d %c %d = %d",a,op,b,r); // metto in stop il programma prima della sua chiusura fflush(stdin); getchar(); return(0); }
Quando invece una funzione dichiara fra i suoi argomenti un puntatore a funzione, allora sono parametrizzate proprio le funzioni e non i loro valori di ritorno. Nelle chiamate é necessario specificare come argomento il nome di una funzione "vera", precedentemente dichiarata, che viene sostituito a quello del puntatore.
Tipo NomeFunzione(param1, param2,...,tipoR (*NomeFunz)(tipo1, tipo2, ... , tipoN ), .. , paramN);
#include <stdio.h> int min(int a, int b) { return (a > b) ? b : a ; } int max(int a, int b) { return (a > b) ? a : b ; } // prototype o forward declaration int statistica(char *frase, int a, int b, int (*)(int, int)); int main() { int a, b, r; printf("Digita 2 numeri a b: "); scanf("%d %d",&a,&b); statistica("Minimo",a,b,min); statistica("Massimo",a,b,max); // metto in stop il programma prima della sua chiusura fflush(stdin); getchar(); return(0); } int statistica(char *frase, int a, int b, int (*stat)(int, int)) { printf("%s: %d\n",frase, (*stat)(a,b)); } // oppure posso usare il puntatore dereferenziato: // int statistica(char *frase, int a, int b, int (*stat)(int, int)) { printf("%s: %d\n",frase, stat(a,b)); }
Link utili
http://www.math.unipd.it/~sperduti/CORSO-C%2B%2B/Strutture.htm