【问题标题】:How can I use an array of function pointers?如何使用函数指针数组?
【发布时间】:2010-09-20 03:30:23
【问题描述】:

我应该如何在 C 中使用函数指针数组?

如何初始化它们?

【问题讨论】:

    标签: c initialization function-pointers


    【解决方案1】:
    #include <iostream>
    using namespace std;
        
    int sum (int , int);
    int prod (int , int);
        
    int main()
    {
        int (*p[2])(int , int ) = {sum,prod};
        
        cout << (*p[0])(2,3) << endl;
        cout << (*p[1])(2,3) << endl;
    }
        
    int sum (int a , int b)
    {
        return a+b;
    }
        
    int prod (int a, int b)
    {
        return a*b;
    }
    

    【讨论】:

    • 问题是关于 C,而不是关于 C++。请不要为 C 问题提供 C++ 答案。如果您认为自己的答案比现有答案有所改进,请考虑回答 this question
    【解决方案2】:

    下面是一个更简单的例子:

    jump_table.c

    int func1(int arg)  { return arg + 1; }
    int func2(int arg)  { return arg + 2; }
    int func3(int arg)  { return arg + 3; }
    int func4(int arg)  { return arg + 4; }
    int func5(int arg)  { return arg + 5; }
    int func6(int arg)  { return arg + 6; }
    int func7(int arg)  { return arg + 7; }
    int func8(int arg)  { return arg + 8; }
    int func9(int arg)  { return arg + 9; }
    int func10(int arg) { return arg + 10; }
    
    int (*jump_table[10])(int) = { func1, func2, func3, func4, func5, 
                                   func6, func7, func8, func9, func10 };
        
    int main(void) {
      int index = 2;
      int argument = 42;
      int result = (*jump_table[index])(argument);
      // result is 45
    }
    

    存储在数组中的所有函数必须具有相同的签名。这仅仅意味着它们必须返回相同的类型(例如int)并具有相同的参数(在上面的示例中只有一个int)。


    在 C++ 中,您可以对 static 类方法(但不是实例方法)执行相同的操作。例如,您可以在上面的数组中使用MyClass::myStaticMethod,但不能使用MyClass::myInstanceMethodinstance.myInstanceMethod

    class MyClass {
    public:
      static int myStaticMethod(int foo)   { return foo + 17; }
      int        myInstanceMethod(int bar) { return bar + 17; }
    }
    
    MyClass instance;
    

    【讨论】:

      【解决方案3】:

      以上答案可能对您有所帮助,但您可能还想知道如何使用函数指针数组。

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

      您只能将具有相同返回类型和相同参数类型且没有参数的函数的地址分配给单个函数指针数组。

      如果上述所有函数具有相同数量的相同类型的参数,您也可以传递如下参数。

        (*func_ptr[option])(argu1);
      

      注意:这里的数组中函数指针的编号将从 0 开始,与一般数组相同。所以在上面的例子中fun1可以在option=0时调用,fun2可以在option=1时调用,fun3可以在option=2时调用。

      【讨论】:

      • 即使是这个小演示,您也应该添加对输入值的检查,因为代码针对的是新手... :-)
      【解决方案4】:

      可以这样使用:

      //! 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);
      

      【讨论】:

        【解决方案5】:

        你可以这样使用它:

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

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

        我希望这有助于理解Function Pointer.

        【讨论】:

        • Main.c 的第 15 行应该是 for (i = 0; i
        • 为什么要声明 fp 枚举器?
        • @Arrrow:我想我看到了一些他们以这种方式制作的遗留代码......而且它看起来非常漂亮。只需删除f1, f2 ...,然后输入'writefile,readfromfile ...'......它变得更加可红色
        【解决方案6】:

        最简单的解决方案是给出你想要的最终向量的地址,并在函数内部修改它。

        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
        }
        

        【讨论】:

          【解决方案7】:

          这个带有函数指针的多维数组的简单示例:

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

          【讨论】:

            【解决方案8】:

            这应该是上述响应的简短复制和粘贴代码示例。希望这会有所帮助。

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

            【讨论】:

            • 如果是其他答案的复制粘贴,我不确定它是否会增加任何价值...
            • 是的,我明白你的意思了,今晚我会在工作中添加价值。
            【解决方案9】:

            这个问题已经用很好的例子回答了。唯一可能缺少的示例是函数返回指针的示例。我用这个写了另一个例子,并添加了很多 cmets,以防有人发现它有帮助:

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

            【讨论】:

              【解决方案10】:

              这个“答案”更像是对 VonC 答案的补充;只是注意到可以通过 typedef 简化语法,并且可以使用聚合初始化:

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

              【讨论】:

              • 请将所有大写保留给预处理器宏。许多人还主张创建类型以_t 结尾,尽管这对于用户定义的类型似乎存在争议。
              【解决方案11】:

              你有一个很好的例子here (Array of Function pointers)syntax detailed

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

              调用这些函数指针之一:

              result = (*p[op]) (i, j); // op being the index of one of the four functions
              

              【讨论】:

              • 好答案 - 不过,您应该扩展它以显示如何调用其中一个函数。
              • @crucifiedsoul “C 编程语言”,由 Brian Kernighan 和 Dennis Ritchie 编写?可能是,但在三年半前我写答案时,我没有它作为参考。所以我不知道。
              • 我想补充一下你可以用(*p[4]) (int, int) {sum,substract,mul,div}初始化p
              • @VonC:很好的答案。为链接 +1。
              • @WilliamMartens 欢迎您。当我 12 多年前使用的链接仍然有效时,我总是感到惊讶!
              【解决方案12】:

              哦,有很多例子。看看 glib 或 gtk 中的任何内容。 您可以一路看到函数指针在工作中的工作。

              这里例如初始化 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;
              
              

              在 gtkobject.h 中,您可以找到以下声明:

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

              (*set_arg) 东西是一个指向函数的指针,例如可以在某个派生类中为其分配另一个实现。

              你经常看到这样的东西

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

              因此您可以按名称访问表并调用“关联”函数。

              或者,也许您使用一个哈希表来放置函数并“按名称”调用它。

              问候
              弗里德里希

              【讨论】:

              • 在哈希表实现本身中使用这样的 function_table 对函数进行哈希处理是否可行? (阅读:涉及循环依赖)。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2021-06-25
              • 1970-01-01
              • 2012-09-15
              • 1970-01-01
              • 1970-01-01
              • 2019-01-25
              • 1970-01-01
              相关资源
              最近更新 更多