5 votes

Fonction avec des paramètres mais sans arguments

Je lisais un mergeSort de la bibliothèque standard en c et j'ai trouvé qu'il a une fonction de comparaison comme argument (i.e void msort(void *base, size_t nitems, size_t size, int (*compar)(const void , const void )) lorsqu'il est défini). Cependant, dans l'utilisation réelle, lorsque la fonction msort est appelée, la fonction compar n'a pas d'argument qui lui est passé (même si elle a deux paramètres, qui sont (const void *, const void *) comme paramètres. Regardez l'extrait de code suivant et j'aimerais comprendre comment il est possible pour une fonction avec des paramètres d'être utilisée sans arguments au moment où elle est appelée ?

#include <stdio.h>
#include <stdlib.h>

int values[] = { 88, 56, 100, 2, 25 };

int cmpfunc (const void * a, const void * b) {
   return ( *(int*)a - *(int*)b );
}

int main () {
   int n;

   printf("Before sorting the list is: \n");
   for( n = 0 ; n < 5; n++ ) {
      printf("%d ", values[n]);
   }

   msort(values, 5, sizeof(int), cmpfunc);

   printf("\nAfter sorting the list is: \n");
   for( n = 0 ; n < 5; n++ ) {   
      printf("%d ", values[n]);
   }

   return(0);
}

3voto

mikyll98 Points 557

C'est ce qu'on appelle un pointeur de fonction : en fait, vous passez la fonction cmpfunc() en tant que paramètre, qui sera ensuite utilisé par la fonction msort() en interne, avec les arguments appropriés.

Un pointeur de fonction est une variable qui stocke l'adresse d'une fonction qui peut être appelée ultérieurement par ce pointeur de fonction. Ceci est utile car les fonctions encapsulent le comportement.

Les pointeurs de fonction sont les précurseurs de fermetures de fonctions .


Pour être plus clair : la raison pour laquelle il n'a pas d'arguments est que vous ne les connaissez pas encore .
Laissez-moi vous expliquer : cmpfunc() sert à comparer 2 éléments et à dire lequel précède l'autre. Mais msort() devra effectuer de nombreuses comparaisons différentes, puisqu'il doit itérer sur tous les éléments de la classe values[] . Par conséquent, en interne msort() va sélectionner 2 éléments à la fois, appelons-les x y y comparez-les cmpfunc(x, y) et les échanger si nécessaire.

1voto

melonduofromage Points 382
void msort(void *base, size_t nitems, size_t size, int (*compar)(const void* , const void*)) 

La fonction msort prend un pointeur de fonction comme argument final. Tout comme les paramètres normaux, ce paramètre indique à la commande msort qui "une adresse d'une fonction qui elle-même prend deux const void* en tant qu'argument et renvoie un int " sera passé en paramètre. Lorsqu'il est appelé comme :

msort(values, 5, sizeof(int), cmpfunc);

sans le paranthèse à la fin de cmpfunc vous ne faites que passer l'adresse de cmpfunc et ne l'appelle pas réellement, donc cela n'a pas de sens de passer des paramètres de toute façon. Vous dites simplement à la msort où trouver la fonction.

Qui appelle réellement le cmpfunc est le msort . Si vous avez accès à sa source, vous pouvez probablement voir quand et comment il l'appelle (avec les paramètres appropriés passés).

0voto

Fe2O3 Points 305

Je ne répéterai pas ce que d'autres ont correctement décrit à propos de "passer l'adresse d'une fonction comme paramètre à une autre fonction".

Un "cas d'utilisation" peut vous aider à comprendre "POURQUOI ?"

D'après votre exemple :

int cmpAscending (const void * a, const void * b) {
    return ( *(int*)a - *(int*)b );
}

Maintenant, un "jumeau" de cela :

int cmpDescending (const void * a, const void * b) {
    return ( *(int*)b - *(int*)a );  // NB: subtle difference
}

Maintenant, un programme peut passer l'adresse de la fonction de comparaison appropriée à msort() .

if( ascending )
    msort( values, 5, sizeof(int), cmpAscending );
else
    msort( values, 5, sizeof(int), cmpDescending );

Il existe des moyens encore plus économiques d'y parvenir :

    msort( values, 5, sizeof(int), ascending ? cmpAscending : cmpDescending );

0voto

CGi03 Points 84

Par exemple, dans la fonction main, foo reçoit l'adresse de la fonction bar. La fonction foo peut alors appeler la fonction bar via le pointeur de fonction pbar qu'elle a reçu en argument :

#include <stdio.h>

void bar(int x )
{
    printf("%d\n", x);
}

void foo(void(*pbar)(int))
{
    pbar(10);
    pbar(20);
}

int main(void)
{
   foo(bar);

   return(0);
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X