Puntatori a funzioni nella programmazione in C con esempi
I puntatori offrono grandi possibilitร alle funzioni "C" che siamo limitati a restituire un valore. Con i parametri del puntatore, le nostre funzioni ora possono elaborare i dati effettivi anzichรฉ una copia dei dati.
Per modificare i valori effettivi delle variabili, l'istruzione chiamante passa gli indirizzi ai parametri del puntatore in una funzione.
Esempio di puntatori di funzioni
Ad esempio, il programma successivo scambia due valori di due:
void swap (int *a, int *b);
int main() {
int m = 25;
int n = 100;
printf("m is %d, n is %d\n", m, n);
swap(&m, &n);
printf("m is %d, n is %d\n", m, n);
return 0;}
void swap (int *a, int *b) {
int temp;
temp = *a;
*a = *b;
*b = temp;}
}
Produzione:
m is 25, n is 100 m is 100, n is 25
Il programma scambia i valori effettivi delle variabili perchรฉ la funzione vi accede tramite l'indirizzo utilizzando pointer. Qui discuteremo il processo del programma:
- Dichiariamo la funzione responsabile dello scambioping i due valori delle variabili, che accetta due puntatori interi come parametri e restituisce un valore qualsiasi quando viene chiamata.
- Nella funzione principale, dichiariamo e inizializziamo due variabili intere ('m' e 'n'), quindi stampiamo rispettivamente i loro valori.
- Chiamiamo la funzione swap() passando l'indirizzo delle due variabili come argomenti utilizzando il simbolo della e commerciale. Successivamente, stampiamo i nuovi valori scambiati delle variabili.
- Qui definiamo il contenuto della funzione swap() che accetta due indirizzi di variabili intere come parametri e dichiariamo una variabile intera temporanea utilizzata come terza casella di archiviazione per salvare una delle variabili valore che verrร inserita nella seconda variabile.
- Salva il contenuto della prima variabile puntata da "a" nella variabile temporanea.
- Memorizza la seconda variabile puntata da b nella prima variabile puntata da a.
- Aggiorna la seconda variabile (indicata da b) con il valore della prima variabile salvata nella variabile temporanea.
Funzioni con parametri di array
In C, non possiamo passare un array per valore a una funzione. Considerando che il nome di un array รจ un puntatore (indirizzo), quindi passiamo semplicemente un nome di array a una funzione che significa passare un puntatore all'array.
Ad esempio, consideriamo il seguente programma:
int add_array (int *a, int num_elements);
int main() {
int Tab[5] = {100, 220, 37, 16, 98};
printf("Total summation is %d\n", add_array(Tab, 5));
return 0;}
int add_array (int *p, int size) {
int total = 0;
int k;
for (k = 0; k < size; k++) {
total += p[k]; /* it is equivalent to total +=*p ;p++; */}
return (total);}
Produzione:
Total summation is 471
Qui spiegheremo il codice del programma con i suoi dettagli
- Dichiariamo e definiamo la funzione add_array() che accetta un indirizzo di array (puntatore) con il suo numero di elementi come parametri e restituisce la somma totale accumulata di questi elementi. Il puntatore viene utilizzato per iterare gli elementi dell'array (usando la notazione p[k]) e accumuliamo la somma in una variabile locale che verrร restituita dopo aver iterato l'intero elemento dell'array.
- Dichiariamo e inizializziamo un array di numeri interi con cinque elementi interi. Stampiamo la somma totale passando il nome dell'array (che funge da indirizzo) e la dimensione dell'array al file aggiungi_array()chiamata funzione come argomenti.
Funzioni che restituiscono un array
In C, possiamo restituire un puntatore a un array, come nel seguente programma:
#include <stdio.h>
int * build_array();
int main() {
int *a;
a = build_array(); /* get first 5 even numbers */
for (k = 0; k < 5; k++)
printf("%d\n", a[k]);
return 0;}
int * build_array() {
static int Tab[5]={1,2,3,4,5};
return (Tab);}
Produzione:
1 2 3 4 5
E qui discuteremo i dettagli del programma
- Definiamo e dichiariamo una funzione che restituisce un indirizzo di array contenente un valore intero e non accetta argomenti.
- Dichiariamo un puntatore intero che riceve l'array completo costruito dopo la chiamata della funzione e stampiamo il suo contenuto eseguendo l'iterazione dell'intero array di cinque elementi.
Si noti che per memorizzare l'indirizzo dell'array restituito dalla funzione viene definito un puntatore, non un array. Nota anche che quando una variabile locale viene restituita da una funzione, dobbiamo dichiararla come statica nella funzione.
Puntatori di funzioni
Poichรฉ sappiamo per definizione che i puntatori puntano a un indirizzo in qualsiasi posizione di memoria, possono anche puntare all'inizio del codice eseguibile come funzioni in memoria.
Un puntatore a una funzione viene dichiarato con *, l'istruzione generale della sua dichiarazione รจ:
return_type (*function_name)(arguments)
Devi ricordare che le parentesi attorno a (*nome_funzione) sono importanti perchรฉ senza di esse, il compilatore penserร che nome_funzione restituisca un puntatore di tipo_ritorno.
Dopo aver definito il puntatore di funzione, dobbiamo assegnarlo a una funzione. Ad esempio, il programma seguente dichiara una funzione ordinaria, definisce un puntatore di funzione, assegna il puntatore di funzione alla funzione ordinaria e dopodichรฉ chiama la funzione tramite il puntatore:
#include <stdio.h>
void Hi_function (int times); /* function */
int main() {
void (*function_ptr)(int); /* function pointer Declaration */
function_ptr = Hi_function; /* pointer assignment */
function_ptr (3); /* function call */
return 0;}
void Hi_function (int times) {
int k;
for (k = 0; k < times; k++) printf("Hi\n");}
Produzione:
Hi Hi Hi
- Definiamo e dichiariamo una funzione standard che stampa un testo Hi k volte indicato dal parametro times quando viene chiamata la funzione
- Definiamo una funzione puntatore (con la sua dichiarazione speciale) che accetta un parametro intero e non restituisce nulla.
- Inizializziamo la nostra funzione puntatore con la funzione Hi_, il che significa che il puntatore punta alla funzione Hi_().
- Invece della chiamata di funzione standard da parte di taping il nome della funzione con argomenti, chiamiamo solo la funzione puntatore passando il numero 3 come argomento, e questo รจ tutto!
Tieni presente che il nome della funzione punta all'indirizzo iniziale del codice eseguibile come un nome di array che punta al suo primo elemento. Pertanto, istruzioni come function_ptr = &Hi_function e (*funptr)(3) sono corrette.
NOTA: Non รจ importante inserire l'operatore di indirizzo & e l'operatore indiretto * durante l'assegnazione della funzione e la chiamata della funzione.
Matrice di puntatori a funzioni
Un array di puntatori a funzione puรฒ svolgere un ruolo di interruttore o di istruzione if per prendere una decisione, come nel prossimo programma:
#include <stdio.h>
int sum(int num1, int num2);
int sub(int num1, int num2);
int mult(int num1, int num2);
int div(int num1, int num2);
int main()
{ int x, y, choice, result;
int (*ope[4])(int, int);
ope[0] = sum;
ope[1] = sub;
ope[2] = mult;
ope[3] = div;
printf("Enter two integer numbers: ");
scanf("%d%d", &x, &y);
printf("Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: ");
scanf("%d", &choice);
result = ope[choice](x, y);
printf("%d", result);
return 0;}
int sum(int x, int y) {return(x + y);}
int sub(int x, int y) {return(x - y);}
int mult(int x, int y) {return(x * y);}
int div(int x, int y) {if (y != 0) return (x / y); else return 0;}
Enter two integer numbers: 13 48 Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: 2 624
Qui discutiamo i dettagli del programma:
- Ne dichiariamo e ne definiamo quattro funzioni che prendono due argomenti interi e restituiscono un valore intero. Queste funzioni sommano, sottraggonotract, moltiplica e dividi i due argomenti relativi alla funzione che viene chiamata dall'utente.
- Dichiariamo 4 numeri interi per gestire rispettivamente gli operandi, il tipo di operazione e il risultato. Inoltre, dichiariamo un array di quattro puntatori a funzione. Ogni puntatore a funzione dell'elemento dell'array accetta due parametri interi e restituisce un valore intero.
- Assegniamo e inizializziamo ogni elemento dell'array con la funzione giร dichiarata. Ad esempio, il terzo elemento che รจ il terzo puntatore a funzione punterร alla funzione dell'operazione di moltiplicazione.
- Cerchiamo operandi e tipo di operazione digitati dall'utente con la tastiera.
- Abbiamo chiamato l'elemento appropriato dell'array (puntatore a funzione) con argomenti e memorizziamo il risultato generato dalla funzione appropriata.
L'istruzione int (*ope[4])(int, int); definisce l'array di puntatori a funzione. Ogni elemento dell'array deve avere gli stessi parametri e tipo restituito.
L'istruzione result = ope[choice](x, y); esegue la funzione appropriata in base alla scelta fatta dall'utente. I due interi immessi sono gli argomenti passati alla funzione.
Funzioni che utilizzano puntatori void
I puntatori void vengono utilizzati durante le dichiarazioni di funzioni. Usiamo un void * return type permette di restituire qualsiasi tipo. Se assumiamo che i nostri parametri non cambino quando passiamo a una funzione, lo dichiariamo come const.
Per esempio:
void * cube (const void *);
Considera il seguente programma:
#include <stdio.h>
void* cube (const void* num);
int main() {
int x, cube_int;
x = 4;
cube_int = cube (&x);
printf("%d cubed is %d\n", x, cube_int);
return 0;}
void* cube (const void *num) {
int result;
result = (*(int *)num) * (*(int *)num) * (*(int *)num);
return result;}
Risultato:
4 cubed is 64
Qui discuteremo i dettagli del programma:
- Definiamo e dichiariamo una funzione che restituisce un valore intero e accetta un indirizzo di variabile immutabile senza un tipo di dati specifico. Calcoliamo il valore del cubo della variabile content (x) puntata dal puntatore num, e poichรฉ รจ un puntatore void, dobbiamo digitarlo cast su un tipo di dati intero usando un puntatore di notazione specifica (* datatype), e restituiamo il valore del cubo.
- Dichiariamo l'operando e la variabile risultato. Inoltre, inizializziamo il nostro operando con il valore โ4โ.
- Chiamiamo la funzione cubo passando l'indirizzo dell'operando e gestiamo il valore restituito nella variabile risultato
Puntatori a funzioni come argomenti
Un altro modo per sfruttare un puntatore a funzione passandolo come argomento a un'altra funzione talvolta chiamata "funzione di callback" perchรฉ la funzione ricevente "lo richiama".
Nel file di intestazione stdlib.h, la funzione Quicksort โqsort()โ utilizza questa tecnica che รจ un algoritmo dedicato all'ordinamento di un array.
void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
- void *base: puntatore void all'array.
- size_t num: il numero dell'elemento dell'array.
- size_t larghezza La dimensione dell'elemento.
- int (*compare (const void *, const void *) : puntatore a funzione composto da due argomenti e restituisce 0 quando gli argomenti hanno lo stesso valore, <0 quando arg1 viene prima di arg2 e >0 quando arg1 viene dopo arg2.
Il seguente programma ordina un array di numeri interi dal piรน piccolo al piรน grande utilizzando la funzione qsort():
#include <stdio.h>
#include <stdlib.h>
int compare (const void *, const void *);
int main() {
int arr[5] = {52, 14, 50, 48, 13};
int num, width, i;
num = sizeof(arr)/sizeof(arr[0]);
width = sizeof(arr[0]);
qsort((void *)arr, num, width, compare);
for (i = 0; i < 5; i++)
printf("%d ", arr[ i ]);
return 0;}
int compare (const void *elem1, const void *elem2) {
if ((*(int *)elem1) == (*(int *)elem2)) return 0;
else if ((*(int *)elem1) < (*(int *)elem2)) return -1;
else return 1;}
Risultato:
13 14 48 50 52
Qui discuteremo i dettagli del programma:
- Definiamo la funzione di confronto composta da due argomenti e restituisce 0 quando gli argomenti hanno lo stesso valore, <0 quando arg1 viene prima di arg2 e >0 quando arg1 viene dopo arg2. I parametri sono un tipo di puntatori void espressi nel tipo di dati dell'array appropriato (numero intero)
- Definiamo e inizializziamo un array di numeri interi. La dimensione dell'array รจ memorizzata nel file num variabile e la dimensione di ciascun elemento dell'array viene memorizzata nella variabile larghezza utilizzando sizeof() predefinito Operatore C.
- Noi chiamiamo la qsort funzione e passare il nome dell'array, la dimensione, la larghezza e la funzione di confronto definita in precedenza dall'utente per ordinare il nostro array in ordine crescente. Il confronto verrร eseguito prendendo in ogni iterazione due elementi dell'array fino a quando l'intero array non sarร ordinato.
- Stampiamo gli elementi dell'array per essere sicuri che il nostro array sia ben ordinato eseguendo l'iterazione dell'intero array utilizzando per loop.







