Wie kann ich ein Array von Funktionszeigern verwenden?

150

Wie soll ich ein Array von Funktionszeigern in C verwenden?

Wie kann ich sie initialisieren?

Der Typ mit dem Hut
quelle

Antworten:

194

Sie haben hier ein gutes Beispiel (Array von Funktionszeigern) mit detaillierter Syntax .

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() */
[...]

So rufen Sie einen dieser Funktionszeiger auf:

result = (*p[op]) (i, j); // op being the index of one of the four functions
VonC
quelle
3
Gute Antwort - Sie sollten es erweitern, um zu zeigen, wie eine der Funktionen aufgerufen wird.
Jonathan Leffler
1
@crucifiedsoul "die C-Programmiersprache" von Brian Kernighan und Dennis Ritchie? Es könnte sein, aber ich hatte es nicht als Referenz, als ich die Antwort vor dreieinhalb Jahren schrieb. Also ich weiß es nicht.
VonC
12
Ich möchte hinzufügen, dass Sie p mit(*p[4]) (int, int) {sum,substract,mul,div}
jiggunjer
1
@VonC: tolle Antwort. +1 für die Links.
Zerstörer
@jiggunjer s / subtrahieren / subtrahieren /: p. Aber danke für diesen Kommentar, sehr nützlich :). +1.
RastaJedi
41

Die obigen Antworten können Ihnen helfen, aber Sie möchten möglicherweise auch wissen, wie Sie ein Array von Funktionszeigern verwenden.

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;
}

Sie können einem einzelnen Funktionszeigerarray nur die Adressen von Funktionen mit demselben Rückgabetyp und denselben Argumenttypen sowie keine Argumente zuweisen.

Sie können auch Argumente wie unten übergeben, wenn alle oben genannten Funktionen dieselbe Anzahl von Argumenten desselben Typs haben.

  (*func_ptr[option])(argu1);

Hinweis: Hier im Array beginnt die Nummerierung der Funktionszeiger wie in allgemeinen Arrays bei 0. Im obigen Beispiel fun1kann also aufgerufen werden, wenn Option = 0, fun2kann aufgerufen werden, wenn Option = 1 und fun3kann aufgerufen werden, wenn Option = 2.

Manoj Zweifel
quelle
Selbst für diese kleine Demo sollten Sie eine Überprüfung für den Eingabewert hinzufügen, da der Code auf einen Neuling
abzielt
if ((Option <0) || (Option> 2)) {(* func_ptr [Option]) (); } Alter, das heißt, die Methode wird nur aufgerufen, wenn der Benutzer einen ungültigen Index eingibt!
ljs
6
Das ist eine gute Antwort, Sie sollten jedoch nach (* func_ptr [3]) eine Klammer einfügen, um einen gültigen Code zu erhalten.
Alex
Dies ist eine schrecklich schlechte Antwort. Aufgrund der fehlenden Klammern wird dieser Code nicht einmal kompiliert .
CL.
Wie @Alex sagte, ändern Sie es einfach von (*func_ptr[3])zu (*func_ptr[3])()und es wird kompiliert
Dsaydon
9

So können Sie es verwenden:

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");
}

Haupt 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;
}

Ich hoffe das hilft beim Verständnis Function Pointer.

Rasmi Ranjan Nayak
quelle
Zeile 15 von Main.c sollte für (i = 0; i <5; i ++) stehen, oder?
user3116936
Warum haben Sie den fp-Enumerator deklariert?
Arrrow
@Arrrow: Ich glaube, ich habe einen Teil des Legacy-Codes gesehen, in dem sie auf diese Weise erstellt wurden ... Und er sieht sehr schön aus. Entfernen Sie f1, f2 ...einfach und geben Sie stattdessen 'writefile, readfromfile ...' ein. Es wird redable
Rasmi Ranjan Nayak
5

Diese "Antwort" ist eher ein Nachtrag zu VonCs Antwort; Ich möchte nur darauf hinweisen, dass die Syntax über ein typedef vereinfacht und eine aggregierte Initialisierung verwendet werden kann:

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
quelle
2

Oh, es gibt Unmengen von Beispielen. Schauen Sie sich einfach alles in glib oder gtk an. Sie können die Arbeit der Funktionszeiger dort in Arbeit sehen.

Hier zB die Initialisierung des gtk_button-Materials.


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;

Und in gtkobject.h finden Sie folgende Erklärungen:


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);
};

Das Zeug (* set_arg) ist ein Zeiger auf die Funktion, und dies kann z. B. einer anderen Implementierung in einer abgeleiteten Klasse zugewiesen werden.

Oft sieht man so etwas

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},
...

Sie können also nach Namen in die Tabelle greifen und die "zugehörige" Funktion aufrufen.

Oder Sie verwenden eine Hash-Tabelle, in die Sie die Funktion einfügen und "nach Namen" aufrufen.

Grüße
Friedrich

Friedrich
quelle
Wäre es möglich, eine solche Funktionstabelle für Hashing-Funktionen innerhalb der Implementierung der Hash-Tabelle selbst zu verwenden? (Lesen Sie: zirkuläre Abhängigkeit beteiligt).
Flavius
2

Kann es so verwenden:

//! 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
quelle
1

Dies sollte ein kurzes und einfaches Beispiel für das Kopieren und Einfügen von Code für die obigen Antworten sein. Hoffentlich hilft das.

#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
quelle
Wenn es sich um ein Kopieren und Einfügen aus anderen Antworten handelt, bin ich mir nicht sicher, ob es einen Mehrwert bietet ...
Fabio sagt Reinstate Monica
Ja, ich verstehe Ihren Standpunkt, ich werde heute Abend den Wert hinzufügen, der gerade bei der Arbeit ist.
Nimig18
1

Die einfachste Lösung besteht darin, die Adresse des gewünschten endgültigen Vektors anzugeben und diese innerhalb der Funktion zu ändern.

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
}
Leonardo
quelle
0

Diese Frage wurde bereits mit sehr guten Beispielen beantwortet. Das einzige Beispiel, das möglicherweise fehlt, ist eines, bei dem die Funktionen Zeiger zurückgeben. Ich habe ein weiteres Beispiel damit geschrieben und viele Kommentare hinzugefügt, falls jemand es hilfreich findet:

#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
quelle
0

Dieses einfache Beispiel für ein mehrdimensionales Array mit Funktionszeigern ":

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
quelle