Comment puis-je utiliser un tableau de pointeurs de fonction?

151

Comment utiliser un tableau de pointeurs de fonction en C?

Comment puis-je les initialiser?

Le gars avec le chapeau
la source

Réponses:

194

Vous avez un bon exemple ici (Tableau de pointeurs de fonction) , avec la syntaxe détaillée .

int sum(int a, int b);
int subtract(int a, int b);
int mul(int a, int b);
int div(int a, int b);

int (*p[4]) (int x, int y);

int main(void)
{
  int result;
  int i, j, op;

  p[0] = sum; /* address of sum() */
  p[1] = subtract; /* address of subtract() */
  p[2] = mul; /* address of mul() */
  p[3] = div; /* address of div() */
[...]

Pour appeler l'un de ces pointeurs de fonction:

result = (*p[op]) (i, j); // op being the index of one of the four functions
VonC
la source
3
Bonne réponse - vous devriez l'étendre pour montrer comment appeler l'une des fonctions, cependant.
Jonathan Leffler
1
@crucifiedsoul "le langage de programmation C" écrit par Brian Kernighan et Dennis Ritchie? C'est possible, mais je ne l'avais pas comme référence au moment où j'ai rédigé la réponse il y a trois ans et demi. Alors je ne sais pas.
VonC
12
Je voudrais ajouter que vous pouvez initialiser p avec(*p[4]) (int, int) {sum,substract,mul,div}
jiggunjer
1
@VonC: excellente réponse. +1 pour les liens.
Destructor
@jiggunjer s / soustraire / soustraire /: p. Mais merci pour ce commentaire, très utile :). +1.
RastaJedi du
41

Les réponses ci-dessus peuvent vous aider, mais vous voudrez peut-être également savoir comment utiliser un tableau de pointeurs de fonction.

void fun1()
{

}

void fun2()
{

}

void fun3()
{

}

void (*func_ptr[3])() = {fun1, fun2, fun3};

main()
{
    int option;


    printf("\nEnter function number you want");
    printf("\nYou should not enter other than 0 , 1, 2"); /* because we have only 3 functions */
    scanf("%d",&option);

    if((option>=0)&&(option<=2))
    { 
        (*func_ptr[option])();
    }

    return 0;
}

Vous ne pouvez affecter les adresses des fonctions avec le même type de retour et les mêmes types d'argument et aucun argument à un seul tableau de pointeurs de fonction.

Vous pouvez également passer des arguments comme ci-dessous si toutes les fonctions ci-dessus ont le même nombre d'arguments du même type.

  (*func_ptr[option])(argu1);

Remarque: ici, dans le tableau, la numérotation des pointeurs de fonction commencera à 0 comme dans les tableaux généraux. Ainsi, dans l'exemple ci-dessus, il fun1peut être appelé si option = 0, fun2peut être appelé si option = 1 et fun3peut être appelé si option = 2.

Manoj doute
la source
Même pour cette petite démo, vous devriez ajouter une vérification pour la valeur d'entrée, car le code cible un débutant ... :-)
PhiLho
if ((option <0) || (option> 2)) {(* func_ptr [option]) (); } Mec, cela signifie que la méthode est appelée uniquement lorsque l'utilisateur tape un index invalide!
ljs
6
C'est une bonne réponse, cependant vous devriez ajouter des parenthèses après (* func_ptr [3]) pour que le code soit valide.
Alex
C'est une réponse horriblement mauvaise. En raison des parenthèses manquantes, ce code ne se compile même pas .
CL.
comme @ Alex l'a dit, changez-le simplement de (*func_ptr[3])en (*func_ptr[3])()et il sera compilé
dsaydon
9

Voici comment vous pouvez l'utiliser:

New_Fun.h

#ifndef NEW_FUN_H_
#define NEW_FUN_H_

#include <stdio.h>

typedef int speed;
speed fun(int x);

enum fp {
    f1, f2, f3, f4, f5
};

void F1();
void F2();
void F3();
void F4();
void F5();
#endif

New_Fun.c

#include "New_Fun.h"

speed fun(int x)
{
    int Vel;
    Vel = x;
    return Vel;
}

void F1()
{
    printf("From F1\n");
}

void F2()
{
    printf("From F2\n");
}

void F3()
{
    printf("From F3\n");
}

void F4()
{
    printf("From F4\n");
}

void F5()
{
    printf("From F5\n");
}

Principal c

#include <stdio.h>
#include "New_Fun.h"

