Sei sulla pagina 1di 7

2

Indirizzo di una funzione


 Si può chiamare una funzione utilizzando
l’indirizzo di memoria dal quale inizia il codice
Puntatori a funzioni eseguibile della funzione stessa
 L’indirizzo di memoria di una funzione può
essere assegnato ad una variabile puntatore,
memorizzato in un vettore, passato a una
Ver. 2.4 funzione, restituito da una funzione

© 2010 - Claudio Fornaro - Corso di programmazione in C

3 4

Definizione di variabili Definizione di variabili


 tipo (*nome)(parametri );  double (*fp)();
definisce la variabile nome come puntatore a definisce fp come variabile puntatore a una
una funzione che restituisce un valore del tipo funzione che restituisce un double, nulla è
indicato e richiede i parametri indicati indicato per i suoi parametri, quindi non
 Le parentesi intorno al nome sono necessarie vengono controllati (un compilatore C++
altrimenti si ha: invece considera l’argomento come void)
tipo *nome(parametri );  double (*fp)(double, double);
e questa costituisce il prototipo di una definisce fp come variabile puntatore a una
funzione che restituisce un puntatore del tipo funzione che ha come parametri due double
indicato e richiede i parametri indicati e restituisce un double
5 6

Definizione di variabili Inizializzazione


 int (*fpv[3])(long);  Il nome di una funzione equivale al suo
definisce fpv come vettore di 3 elementi, indirizzo di memoria (come per i vettori)
ciascuno è un puntatore a una funzione che  Con le seguenti funzioni (prototipi):
ha come parametri un long e restituisce un double pow(double,double);
int double atan2(double,double);
 Le definizioni esterne inizializzano a NULL le int f1(long), f2(long);
variabili puntatori a funzioni si possono avere le seguenti inizializzazioni:
double (*fp)(double,double) = NULL;
double (*fp)(double,double) = pow;
int (*fpv[3])(long)={f1,f2}; /*+1NULL*/
int (*fpv[3])(long)={NULL};/*3 NULL*/

7 8

Utilizzo con typedef Assegnazione


 typedef può definire un tipo puntatore a  Il nome di una funzione equivale al suo
funzione con determinati parametri e valore indirizzo di memoria (come per i vettori)
restituito  L’operatore & è ininfluente se applicato al
 typedef double (*fpType)(double,double); nome di una funzione
dichiara fpType come tipo puntatore a
 Esempi (l’operatore & può essere omesso):
funzione con due argomenti double e che
restituisce un double fp = &atan2;
fp = atan2;
 fpType fp = pow;
fpType fpv[5] = {pow,NULL,atan2}; fpv[2] = &f1;
fpv[2] = f1;
Nota: fpv[3] e fpv[4] sono inizializzati a
NULL perché l’inizializzazione dei primi
elementi impone 0 (NULL) per i rimanenti
9 10

Confronto Chiamata della funzione


 È un normale confronto tra puntatori,  La funzione il cui puntatore è stato
permette ad esempio di determinare se il memorizzato nella variabile fp può essere
puntatore si riferisce ad una certa funzione o richiamata in due modi equivalenti:
no oppure se è NULL  (*fp)(argomenti)
 fp(argomenti)
if (fp == pow)
printf("fp punta a pow\n");  Il primo metodo rende più evidente che si
tratta di un puntatore a funzione e non del
nome di una funzione, il secondo è più
leggibile e comodo
x = (*fp)(2.23, 4.76);
x = fp(2.23, 4.76);
i = (*fpv[1])(22);
i = fpv[1](22);

11 12

Passaggio a funzione Passaggio a funzione


 Un puntatore a funzione può essere passato  Esempio
ad una funzione come argomento Si supponga di avere le due funzioni seguenti:
 Questo permette di passare ad una funzione  int piu(int a,int b) fa la somma di 2
[puntatori a] funzioni diverse per ottenere numeri interi
dalla stessa funzione comportamenti diversi  int meno(int a,int b) fa la differenza di 2
numeri interi
 Il parametro attuale deve essere il nome di
m = calc(12, 23, piu);
una funzione
calcola somma dei due valori
 Il parametro formale deve essere il prototipo
n = calc(12, 23, meno);
delle funzioni chiamabili (è lì che viene
calcola la differenza dei due valori
definito il nome del puntatore visto
dall’interno della funzione stessa)
13 14

Passaggio a funzione Valore restituito da funzione


