• Non ci sono risultati.

Indirizzo di una funzione

N/A
N/A
Protected

Academic year: 2021

Condividi "Indirizzo di una funzione"

Copied!
7
0
0

Testo completo

(1)

Puntatori a funzioni

Ver. 2.4

© 2010 - Claudio Fornaro - Corso di programmazione in C

Indirizzo di una funzione

Si può chiamare una funzione utilizzando l’indirizzo di memoria dal quale inizia il codice 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 funzione, restituito da una funzione

3

Definizione di variabili

tipo (*nome)(parametri );

definisce la variabile nome come puntatore a una funzione che restituisce un valore del tipo indicato e richiede i parametri indicati

Le parentesi intorno al nome sono necessarie altrimenti si ha:

tipo *nome(parametri );

e questa costituisce il prototipo di una

funzione che restituisce un puntatore del tipo indicato e richiede i parametri indicati

4

Definizione di variabili

double (*fp)();

definisce fp come variabile puntatore a una funzione che restituisce un double, nulla è indicato per i suoi parametri, quindi non vengono controllati (un compilatore C++

invece considera l’argomento come void)

double (*fp)(double, double);

definisce fp come variabile puntatore a una

funzione che ha come parametri due double

e restituisce un double

(2)

Definizione di variabili

int (*fpv[3])(long);

definisce fpv come vettore di 3 elementi, ciascuno è un puntatore a una funzione che ha come parametri un long e restituisce un int

Le definizioni esterne inizializzano a NULL le variabili puntatori a funzioni

Inizializzazione

Il nome di una funzione equivale al suo indirizzo di memoria (come per i vettori)

Con le seguenti funzioni (prototipi):

double pow(double,double);

double atan2(double,double);

int f1(long), f2(long);

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

Utilizzo con typedef

typedef può definire un tipo puntatore a funzione con determinati parametri e valore restituito

typedef double (*fpType)( double , double );

dichiara fpType come tipo puntatore a funzione con due argomenti double e che restituisce un double

fpType fp = pow;

fpType fpv[5] = {pow,NULL,atan2};

Nota: fpv[3] e fpv[4] sono inizializzati a NULL perché l’inizializzazione dei primi elementi impone 0 (NULL) per i rimanenti

8

Assegnazione

Il nome di una funzione equivale al suo indirizzo di memoria (come per i vettori)

L’operatore & è ininfluente se applicato al nome di una funzione

Esempi (l’operatore & può essere omesso):

fp = &atan2;

fp = atan2;

fpv[2] = &f1;

fpv[2] = f1;

(3)

Confronto

È un normale confronto tra puntatori, permette ad esempio di determinare se il puntatore si riferisce ad una certa funzione o no oppure se è NULL

if (fp == pow)

printf("fp punta a pow\n");

Chiamata della funzione

La funzione il cui puntatore è stato

memorizzato nella variabile fp può essere richiamata in due modi equivalenti:

(*fp)(argomenti)

fp(argomenti)

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

Passaggio a funzione

Un puntatore a funzione può essere passato ad una funzione come argomento

Questo permette di passare ad una funzione [puntatori a] funzioni diverse per ottenere dalla stessa funzione comportamenti diversi

Il parametro attuale deve essere il nome di una funzione

Il parametro formale deve essere il prototipo delle funzioni chiamabili (è lì che viene

definito il nome del puntatore visto dall’interno della funzione stessa)

12

Passaggio a funzione

Esempio

Si supponga di avere le due funzioni seguenti:

int piu(int a,int b) fa la somma di 2 numeri interi

int meno(int a,int b) fa la differenza di 2 numeri interi

m = calc(12, 23, piu);

calcola somma dei due valori n = calc(12, 23, meno);

calcola la differenza dei due valori

(4)

Passaggio a funzione

int piu(int a,int b) {return a+b;}

int meno(int a,int b) {return a-b;}

int calc( int x, int y, int (*funz)(int,int) ) {

return (*funz)(x,y);

}