int main()
{
    int (*F_P)(int y);
    void (*F_A[5])() = { F1, F2, F3, F4, F5 };    // if it is int the pointer incompatible is bound to happen
    int xyz, i;

    printf("Hello Function Pointer!\n");
    F_P = fun;
    xyz = F_P(5);
    printf("The Value is %d\n", xyz);
    //(*F_A[5]) = { F1, F2, F3, F4, F5 };
    for (i = 0; i < 5; i++)
    {
        F_A[i]();
    }
    printf("\n\n");
    F_A[f1]();
    F_A[f2]();
    F_A[f3]();
    F_A[f4]();
    return 0;
}

J'espère que cela aide à comprendre Function Pointer.

Rasmi Ranjan Nayak
la source
La ligne 15 de Main.c devrait être pour (i = 0; i <5; i ++), non?
user3116936
Pourquoi avez-vous déclaré l'énumérateur FP?
Arrrow
@Arrrow: Je pense avoir vu une partie du code hérité où ils l'ont fait de cette façon ... Et ça a l'air très beau. Il suffit de supprimer f1, f2 ...et à la place de puis entrez 'writefile, readfromfile ...' ... il devient plus redable
Rasmi Ranjan Nayak
5

Cette «réponse» est plus un addendum à la réponse de VonC; en notant simplement que la syntaxe peut être simplifiée via un typedef, et que l'initialisation agrégée peut être utilisée:

typedef int FUNC(int, int);

FUNC sum, subtract, mul, div;
FUNC *p[4] = { sum, subtract, mul, div };

int main(void)
{
    int result;
    int i = 2, j = 3, op = 2;  // 2: mul

    result = p[op](i, j);   // = 6
}

// maybe even in another file
int sum(int a, int b) { return a+b; }
int subtract(int a, int b) { return a-b; }
int mul(int a, int b) { return a*b; }
int div(int a, int b) { return a/b; }
MM
la source
2

Oh, il y a des tonnes d'exemples. Jetez un œil à tout ce qui se trouve dans glib ou gtk. Vous pouvez voir le travail des pointeurs de fonction dans le travail là tout le chemin.

Voici par exemple l'initialisation du truc gtk_button.