int piu(int a,int b) {return a+b;}  Una funzione può restituire un puntatore a
int meno(int a,int b) {return a-b;} funzione (2 metodi)
int calc(int x,int y,int (*funz)(int,int))  Primo metodo
{ Si definisce con l’istruzione typedef il tipo
return (*funz)(x,y); il nome funz viene del puntatore-a-funzione restituito dalla
dichiarato qui…
} funzione chiamata:
main() …e usato qui typedef int (*TipoFunz)(int,int);
{ TipoFunz è un nuovo tipo: puntatore-a-
int m, n; funzione-che-ha-2-argomenti-int-e-
m = calc(12, 23, piu); restituisce-un-int
n = calc(12, 23, meno);
E lo si usa nel solito modo:
... TipoFunz operaz(int x);

15 16

Valore restituito da funzione Valore restituito da funzione


 typedef int (*TipoFunz)(int,int);  Secondo metodo (meno chiaro)
int piu(int a,int b) {return a+b;} Si scrive ogni cast esplicitamente
int meno(int a,int b) {return a-b;} int (* operaz(int f))(int,int)
TipoFunz operaz(int f)
{ {
static TipoFunz fpv[2]={piu,meno}; static int (* fpv[2])(int,int) =
return fpv[f]; {piu,meno};
} static per poter usare return fpv[f];
main() il puntatore dopo che la }
{ funzione è terminata  La funzione definita è operaz e f ne è l’argomento
int y;
TipoFunz op; /* var. puntatore */  la parte non sottolineata è il tipo della funzione
restituita da operaz (dove (int,int) sono i
op = operaz(1); /* scelta op. */ parametri della funzione restituita)
y = (*op)(12, 23);
 static è riferito a fpv
}
17 18

Valore restituito da funzione Cast


Secondo metodo (Continuazione)  Un cast di tipo puntatore-a-funzione
main() “fa credere” al compilatore che la funzione a
{ cui viene applicato abbia il tipo di quella del
int y; puntatore
int (*op)(int,int);/*puntatore */  Si ricorda che il tipo di una funzione è definito
op = operaz(1); /* scelta op. */ dal tipo e numero dei parametri e dal tipo del
y = (*op)(12, 23); valore restituito
}
 Il cast può essere premesso al nome di una
funzione o a un puntatore a funzione
 Attenzione che il cast di tipo puntatore-a-
funzione non applica anche il cast agli
argomenti e al valore restituito

19
Passaggio a funzione con cast 20

Cast qsort
 Il cast di puntatore-a-funzione può essere  La funzione qsort in <stdlib.h> ordina un
utilizzato per rendere una funzione vettore, deve essere chiamata indicando il
compatibile con quella richiesta come nome della funzione da usare per il confronto
argomento da un’altra funzione degli elementi, il suo prototipo è:
 E’ indispensabile che gli argomenti siano void qsort(
comunque compatibili (in generale sono void *base,  puntatore al vett da riordinare
puntatori) size_t n,  sua dim (numero di elementi)
size_t size,  dim di ogni elemento (in byte)
 Si veda l’esempio del qsort seguente int (*cmp)(const void*,const void*))
cmp è il puntatore alla funzione da utilizzare
per confrontare due elementi di quel vettore
Passaggio a funzione con cast 21
Passaggio a funzione con cast 22

qsort qsort su vettore di interi


 La funzione passata per cmp deve: #include <stdlib.h>
 avere come argomenti due puntatori agli elementi #include <stdio.h>
del vettore da confrontare (qsort passerà a cmp
gli indirizzi dei due elementi mediante &base[i]) int cfr(const int *a, const int *b)
 restituire un valore int: {
if (*a < *b) return -1;
 <0 se il 1o elemento è minore del 2o
else if (*a > *b) return +1;
 0 se sono uguali else return 0;
 >0 se il 1o è maggiore del 2o }
 La clausola const indica che gli oggetti da main()
confrontare non saranno modificati {
 Il tipo void* permette di passare puntatori di int vett[10] = {3,2,5,4,7,9,0,1,6,8};
qsort(vett, 10, sizeof(int),
qualsiasi tipo: sarà la funzione passata ad (int (*)(const void*,const void*))cfr );
utilizzarli ritrasformandoli al tipo corretto }

Passaggio a funzione con cast 23


Passaggio a funzione con cast 24

qsort su vettore di interi qsort su vettore di stringhe


 La funzione passata cfr ha prototipo non  Per ordinare con qsort un vettore di stringhe
identico a quello richiesto, ma compatibile (i char *vs[10] non si può utilizzare
puntatori sono sempre assegnabili gli uni agli direttamente strcmp
altri anche se di tipo diverso); quindi viene  Gli elementi che qsort() passerebbe alla
fatto un cast della funzione passata: funzione di confronto sarebbero &vs[i], cioè
(int (*)(const void*,const void*))cfr i puntatori (indirizzi) ai puntatori agli
 I valori che la funzione qsort passa elementi, mentre strcmp() richiede
automaticamente a cfr per essere confrontati puntatori a char
sono i vari &vett[i] che vengono usati
come puntatori a int (quali sono)
Passaggio a funzione con cast 25
Passaggio a funzione con cast 26

qsort su vettore di stringhe qsort su vettore di strutture


 Bisogna definire una funzione ausiliaria:  Per ordinare un vettore di struct bisogna
int cp(const void *p1,const void *p2) definire una funzione di confronto ausiliaria:
{ int structcmp(const void *p1,
return strcmp(*(char * const *)p1, const void *p2)
*(char * const *)p2); {
} const struct nome *sp1;
 Gli argomenti di cp sono generici puntatori const struct nome *sp2;
costanti a void (const void * ), il cast sp1=(const struct nome *)p1;
(char * const *) li riconverte nel loro vero sp2=(const struct nome *)p2;
tipo (puntatore a puntatore costante a char) e if (sp1->membro > sp2->membro)
la deferenziazione produce un puntatore return +1;
costante a char come la strcmp richiede else if (...

27

Esercizi
1. Scrivere un programma che riordini con
qsort un vettore di stringhe
2. Scrivere un programma che
1. definisca un vettore di 10 struct contenenti due
valori interi x e y
2. inizializzi il vettore
3. ordini il vettore con qsort in base alla somma dei
valori (se due somme sono uguali, il confronto è
tra i primi membri, es. {4,6}>{3,7})
4. cerchi un elemento, dati i due valori in input, con
la bsearch di <stdlib.h> e ne fornisca l’indice