zoukankan      html  css  js  c++  java
  • 函数指针读书笔记

    • 函数指针的定义格式
    1. <返回类型> (*<指针变量>)(<形参表>)   例如:
    int  f(int);
    int (*pf)(int) = &f;

      pf是一个函数指针,它能够指向的是参数为int类型并且返回值为int类型的函数

      2.  也可以用typedef为函数指针类型取一个名字,然后再用该函数指针类型来定义指针变量:

          typedef  <返回类型>  (*<函数指针类型名>)(<形参表>)。

    typedef double (*PF)(double);
    PF pf;

      第一行是对一个函数指针进行了定义声明,声明了一个具有double返回值,并且参数是double类型的函数指针。以后就可以用PF来声明其它的相同类型的函数指针。

    • 函数指针的用途
      • 转换表(jump table)
      • 作为参数传递给另一个函数

           作为参数传递给另一个函数   用法主要是回调函数(callback function),也就是用户把一个函数指针作为参数传递给其它函数,后者将“回调”用户的函数。一个很常用的例子就是c函数库的qsort函数, qsort并不知道进行比较的值的类型,这是我们就可以传入一个比较函数的函数指针,对于不同类型的比较,我们可以让这个函数指针绑定到不同的函数上。这里就不详细说了。

        转换表  对于用户的不同输入,我们要调用不同的函数实现不同的功能,这时候也许我们可以用switch语句来实现。但是当每次我要增加一些操作的时候,就必须修改switch,也就是修改main函数里面的代码,这样是非常不方便的。那我们就可以用跳转表来实现,跳转表其实就是一函数指针数组。一般的用法如下[1]:

      

      代码实现如下:

    #include <stdio.h>
    
    typedef void (*PF)(void);
    
    struct jump_table{
        char ch;
        PF pf;
    };
    
    void pf_a(void) {    printf("CALL pf_a
    "); }
    void pf_b(void) {    printf("CALL pf_b
    "); }
    void pf_w(void) {    printf("CALL pf_w
    "); }
    
    struct jump_table table[100] = {  //跳转表
        {'a',pf_a},
        {'b',pf_b},
        {'w',pf_w},
        {0,NULL}
    };
    
    int main()
    {
        char ch;
        int i;
    
        while( (ch = getchar()) != 'x')
        {
            i = 0;
            while ((table[i].ch != 0))
            {
                if (ch == table[i].ch)
                {    
                    table[i].pf();
                    break;
                }
                i++;
            }
        }
    }
    
    2013/10/16  22:33

      我们可以看到用户输入的key值是不连续的,所以我们必须每次都扫描一遍数组,同时我们在定义数组的时候要设置结束标志,这样能方便判断结束。

      但是如果用户输入的是从零开始的连续整数,或者是一些诸如连续字符a-z之类的,那么我们就可以直接跳转到相应的项,而不需扫描数组。比如我们在做计算器的时候,我们把ADD定义为0,SUB定义为1....[2],那么就可以如下的定义:

    double add(double, double);
    double sub(double, double);
    double mul(double, double);
    double div(double, double);
    ....
    
    double (*oper_func[])(double,double) = {
        add,sub,mul,div,.....
    };

      

    然后通过下面来调用相应的操作函数,oper为输入的值:

    result = oper_func[oper](op1, op2);

    oper_func从数组中选择正确的函数指针,而函数调用操作符将执行这个函数。当然,我们这里还需要的注意的是数组越界问题,为了保证所使用的下标位于合法的范围内,在一开始的时候我们可以先检查下标的合法性,然后再进行调用操作。

    •  参考资料
      •   [1] 我们老师上课的课件,具体解释权归老师所以;
      •       [2] 《C和指针》

    复杂函数指针的应用

      来看下下面这个代码:

    void (* pf(void (*fun)()))()

      咋第一眼看上去有点头晕呢!那么多括号,那么多嵌套。莫急莫急!我们来把它细分一下,首先看 void (*fun)(),这就是我们前面看到的函数指针,这个没问题。然后再看看

    pf(void (*fun)()),pf不也是一个函数嘛,只不过它的参数是一个函数指针罢了。那么如果我们令pf(void (*fun)())为X,那么那一整个式子可以表示成:void(*X)(),这就是函数指针的定义。说明X又是一个函数指针,也就是说函数pf的返回值又是一个函数指针。这样就都清楚啦,再来屡一下:pf这样一个函数:接受参数为函数指针,而且pf的返回值也是个参数为void返回值为void的函数指针。

    而且我们还可以用下面这两个定义来表示上面这个函数定义,这样看起来就明了多了:

    typedef  void  (*PF)();
    PF pf(PF fun);
    typedef void PF();
    PF *pf(PF *fun);

     从下面这个定义方式,我们就可以很明确的看到pf函数的参数是一个PF*类型,返回值也是一个PF*类型的函数。


     

    下面用一个程序来看看这个应用的例子:

    #include <stdio.h>
    
    void fun_a(int a,int b)
    {
        printf("This is function A.
    ");
    }
    
    void fun_b(int a)
    {
        printf("This is function B.
    ");
    }
    
    void (*pf(void (*fun)(int,int)))(int)
    {
            void (*p)(int);
            
            printf("This is function pf.
    ");
            fun(1,1);
            
            p = fun_b;
            
            return p;
    }
    
    int main()
    {
        pf(fun_a)(1);
        return 0;
    }

    输出结果是:

     参考资料:

    http://bbs.csdn.net/topics/30344321

  • 相关阅读:
    几道cf水题
    cf水题
    一道cf水题
    c++list用法
    c++map用法
    c++ vector常见用法
    c++string,常见用法总结
    复变函数考试后的反思
    [FZYZOJ 1204] 零和问题
    [FZYZOJ 1202] 金坷垃
  • 原文地址:https://www.cnblogs.com/Jason-Damon/p/3373101.html
Copyright © 2011-2022 走看看