static void
gtk_button_class_init (GtkButtonClass *klass)
{
  GObjectClass *gobject_class;
  GtkObjectClass *object_class;
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;

  gobject_class = G_OBJECT_CLASS (klass);
  object_class = (GtkObjectClass*) klass;
  widget_class = (GtkWidgetClass*) klass;
  container_class = (GtkContainerClass*) klass;

  gobject_class->constructor = gtk_button_constructor;
  gobject_class->set_property = gtk_button_set_property;
  gobject_class->get_property = gtk_button_get_property;

Et dans gtkobject.h, vous trouvez les déclarations suivantes:


struct _GtkObjectClass
{
  GInitiallyUnownedClass parent_class;

  /* Non overridable class methods to set and get per class arguments */
  void (*set_arg) (GtkObject *object,
           GtkArg    *arg,
           guint      arg_id);
  void (*get_arg) (GtkObject *object,
           GtkArg    *arg,
           guint      arg_id);

  /* Default signal handler for the ::destroy signal, which is
   *  invoked to request that references to the widget be dropped.
   *  If an object class overrides destroy() in order to perform class
   *  specific destruction then it must still invoke its superclass'
   *  implementation of the method after it is finished with its
   *  own cleanup. (See gtk_widget_real_destroy() for an example of
   *  how to do this).
   */
  void (*destroy)  (GtkObject *object);
};

Le truc (* set_arg) est un pointeur vers une fonction et cela peut par exemple être affecté à une autre implémentation dans une classe dérivée.

Souvent, vous voyez quelque chose comme ça

struct function_table {
   char *name;
   void (*some_fun)(int arg1, double arg2);
};

void function1(int  arg1, double arg2)....


struct function_table my_table [] = {
    {"function1", function1},
...

Ainsi, vous pouvez accéder à la table par son nom et appeler la fonction "associée".

Ou peut-être que vous utilisez une table de hachage dans laquelle vous mettez la fonction et l'appelez "par nom".

Cordialement
Friedrich

Friedrich
la source
Serait-il possible d'utiliser une telle table_fonction pour les fonctions de hachage dans l'implémentation de la table de hachage elle-même? (Lire: dépendance circulaire impliquée).
Flavius
2

Peut l'utiliser de la manière suivante:

//! Define:
#define F_NUM 3
int (*pFunctions[F_NUM])(void * arg);

//! Initialise:
int someFunction(void * arg) {
    int a= *((int*)arg);
    return a*a;
}

pFunctions[0]= someFunction;

//! Use:
int someMethod(int idx, void * arg, int * result) {
    int done= 0;
    if (idx < F_NUM && pFunctions[idx] != NULL) {
        *result= pFunctions[idx](arg);
        done= 1;
    }
    return done;
}

int x= 2;
int z= 0;
someMethod(0, (void*)&x, &z);
assert(z == 4);
Peter Hirt
la source
1

Il doit s'agir d'un exemple de code court et simple copier-coller des réponses ci-dessus. Espérons que cela aide.

#include <iostream>
using namespace std;

#define DBG_PRINT(x) do { std::printf("Line:%-4d" "  %15s = %-10d\n", __LINE__, #x, x); } while(0);

void F0(){ printf("Print F%d\n", 0); }
void F1(){ printf("Print F%d\n", 1); }
void F2(){ printf("Print F%d\n", 2); }
void F3(){ printf("Print F%d\n", 3); }
void F4(){ printf("Print F%d\n", 4); }
void (*fArrVoid[N_FUNC])() = {F0, F1, F2, F3, F4};

int Sum(int a, int b){ return(a+b); }
int Sub(int a, int b){ return(a-b); }
int Mul(int a, int b){ return(a*b); }
int Div(int a, int b){ return(a/b); }
int (*fArrArgs[4])(int a, int b) = {Sum, Sub, Mul, Div};

int main(){
    for(int i = 0; i < 5; i++)  (*fArrVoid[i])();
    printf("\n");

    DBG_PRINT((*fArrArgs[0])(3,2))
    DBG_PRINT((*fArrArgs[1])(3,2))
    DBG_PRINT((*fArrArgs[2])(3,2))
    DBG_PRINT((*fArrArgs[3])(3,2))

    return(0);
}
nimig18
la source
S'il s'agit d'un copier-coller d'autres réponses, je ne suis pas sûr que cela ajoute de la valeur ...
Fabio dit Réintégrer Monica le
Oui je vois votre point, je vais ajouter la valeur ce soir actuellement au travail.
nimig18
1

La solution la plus simple est de donner l'adresse du vecteur final souhaité et de la modifier à l'intérieur de la fonction.

void calculation(double result[] ){  //do the calculation on result

   result[0] = 10+5;
   result[1] = 10 +6;
   .....
}

int main(){

    double result[10] = {0}; //this is the vector of the results

    calculation(result);  //this will modify result
}
Léonard
la source
0

Cette question a déjà reçu de très bons exemples. Le seul exemple qui pourrait manquer est celui où les fonctions renvoient des pointeurs. J'ai écrit un autre exemple avec ceci et ajouté beaucoup de commentaires, au cas où quelqu'un le trouverait utile:

#include <stdio.h>

char * func1(char *a) {
    *a = 'b';
    return a;
}

char * func2(char *a) {
    *a = 'c';
    return a;
}

int main() {
    char a = 'a';
    /* declare array of function pointers
     * the function pointer types are char * name(char *)
     * A pointer to this type of function would be just
     * put * before name, and parenthesis around *name:
     *   char * (*name)(char *)
     * An array of these pointers is the same with [x]
     */
    char * (*functions[2])(char *) = {func1, func2};
    printf("%c, ", a);
    /* the functions return a pointer, so I need to deference pointer
     * Thats why the * in front of the parenthesis (in case it confused you)
     */
    printf("%c, ", *(*functions[0])(&a)); 
    printf("%c\n", *(*functions[1])(&a));

    a = 'a';
    /* creating 'name' for a function pointer type
     * funcp is equivalent to type char *(*funcname)(char *)
     */
    typedef char *(*funcp)(char *);
    /* Now the declaration of the array of function pointers
     * becomes easier
     */
    funcp functions2[2] = {func1, func2};

    printf("%c, ", a);
    printf("%c, ", *(*functions2[0])(&a));
    printf("%c\n", *(*functions2[1])(&a));

    return 0;
}
Jay Medina
la source
0

Cet exemple simple de tableau multidimensionnel avec des pointeurs de fonction ":

void one( int a, int b){    printf(" \n[ ONE ]  a =  %d   b = %d",a,b);}
void two( int a, int b){    printf(" \n[ TWO ]  a =  %d   b = %d",a,b);}
void three( int a, int b){    printf("\n [ THREE ]  a =  %d   b = %d",a,b);}
void four( int a, int b){    printf(" \n[ FOUR ]  a =  %d   b = %d",a,b);}
void five( int a, int b){    printf(" \n [ FIVE ]  a =  %d   b = %d",a,b);}
void(*p[2][2])(int,int)   ;
int main()
{
    int i,j;
    printf("multidimensional array with function pointers\n");

    p[0][0] = one;    p[0][1] = two;    p[1][0] = three;    p[1][1] = four;
    for (  i  = 1 ; i >=0; i--)
        for (  j  = 0 ; j <2; j++)
            (*p[i][j])( (i, i*j);
    return 0;
}
Arun Kumar
la source