Pointeurs de fonctions en programmation C avec exemples
Les pointeurs donnent de grandes possibilitรฉs aux fonctions 'C' qui sont limitรฉes ร renvoyer une seule valeur. Avec les paramรจtres de pointeur, nos fonctions peuvent dรฉsormais traiter des donnรฉes rรฉelles plutรดt qu'une copie de donnรฉes.
Afin de modifier les valeurs rรฉelles des variables, l'instruction appelante transmet les adresses aux paramรจtres de pointeur dans une fonction.
Exemple de pointeurs de fonctions
Par exemple, le programme suivant รฉchange deux valeurs sur deux :
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;}
}
Sortie :
m is 25, n is 100 m is 100, n is 25
Le programme รฉchange les valeurs rรฉelles des variables car la fonction y accรจde par adresse en utilisant aiguille. Nous discuterons ici du processus du programme :
- Nous dรฉclarons la fonction responsable de l'รฉchange des deux valeurs de variables, qui prend deux pointeurs entiers comme paramรจtres et renvoie n'importe quelle valeur lorsqu'elle est appelรฉe.
- Dans la fonction principale, nous dรฉclarons et initialisons deux variables entiรจres ('m' et 'n') puis nous imprimons respectivement leurs valeurs.
- Nous appelons la fonction swap() en passant l'adresse des deux variables comme arguments ร l'aide du symbole esperluette. Aprรจs cela, nous imprimons les nouvelles valeurs รฉchangรฉes des variables.
- Ici, nous dรฉfinissons le contenu de la fonction swap() qui prend deux adresses de variables entiรจres comme paramรจtres et dรฉclarons une variable entiรจre temporaire utilisรฉe comme troisiรจme boรฎte de stockage pour enregistrer l'une des variables de valeur qui sera placรฉe dans la deuxiรจme variable.
- Enregistrez le contenu de la premiรจre variable pointรฉe par 'a' dans la variable temporaire.
- Stockez la deuxiรจme variable pointรฉe par b dans la premiรจre variable pointรฉe par a.
- Mettez ร jour la deuxiรจme variable (pointรฉe par b) par la valeur de la premiรจre variable enregistrรฉe dans la variable temporaire.
Fonctions avec paramรจtres de tableau
En C, on ne peut pas passer un tableau par valeur ร une fonction. Alors qu'un nom de tableau est un pointeur (adresse), nous passons donc simplement un nom de tableau ร une fonction, ce qui signifie passer un pointeur vers le tableau.
Par exemple, nous considรฉrons le programme suivant :
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);}
Sortie :
Total summation is 471
Ici, nous expliquerons le code du programme avec ses dรฉtails
- Nous dรฉclarons et dรฉfinissons la fonction add_array() qui prend une adresse de tableau (pointeur) avec son numรฉro d'รฉlรฉments comme paramรจtres et renvoie la somme totale accumulรฉe de ces รฉlรฉments. Le pointeur est utilisรฉ pour itรฉrer les รฉlรฉments du tableau (en utilisant la notation p[k]), et nous accumulons la somme dans une variable locale qui sera renvoyรฉe aprรจs avoir itรฉrรฉ l'ensemble du tableau d'รฉlรฉments.
- Nous dรฉclarons et initialisons un tableau d'entiers avec cinq รฉlรฉments entiers. Nous imprimons la somme totale en passant le nom du tableau (qui fait office d'adresse) et la taille du tableau au add_array()fonction appelรฉe comme arguments.
Fonctions qui renvoient un tableau
En C, on peut renvoyer un pointeur vers un tableau, comme dans le programme suivant :
#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);}
Sortie :
1 2 3 4 5
Et ici, nous discuterons des dรฉtails du programme
- Nous dรฉfinissons et dรฉclarons une fonction qui renvoie une adresse de tableau contenant une valeur entiรจre et ne prend aucun argument.
- Nous dรฉclarons un pointeur entier qui reรงoit le tableau complet construit aprรจs l'appel de la fonction et nous imprimons son contenu en itรฉrant l'intรฉgralitรฉ du tableau de cinq รฉlรฉments.
Notez qu'un pointeur, et non un tableau, est dรฉfini pour stocker l'adresse du tableau renvoyรฉe par la fonction. Notez รฉgalement que lorsqu'une variable locale est renvoyรฉe par une fonction, nous devons la dรฉclarer comme statique dans la fonction.
Pointeurs de fonction
Comme nous savons par dรฉfinition que les pointeurs pointent vers une adresse dans n'importe quel emplacement mรฉmoire, ils peuvent รฉgalement pointer vers le dรฉbut du code exรฉcutable en tant que fonctions en mรฉmoire.
Un pointeur vers une fonction est dรฉclarรฉ avec le * , l'instruction gรฉnรฉrale de sa dรฉclaration est :
return_type (*function_name)(arguments)
Vous devez vous rappeler que les parenthรจses autour de (*function_name) sont importantes car sans elles, le compilateur pensera que function_name renvoie un pointeur de return_type.
Aprรจs avoir dรฉfini le pointeur de fonction, nous devons l'attribuer ร une fonction. Par exemple, le programme suivant dรฉclare une fonction ordinaire, dรฉfinit un pointeur de fonction, attribue le pointeur de fonction ร la fonction ordinaire et appelle ensuite la fonction via le pointeur :
#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");}
Sortie :
Hi Hi Hi
- Nous dรฉfinissons et dรฉclarons une fonction standard qui imprime un texte Hi k fois indiquรฉ par le paramรจtre times lorsque la fonction est appelรฉe
- Nous dรฉfinissons une fonction pointeur (avec sa dรฉclaration spรฉciale) qui prend un paramรจtre entier et ne renvoie rien.
- Nous initialisons notre fonction pointeur avec la Hi_function ce qui signifie que le pointeur pointe vers la Hi_function().
- Plutรดt que d'appeler la fonction standard en enregistrant le nom de la fonction avec des arguments, nous appelons uniquement la fonction pointeur en passant le chiffre 3 comme arguments, et c'est tout !
Gardez ร l'esprit que le nom de la fonction pointe vers l'adresse de dรฉbut du code exรฉcutable comme un nom de tableau qui pointe vers son premier รฉlรฉment. Par consรฉquent, des instructions telles que function_ptr = &Hi_function et (*funptr)(3) sont correctes.
REMARQUE : Il n'est pas important d'insรฉrer l'opรฉrateur d'adresse & et l'opรฉrateur d'indirection * lors de l'affectation de fonction et de l'appel de fonction.
Tableau de pointeurs de fonction
Un tableau de pointeurs de fonction peut jouer un rรดle de commutateur ou d'instruction if pour prendre une dรฉcision, comme dans le programme suivant :
#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
Ici, nous discutons des dรฉtails du programme :
- Nous dรฉclarons et dรฉfinissons quatre fonctions qui prend deux arguments entiers et renvoie une valeur entiรจre. Ces fonctions ajoutent, soustraient, multiplient et divisent les deux arguments concernant la fonction appelรฉe par l'utilisateur.
- Nous dรฉclarons 4 entiers pour gรฉrer respectivement les opรฉrandes, le type d'opรฉration et le rรฉsultat. De plus, nous dรฉclarons un tableau de quatre pointeurs de fonctions. Chaque pointeur de fonction d'un รฉlรฉment du tableau prend deux paramรจtres entiers et renvoie une valeur entiรจre.
- Nous attribuons et initialisons chaque รฉlรฉment du tableau avec la fonction dรฉjร dรฉclarรฉe. Par exemple, le troisiรจme รฉlรฉment qui est le troisiรจme pointeur de fonction pointera vers la fonction d'opรฉration de multiplication.
- On recherche les opรฉrandes et le type d'opรฉration de l'utilisateur tapรฉ au clavier.
- Nous avons appelรฉ l'รฉlรฉment de tableau appropriรฉ (pointeur de fonction) avec des arguments et nous stockons le rรฉsultat gรฉnรฉrรฉ par la fonction appropriรฉe.
L'instruction int (*ope[4])(int, int); dรฉfinit le tableau de pointeurs de fonction. Chaque รฉlรฉment du tableau doit avoir les mรชmes paramรจtres et le mรชme type de retour.
Le rรฉsultat de l'instruction = ope[choice](x, y); exรฉcute la fonction appropriรฉe selon le choix fait par l'utilisateur. Les deux entiers saisis sont les arguments passรฉs ร la fonction.
Fonctions utilisant des pointeurs vides
Les pointeurs vides sont utilisรฉs lors des dรฉclarations de fonctions. Nous utilisons un type de retour void * permettant de renvoyer n'importe quel type. Si nous supposons que nos paramรจtres ne changent pas lors du passage ร une fonction, nous le dรฉclarons comme const.
Par exemple :
void * cube (const void *);
Considรฉrez le programme suivant :
#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;}
Rรฉsultat:
4 cubed is 64
Ici, nous discuterons des dรฉtails du programme :
- Nous dรฉfinissons et dรฉclarons une fonction qui renvoie une valeur entiรจre et prend une adresse de variable immuable sans type de donnรฉes spรฉcifique. Nous calculons la valeur cubique de la variable de contenu (x) pointรฉe par le pointeur num, et comme il s'agit d'un pointeur vide, nous devons la convertir en un type de donnรฉes entier en utilisant un pointeur de notation spรฉcifique (* type de donnรฉes), et nous retournons la valeur du cube.
- Nous dรฉclarons l'opรฉrande et la variable rรฉsultat. De plus, nous initialisons notre opรฉrande avec la valeur ยซ 4 ยป.
- Nous appelons la fonction cube en passant l'adresse de l'opรฉrande, et nous gรฉrons la valeur renvoyรฉe dans la variable rรฉsultat
Pointeurs de fonction comme arguments
Une autre faรงon d'exploiter un pointeur de fonction en le passant en argument ร une autre fonction parfois appelรฉe ยซ fonction de rappel ยป car la fonction rรฉceptrice ยซ le rappelle ยป.
Dans le fichier d'en-tรชte stdlib.h, la fonction Quicksort ยซ qsort() ยป utilise cette technique qui est un algorithme dรฉdiรฉ au tri d'un tableau.
void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
- void *base : pointeur void vers le tableau.
- size_t num : Le numรฉro de l'รฉlรฉment du tableau.
- size_t width La taille de l'รฉlรฉment.
- int (*compare (const void *, const void *) : pointeur de fonction composรฉ de deux arguments et renvoie 0 lorsque les arguments ont la mรชme valeur, <0 lorsque arg1 vient avant arg2, et >0 lorsque arg1 vient aprรจs arg2.
Le programme suivant trie un tableau d'entiers du petit au grand nombre ร l'aide de la fonction 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;}
Rรฉsultat:
13 14 48 50 52
Ici, nous discuterons des dรฉtails du programme :
- Nous dรฉfinissons une fonction de comparaison composรฉe de deux arguments et renvoie 0 lorsque les arguments ont la mรชme valeur, <0 lorsque arg1 vient avant arg2 et >0 lorsque arg1 vient aprรจs arg2. Les paramรจtres sont un type de pointeurs vides convertis en type de donnรฉes de tableau appropriรฉ. (entier)
- Nous dรฉfinissons et initialisons un tableau d'entiers. La taille du tableau est stockรฉe dans le num variable et la taille de chaque รฉlรฉment du tableau est stockรฉe dans la variable width en utilisant sizeof() prรฉdรฉfini Opรฉrateur C.
- Nous appelons l' qtrier et transmettez le nom du tableau, la taille, la largeur et la fonction de comparaison dรฉfinis prรฉcรฉdemment par l'utilisateur afin de trier notre tableau par ordre croissant. La comparaison sera effectuรฉe en prenant ร chaque itรฉration deux รฉlรฉments du tableau jusqu'ร ce que l'ensemble du tableau soit triรฉ.
- Nous imprimons les รฉlรฉments du tableau pour รชtre sรปr que notre tableau est bien triรฉ en itรฉrant tout le tableau en utilisant pour la boucle.