main() {

int m, n;

m = calc(12, 23, piu);

n = calc(12, 23, meno);

...

il nome funz viene dichiarato qui…

…e usato qui

Valore restituito da funzione

Una funzione può restituire un puntatore a funzione (2 metodi)

Primo metodo

Si definisce con l’istruzione typedef il tipo del puntatore-a-funzione restituito dalla funzione chiamata:

typedef int (*TipoFunz)(int,int);

TipoFunz è un nuovo tipo: puntatore-a- funzione-che-ha-2-argomenti- int -e- restituisce-un- int

E lo si usa nel solito modo:

TipoFunz operaz(int x);

15

Valore restituito da funzione

typedef int (*TipoFunz)(int,int);

int piu(int a,int b) {return a+b;}

int meno(int a,int b) {return a-b;}

TipoFunz operaz(int f) {

static TipoFunz fpv[2]={piu,meno};

return fpv[f];

}

main() {

int y;

TipoFunz op; /* var. puntatore */

op = operaz(1); /* scelta op. */

y = (*op)(12, 23);

}

static per poter usare il puntatore dopo che la

funzione è terminata

16

Valore restituito da funzione

Secondo metodo (meno chiaro) Si scrive ogni cast esplicitamente

int (* operaz(int f))(int,int) {

static int (* fpv[2])(int,int) = {piu,meno};

return fpv[f];

}

La funzione definita è operaz e f ne è l’argomento

la parte non sottolineata è il tipo della funzione restituita da operaz (dove (int,int) sono i parametri della funzione restituita)

static è riferito a fpv

(5)

Valore restituito da funzione

Secondo metodo (Continuazione) main()

{

int y;

int (*op)(int,int);/*puntatore */

op = operaz(1); /* scelta op. */

y = (*op)(12, 23);

}

Cast

Un cast di tipo puntatore-a-funzione

“fa credere” al compilatore che la funzione a cui viene applicato abbia il tipo di quella del puntatore

Si ricorda che il tipo di una funzione è definito dal tipo e numero dei parametri e dal tipo del 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

Cast

Il cast di puntatore-a-funzione può essere utilizzato per rendere una funzione

compatibile con quella richiesta come argomento da un’altra funzione

E’ indispensabile che gli argomenti siano comunque compatibili (in generale sono puntatori)

Si veda l’esempio del qsort seguente

Passaggio a funzione con cast

20

qsort

La funzione qsort in <stdlib.h> ordina un vettore, deve essere chiamata indicando il nome della funzione da usare per il confronto degli elementi, il suo prototipo è:

void qsort(

void *base,  puntatore al vett da riordinare

size_t n,  sua dim (numero di elementi)

size_t size,  dim di ogni elemento (in byte)

int (*cmp)(const void*,const void*) )

cmp è il puntatore alla funzione da utilizzare

per confrontare due elementi di quel vettore

(6)

Passaggio a funzione con cast

qsort

La funzione passata per cmp deve:

avere come argomenti due puntatori agli elementi del vettore da confrontare (qsort passerà a cmp gli indirizzi dei due elementi mediante &base[i])

restituire un valore int:

<0 se il 1

o

elemento è minore del 2

o

0 se sono uguali

>0 se il 1

o

è maggiore del 2

o

La clausola const indica che gli oggetti da confrontare non saranno modificati

Il tipo void* permette di passare puntatori di qualsiasi tipo: sarà la funzione passata ad utilizzarli ritrasformandoli al tipo corretto

Passaggio a funzione con cast

qsort su vettore di interi

#include <stdlib.h>

#include <stdio.h>

int cfr(const int *a, const int *b) {

if (*a < *b) return -1;

else if (*a > *b) return +1;

else return 0;

}

main() {

int vett[10] = {3,2,5,4,7,9,0,1,6,8};

qsort(vett, 10, sizeof(int),

(int (*)(const void*,const void*))cfr );

}

Passaggio a funzione con cast

23

qsort su vettore di interi

La funzione passata cfr ha prototipo non identico a quello richiesto, ma compatibile (i puntatori sono sempre assegnabili gli uni agli altri anche se di tipo diverso); quindi viene fatto un cast della funzione passata:

( int (*)(const void*,const void*) ) cfr

I valori che la funzione qsort passa

automaticamente a cfr per essere confrontati sono i vari &vett[i] che vengono usati

come puntatori a int (quali sono)

Passaggio a funzione con cast

24

qsort su vettore di stringhe

Per ordinare con qsort un vettore di stringhe char *vs[10] non si può utilizzare

direttamente strcmp

Gli elementi che qsort() passerebbe alla funzione di confronto sarebbero &vs[i], cioè i puntatori (indirizzi) ai puntatori agli

elementi, mentre strcmp() richiede

puntatori a char

(7)

Passaggio a funzione con cast

qsort su vettore di stringhe

Bisogna definire una funzione ausiliaria:

int cp( const void *p1,const void *p2 ) {

return strcmp(* (char * const *) p1,

* (char * const *) p2);

}

Gli argomenti di cp sono generici puntatori costanti a void (const void * ), il cast (char * const *) li riconverte nel loro vero tipo (puntatore a puntatore costante a char) e la deferenziazione produce un puntatore

costante a char come la strcmp richiede

Passaggio a funzione con cast

qsort su vettore di strutture

Per ordinare un vettore di struct bisogna definire una funzione di confronto ausiliaria:

int structcmp(const void *p1, const void *p2) {

const struct nome *sp1;

const struct nome *sp2;

sp1=(const struct nome *)p1;

sp2=(const struct nome *)p2;

if (sp1->membro > sp2->membro) return +1;

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

Riferimenti

Documenti correlati

Il tempo neces- sario per stabilire la connessione col sito A ` e descritto da una variabile aleatoria T A con legge (assolutamente continua) uniforme sull’intervallo [0, 40]

ƒ restituisce un puntatore che contiene l’indirizzo del blocco di memoria allocato, cioè della variabile, la quale sarà quindi accessibile dereferenziando il puntatore. ƒ la

■ Quindi il vero argomento della prima funzione non é la seconda funzione, ma un normale valore, che può avere qualsiasi origine (variabile, espressione ecc...), e in particolare

Generalmente il confronto può essere fatto tra due generici puntatori che puntano allo stesso tipo di dato; questo confronto è comunque significativo solo nel caso in

Calcolo dell’area di un dominio mediante l’integrale doppio della funzione identicamente uguale

Per la variabile di Student `e stata progettata questa tavole poich`e sono i quantili che vengono utilizzati nella ricerca degli intervalli di fiducia o della regione critica del

Test sulla media di una popolazione normale (casi di varianza nota e non nota).. Test

conta_divisibili (int quadrati[], int valori[], int n_valori, int contatori[]) che scrive in ciascun elemento del vettore contatori (anch’esso di dimensione N) quanti elementi