In generale, un puntatore è una variabile che contiene un indirizzo. Allora, ha senso che possano esistere puntatori a tutti gli oggetti dotati di indirizzo. Finora, si è visto che le variabili hanno un indirizzo, mentre ad esempio le espressioni non lo hanno. Un altro oggetto caratterizzato da un indirizzo sono le funzioni: una funzione è rappresentata da una sequenza di istruzioni in memoria, dunque il suo indirizzo è l’indirizzo della prima istruzione (quella a cui si salta quando la funzione viene chiamata). Perciò, il linguaggio C consente la definizione di puntatori a funzione.
Esistono tanti tipi di puntatori a funzione — uno per ogni possibile prototipo di funzione (cioè per ogni combinazione di tipo restituito e tipi dei parametri). La sintassi per definire un puntatore a funzione è
tipo_restituito (*nome)(tipi_parametri)
dove:
void
) dalle funzioni a cui il puntatore potrà puntarevoid
) di tipi dei parametri formali accettati dalle funzioni a cui il puntatore potrà puntare.Questa sintassi è ispirata alla sintassi dei prototipi di funzione e al modo in cui il puntatore viene suato una volta definito: (*nome)
è l’oggetto puntato da *nome
,* ed è appunto una funzione con un prototipo corrispondente a indicato nella definizione di nome
.
Ad esempio, data una funzione f
con prototipo
int f(short, double);
un puntatore chiamato ptr_to_f
che è del tipo giusto per puntare a f
viene definito nel modo seguente:
int (*ptr_to_f)(short, double);
In C, così come il nome di un array può essere interpretato come un puntatore al suo primo elemento, anche il nome di una funzione corrisponde a un puntatore alla funzione stessa (ovvero alla sua prima istruzione). Di conseguenza, dati il puntatore ptr_to_f
e la funzione f
mostrati prima, per assegnare a ptr_to_f
l’indirizzo di f
è sufficiente scrivere:
ptr_to_f = f;
Una volta assegnato un indirizzo, quando si vuole invocare la funzione puntata, si usa prima l’operatore di indirizzamento indiretto per passare dal puntatore alla funzione puntata, e poi si usa la normale sintassi di chiamata con le parentesi. Ad esempio, se ptr_to_f
contiene l’indirizzo di f
, l’invocazione
int x = (*ptr_to_f)(5, 8.64);
equivale a