查看: 2815|回复: 2

函数指针的资料

[复制链接]
  • TA的每日心情
    郁闷
    2025-2-20 09:41
  • 签到天数: 1704 天

    连续签到: 1 天

    [LV.Master]伴坛终老

    发表于 2013-1-22 09:31:41 | 显示全部楼层 |阅读模式
    分享到:
    [出处:PConline  作者:管宁  责任编辑:xietaoming ]
    C/C++中函数指针的含义
      函数存放在内存的代码区域内,它们同样有地址,我们如何能获得函数的地址呢?


      如果我们有一个int test(int a)的函数,那么,它的地址就是函数的名字,这一点如同数组一样,数组的名字就是数组的起始地址。

      定义一个指向函数的指针用如下的形式,以上面的test()为例:

    int (*fp)(int a);//这里就定义了一个指向函数的指针

      函数指针不能绝对不能指向不同类型,或者是带不同形参的函数,在定义函数指针的时候我们很容易犯如下的错误。

    int *fp(int a);//这里是错误的,因为按照结合性和优先级来看就是先和()结合,然后变成了一个返回整形指针的函数了,而不是函数指针,这一点尤其需要注意!

      下面我们来看一个具体的例子:

    #include <iostream>  
    #include <string>  
    using namespace std;  
      
    int test(int a);  
      
    void main(int argc,char* argv[])   
    {  
        cout<<test<<endl;//显示函数地址
        int (*fp)(int a);  
        fp=test;//将函数test的地址赋给函数学指针fp
        cout<<fp(5)<<"|"<<(*fp)(10)<<endl;  
    //上面的输出fp(5),这是标准c++的写法,(*fp)(10)这是兼容c语言的标准写法,两种同意,但注意区分,避免写的程序产生移植性问题!
        cin.get();  
    }  
      
    int test(int a)  
    {  
        return a;  
    }

      typedef定义可以简化函数指针的定义,在定义一个的时候感觉不出来,但定义多了就知道方便了,上面的代码改写成如下的形式:

    #include <iostream>  
    #include <string>  
    using namespace std;  
      
    int test(int a);  
      
    void main(int argc,char* argv[])   
    {  
        cout<<test<<endl;  
        typedef int (*fp)(int a);//注意,这里不是生命函数指针,而是定义一个函数指针的类型,这个类型是自己定义的,类型名为fp
        fp fpi;//这里利用自己定义的类型名fp定义了一个fpi的函数指针!
        fpi=test;  
        cout<<fpi(5)<<"|"<<(*fpi)(10)<<endl;  
        cin.get();  
    }  
      
    int test(int a)  
    {  
        return a;  
    }


      函数指针同样是可以作为参数传递给函数的,下面我们看个例子,仔细阅读你将会发现它的用处,稍加推理可以很方便我们进行一些复杂的编程工作。

    //-------------------该例以上一个例子作为基础稍加了修改-----------------------------
    #include <iostream>   
    #include <string>   
    using namespace std;   
       
    int test(int);   
      
    int test2(int (*ra)(int),int);  
      
    void main(int argc,char* argv[])      
    {   
        cout<<test<<endl;  
        typedef int (*fp)(int);   
        fp fpi;  
        fpi=test;//fpi赋予test 函数的内存地址
      
        cout<<test2(fpi,1)<<endl;//这里调用test2函数的时候,这里把fpi所存储的函数地址(test的函数地址)传递了给test2的第一个形参
        cin.get();  
    }   
       
    int test(int a)  
    {   
        return a-1;  
    }  
      
    int test2(int (*ra)(int),int b)//这里定义了一个名字为ra的函数指针
    {  
        int c=ra(10)+b;//在调用之后,ra已经指向fpi所指向的函数地址即test函数
        return c;  
    }

      利用函数指针,我们可以构成指针数组,更明确点的说法是构成指向函数的指针数组,这么说可能就容易理解的多了。

    #include <iostream>   
    #include <string>   
    using namespace std;  
      
    void t1(){cout<<"test1";}  
    void t2(){cout<<"test2";}  
    void t3(){cout<<"test3";}  
    void main(int argc,char* argv[])      
    {  
        void* a[]={t1,t2,t3};  
        cout<<"比较t1()的内存地址和数组a[0]所存储的地址是否一致"<<t1<<"|"<<a[0]<<endl;  
      
        cout<<a[0]();//错误!指针数组是不能利用数组下标操作调用函数的
      
        typedef void (*fp)();//自定义一个函数指针类型
        fp b[]={t1,t2,t3}; //利用自定义类型fp把b[]定义趁一个指向函数的指针数组
        b[0]();//现在利用指向函数的指针数组进行下标操作就可以进行函数的间接调用了;
        cin.get();  
    }

      仔细看上面的例子可能不用我多说大家也会知道是怎么一会事情了,最后我们做一个重点小结,只要记住这一点,对于理解利用函数指针构成数组进行函数间接调用就很容易了!

    void* a[]={t1,t2,t3};
    cout<<"比较t1()的内存地址和数组a[0]所存储的地址是否一致"<<t1<<"|"<<a[0]<<endl;

    cout<<a[0]();//错误!指针数组是不能利用数组下标操作调用函数的

      上面的这一小段中的错误行,为什么不能这么调用呢?

      前一篇教程我们已经说的很清楚了,不过在这里我们还是复习一下概念,指针数组元素所保存的只是一个内存地址,既然只是个内存地址就不可能进行a[0]()这样地址带括号的操作,而函数指针不同它是一个例外,函数指针只所以这么叫它就是因为它是指向函数指向内存的代码区的指针,它被系统授予允许与()括号操作的权利,进行间接的函数调用,既然函数指针允许这么操作,那么被定义成函数指针的数组就一定是可以一样的操作的。


    回复

    举报

  • TA的每日心情
    郁闷
    2025-2-20 09:41
  • 签到天数: 1704 天

    连续签到: 1 天

    [LV.Master]伴坛终老

    发表于 2013-1-22 09:32:36 | 显示全部楼层
    [by ☆Coderui☆ @baidu]
    C函数指针的用法
    ------------------------------------------------------------------------------------------------
    函数指针通常用来实现回调,其基本用法如下:
    1、定义函数指针类型
    // 定义一个原型为int Fun( int a );的函数指针
    typedef int (*PTRFUN) ( int aPara );
    2、函数指针变量的定义
    PTRFUN pFun;    // pFun 为函数指针变量名
    int (*pFun2) ( int a );   // pFun2也是函数指针变量名
    3、函数指针作为函数的参数传递
    // 定义回调函数
    int CallBack( int a ){
        return ++a;
    }
    // 定义回调者函数
    void Caller( PTRFUN cb )
    // void Caller( int (*cb) ( int ) ) // 也可这样申明
    {
        int nPara = 1;
        int nRet = cb( nPara );
    }
    // 使用回调
    void Test(){
        Caller( CallBack ); // 直接使用回调函数
        PTRFUN cb = CallBack; // int (*cb) ( int ); cb = CallBack;
        int nRet1 = cb( 99 ); // nRet1 = 100;
    }
    4、函数指针的指针使用
    // 定义函数指针的指针
    typedef int (**PTRPTRFUN) ( int aPara );
    // 函数指针的指针作为参数
    void PtrCaller( PTRPTRFUN cb )
    // void PtrCaller( PTRFUN* cb )           // 指针申明
    // void PtrCaller( int (**cb) ( int ) ) // 原型申明
    {
        int nRet = (*cb)(999); // nRet = 1000;
    }

    // 使用函数指针的指针
    void Test(){
        PTRFUN cb = CallBack;
        PtrCaller( &cb );
    }
    5、函数指针数组的使用
    // 函数指针数组的定义
    PTRFUN fArray[10];
    // int (*fArray[10]) ( int );   // 原型定义
    for ( int i = 0; i < 10; i++ ){
        fArray = CallBack;
        int nRet = fArray(i);    // nRet = i+1;
    }
    6、函数指针的大小
    // 既然叫指针,所以跟普通的指针一样在32位系统下大小都为4
    int nSz1 = sizeof(PTRFUN);      // nSz1 = 4;
    int nSz2 = sizeof(PTRPTRFUN);   // nSz2 = 4;
    注意:
            编译器存在多种种调用规范,如在Visual C++中,可以在函数类型前加_cdecl,_stdcall或者_pascal来表示其调用规范(默认为_cdecl)。调用规范影响编译器产生的给定函数名,参数传递的顺序(从右到左或从左到右),堆栈清理责任(调用者或者被调用者)以及参数传递机制(堆栈,CPU寄存器等)。
    ------------------------------------------------------------------------------------------------
    函数指针与typedef
    关于C++中函数指针的使用(包含对typedef用法的讨论)
    (一)简单的函数指针的应用。
    //形式1:返回类型(*函数名)(参数表)
    char (*pFun)(int);
    char glFun(int a){ return;}
    void main()
    {
          pFun = glFun;
          (*pFun)(2);
    }
            第一行定义了一个指针变量pFun。首先我们根据前面提到的“形式1”认识到它是一个指向某种函数的指针,这种函数参数是一个int型,返回值是char类型。只有第一句我们还无法使用这个指针,因为我们还未对它进行赋值。
            第二行定义了一个函数glFun()。该函数正好是一个以int为参数返回char的函数。我们要从指针的层次上理解函数——函数的函数名实际上就是一个指针,函数名指向该函数的代码在内存中的首地址。
            然后就是可爱的main()函数了,它的第一句您应该看得懂了——它将函数glFun的地址赋值给变量pFun。main()函数的第二句中“*pFun”显然是取pFun所指向地址的内容,当然也就是取出了函数glFun()的内容,然后给定参数为2。
    (二)使用typedef更直观更方便。
    //形式2:typedef 返回类型(*新类型)(参数表)
    typedef char (*PTRFUN)(int);
    PTRFUN pFun;
    char glFun(int a){ return;}
    void main()
    {
          pFun = glFun;
          (*pFun)(2);
    }
              typedef的功能是定义新的类型。第一句就是定义了一种PTRFUN的类型,并定义这种类型为指向某种函数的指针,这种函数以一个int为参数并返回char类型。后面就可以像使用int,char一样使用PTRFUN了。
            第二行的代码便使用这个新类型定义了变量pFun,此时就可以像使用形式1一样使用这个变量了。
    (三)在C++类中使用函数指针。
    //形式3:typedef 返回类型(类名::*新类型)(参数表)
    class CA
    {
    public:
          char lcFun(int a){ return; }
    };
    CA ca;
    typedef char (CA::*PTRFUN)(int);
    PTRFUN pFun;
    void main()
    {
          pFun = CA::lcFun;
          ca.(*pFun)(2);
    }
            在这里,指针的定义与使用都加上了“类限制”或“对象”,用来指明指针指向的函数是那个类的这里的类对象也可以是使用new得到的。比如:
    CA *pca = new CA;
    pca->(*pFun)(2);
    delete pca;
            而且这个类对象指针可以是类内部成员变量,你甚至可以使用this指针。比如:
            类CA有成员变量PTRFUN m_pfun;
    void CA::lcFun2()
    {
         (this->*m_pFun)(2);
    }
            一句话,使用类成员函数指针必须有“->*”或“.*”的调用。
    ------------------------------------------------------------------------------------------------


    回复 支持 反对

    举报

  • TA的每日心情

    2013-3-9 12:50
  • 签到天数: 8 天

    连续签到: 1 天

    [LV.3]偶尔看看II

    发表于 2013-1-24 23:36:21 | 显示全部楼层
    表示看不懂
    回复 支持 反对

    举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 1/3 下一条

    【预约|参会享"豪"礼】2025慕尼黑上海设备展
    “2025慕尼黑上海电子生产设备展”将于2025年03月26-28日上海新国际博览中心开幕诚邀您的光临!

    查看 »

    手机版|小黑屋|与非网

    GMT+8, 2025-3-9 13:28 , Processed in 0.116127 second(s), 19 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.