【问题标题】:c - initialize an array of pointers to functionsc - 初始化一个指向函数的指针数组
【发布时间】:2012-12-28 14:57:15
【问题描述】:

我想初始化一个大小为 5 的指针数组,该数组包含指向没有参数且返回 int 的函数的指针(可以是满足这些要求的任何函数)。

这是我迄今为止尝试过的,但出现语法错误:

int (*func)() fparr[5] = int (*func)();

这个语法有什么问题?

【问题讨论】:

标签: c pointers


【解决方案1】:

如果您要作为数组默认内容提供的函数称为func,则

  1. 你最好使用typedef
  2. 你必须使用数组初始化器

考虑:

typedef int (*IntFunc)(void);
IntFunc fparr[5] = { func, func, func, func, func };

或者可读性较差的方式,如果您不想使用typedef

int (*fparr[5])(void) = { func, func, func, func, func };

【讨论】:

  • typedef-less 的方式是错误的。应该是int (*fparr[5])(void) = ...。它不仅可读性差,而且可写性也差。
  • 很容易弄错,看看这个页面上的其他人 ;)
  • @DanielFischer 当然... :) (你认为我为什么建议 typedef...)
  • 因为,尽管您已经 18 岁(根据您的个人资料,除非最近几天发生了变化),但您基本上是理智的。
  • @DanielFischer(不,最后一次更改是在 6 月 28 日)- 好吧,至少我尽量不要把事情弄得更糟。但有时我会这样做。
【解决方案2】:

因为您实际上并没有初始化函数指针数组...尝试:

int (*fparr[5])(void) = { func1, func2, func3, func4, func5 };

【讨论】:

    【解决方案3】:

    第 1 步:

    将函数的签名定义为类型FN

    typedef int (*FN)();
    

    第二步:

    FN签名定义这5个函数:

    int f1(void) { ; }
    int f2(void) { ; }
    ...
    

    第 3 步:

    定义并初始化一个包含 5 个 FN 类型函数的数组:

    FN fparr[5] = {f1,f2,f3,f4,f5}
    

    否则

    如果你不想定义一个单独的签名,你可以这样做——如前所述——所以:

     int ((*)fpar []) () = {f1,f2, ...}
    

    如果您在声明时知道数组中的函数数量,则无需编写5,如果您在声明的同一行初始化数组,编译器会为您分配此内存。

    【讨论】:

    • @Christoph :在标准 C 中,f()f(void) 是不同的。 () 告诉编译器禁用参数检查。例如,如果你想在调用函数 f 之前给变量 i 加 1,你可以这样做:int f(){;}main(){int i=3;f(i++);printf("%d",i);}
    • 如果你使用typedef int (*FN)();而不是typedef int (*FN)(void);,编译器会很乐意接受static int can_has_arg(int x) { return x; } FN fparr[] = { can_has_arg },而Tom表示他想要一个指向不带参数的函数的指针数组
    【解决方案4】:

    好吧,我来晚了……

    #include <stdio.h>
    
    int fun0()
    {
        return 0;
    }
    
    int fun1()
    {
        return 1;
    }
    
    int fun2()
    {
        return 2;
    }
    
    int main(int argc, char* argv[])
    {
        int (*f[]) (void) = {fun0, fun1, fun2};
        printf("%d\n", f[0]());
        printf("%d\n", f[1]());
        printf("%d\n", f[2]());
        return 0;
    }
    

    【讨论】:

    • C 中的空括号不等于 void(gcc -Wstrict-prototypes 警告:函数声明不是原型
    • @Jens 感谢您的评论。我会解决的。
    【解决方案5】:

    函数指针数组可以用另一种方式用默认值初始化。


    示例代码

       
    #include <stdio.h>
    
    void add(int index, int a, int b){
        printf("%d. %d + %d = %d\n", index, a, b, a + b);
    }
    void sub(int index, int a, int b){
        printf("%d. %d - %d = %d\n", index, a, b, a - b);
    }
    int main(){
        void (*func[10])(int, int, int) = {[0 ... 9] = add};
        func[4] = sub;
        int i;
        for(i = 0; i < 10; i++)func[i](i, i + 10, i + 2);
    }
       
    如果你运行上面的程序,你会得到下面的输出。所有元素都使用函数 add 初始化,但数组中的第 4 个元素分配给函数 sub

    输出

    0. 10 + 2 = 12
    1. 11 + 3 = 14
    2. 12 + 4 = 16
    3. 13 + 5 = 18
    4. 14 - 6 = 8
    5. 15 + 7 = 22
    6. 16 + 8 = 24
    7. 17 + 9 = 26
    8. 18 + 10 = 28
    9. 19 + 11 = 30

    【讨论】:

      【解决方案6】:

      我只是在上面的答案中添加了更多内容。函数指针数组可以由枚举变量索引,显示每个索引的操作类型。看看下面的例子。在这里,我们使用 tyepdef 作为函数指针运算符。然后我们创建一个名为act 的函数指针数组。最后,我们将数组初始化为递增和递减函数。在这种情况下,索引 0 表示递增,索引 1 表示递减。我们不使用这种原始索引,而是使用具有 INCR 和 DECR 的枚举,对应于索引 0、1。

      #include<stdio.h>
      #include<stdlib.h>
      
      typedef void (*operate)(int *, int);
      void increment(int *, int);
      void decrement(int *, int);
      
      enum {
         INCR, DECR
          };
      
       int main(void){
      
         int a = 5;
      
        operate act[2] = {increment,decrement};
      
        act[INCR](&a,1);
      
        printf("%d\n",a);
      
        act[DECR](&a,2);
      
        printf("%d\n",a);
           return 0;
       }
      
       void increment(int *a, int c){
       *a += c;
       }
       void decrement(int *a, int c){
       *a -= c;
        }
      

      【讨论】:

        【解决方案7】:

        这是一个显示正确语法的工作示例:

        #include <stdio.h>
        
        int test1(void) {
            printf("test1\n");
            return 1;
        }
        
        int test2(void) {
            printf("test2\n");
            return 2;
        }
        
        int main(int argc, char **argv) {
            int (*fparr[2])(void) = { test1, test2 };
        
            fparr[0]();
            fparr[1]();
        
            return 0;
        }
        

        【讨论】:

        • test1 和 test2:控制到达非空函数的末尾。空参数列表应拼写为 (void) 而不是 (),因为后者是旧式 (K&R C) 且已弃用 C99。
        【解决方案8】:

        示例代码:

        static int foo(void) { return 42; }
        
        int (*bar[5])(void) = { foo, foo, foo, foo, foo };
        

        请注意,int (*)()int (*)(void) 类型是不同的类型 - 前者表示具有固定但未指定数量的参数的函数,而后者表示没有参数的函数。

        还请注意,C 声明符语法遵循与表达式相同的规则(特别是运算符优先级),因此是由内向外读取的:

        bar 表示指向函数 (int (*bar[5])(void)) 的指针 (*bar[5]) 和数组 (bar[5])。括号(*bar[5]) 是必要的,因为后缀函数调用比前缀指针间接绑定更紧密。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-10-11
          • 1970-01-01
          • 1970-01-01
          • 2011-07-08
          • 2015-04-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多