C/C++函数指针(typedef简化定义)

学习要点:
        1,函数地址的一般定义和typedef简化定义;
        2,函数地址的获取;
        3,A函数地址作为B函数参数的传递;
    函数存放在内存的代码区域内,它们同样有地址.如果我们有一个int test(int a)的函数,那么,它的地址就是函数的名字,这一点如同
数组一样,数组的名字就是数组的起始地址。
    定义一个指向函数的指针用如下的形式,以上面的test()为例:
    int (*fp)(int a);//这里就定义了一个指向函数(这个函数的参数仅仅为一个int类型)的指针
    一般定义方式:
    data_types (*func_pointer)( data_types arg1, data_types arg2, ...,data_types argn);
    函数指针不能绝对不能指向不同类型,或者是带不同形参的函数,这点尤其注意.
    在定义函数指针的时候我们很容易犯如下的错误:
    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]()这样地址带括号的操作,而函数指针不同它是一个例外,函数指针只所以这么叫它就是因为它是指向函数指向内存的代码区的指针
,它被系统授予允许与()括号操作的权利,进行间接的函数调用,既然函数指针允许这么操作,那么被定义成函数指针的数组就一定是可以一样的操作的。

    对上一例子改动:
     // a.c
    #include  < iostream >
    #include 
< string >
    
using   namespace  std;

    
void  t1(){cout << " test1\n " ;}
    
void  t2(){cout << " test2\n " ;}
    
void  t3(){cout << " test3\n " ;}

    
int  main( int  argc, char *  argv[])
    {
            
void *  a[ 3 ];
            a[
0 ] = ( void   * )t1;
            a[
1 ] = ( void   * )t2;
            a[
2 ] = ( void   * )t3;
            printf(
" t1=0x%x\n " , * t1);
            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 ();
            
return   0 ;
    }

    编译:
    [root@CHN ]# g++ a.c -o a
    a.c: In function `int main(int, char**)':
    a.c:16: warning: the address of `void t1()', will always be `true'
    [root@CHN ]# ./a
    t1=0x804881c
    比较t1()的内存地址和数组a[0]所存储的地址是否一致1|0x804881c
    test1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值