原文地址:http://blog.csdn.net/qingshuiyangfan/article/details/7692647

学习要点:

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

转载于:https://www.cnblogs.com/pengkunfan/p/3486801.html

c/c++函数指针(3)相关推荐

  1. c/c++中的函数指针和指针函数

    定义 1.指针函数,本质是函数,返回值为指针,形如,int *pfun(int, int),由于"*"的优先级低于"()"的优先级,所以等同于int *(pfu ...

  2. 函数指针amp;绑定: boost::functoin/std::function/bind

    see link: https://isocpp.org/wiki/faq/pointers-to-members function vs template: http://stackoverflow ...

  3. 0709 C语言常见误区----------函数指针问题

    1.函数指针的定义 对于函数 void test(int a, int b){ // } 其函数指针类型是void (* ) (int , int), 注意这里第一个括号不能少, 定义一个函数指针,v ...

  4. java跨函数跳转_C语言中将绝对地址转换为函数指针以及跳转到内存指定位置处执行的技巧...

    1.方法一 要对绝对地址0x100000赋值,我们可以用 (unsigned int  * ) 0x100000 = 1234; 那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做? ...

  5. 函数指针(就做个笔记)

    1,函数的地址 #include <stdio.h> int main(){int i=0;printf("main=%p\n",main);printf(" ...

  6. 函数指针--Nginx和Redis中两种回调函数写法

    1.Nginx和Redis中两种回调函数写法 #include <stdio.h>//仿Nginx风格 //结构外声明函数指针类型 typedef void (*ngx_connectio ...

  7. 结构体中定义函数指针

    结构体指针变量的定义,定义结构体变量的一般形式如下: 形式1:先定义结构体类型,再定义变量 struct结构体标识符 { 成员变量列表;- }; struct 结构体标识符 *指针变量名; 变量初始化 ...

  8. C++中函数指针的使用

    A function pointer is a variable that stores the address of a function that can later be called thro ...

  9. C++函数指针解引用

    声明函数的引用: int f( double ); int (* const pf)(double) = f;       // pf是指向函数f()的常量指针 int (&rf)(doubl ...

  10. C++成员变量指针和成员函数指针【The semantics of funcitons】

    原文:https://blog.csdn.net/laojiu_/article/details/68946915 (原文有笔误) 1. #include <cstdio> #includ ...

最新文章

  1. 分布式b2b b2c o2o电子商务云平台
  2. python语言怎么学-如何从零开始学习Python,python语言编程入门
  3. C语言的补码表示和unsigned及signed的转换
  4. c语言中输入10,10 is greater than 0,2013练习题__Student
  5. Oracle 11g 基于CentOS7安装并启动em
  6. Udp广播的发送和接收(iOS + AsyncUdpSocket)下篇
  7. css --- [练手小项目]样式小结(字体、颜色的语义 清除浮动的使用)
  8. Ⅴ0还有别的方法设置图案吗_水冷空调扇如何使用 水冷空调扇使用方法介绍【图文】...
  9. JVM常见的七种垃圾收集器的简单比较
  10. python怎么在gui中显示图片_Python 3-如何从Web检索图像并使用TKINTER在GUI中显示?...
  11. 计算机打不开菜鸟打印组件,菜鸟打印常见问题
  12. 【聚沙成塔】将Mon Jun 01 2020 00:00:00 GMT+0800 (中国标准时间) 转换为 2020-06
  13. 测量string变量长度函数_测量字符串长度的函数
  14. 诗词收集——用于人文素养扫盲
  15. 让Thinkpad USB键盘支持小红帽中键滚轮的方法(ThinkPad USB Keyboard with TrackPoint)
  16. 2021-03-24
  17. uniapp处理tsconfig.json报错
  18. 有python画螺旋线
  19. 地理空间框架(二):大地水准面、似大地水准面、参考椭球面
  20. 社区社群运营,如何打造火爆营销的方法?

热门文章

  1. URAL 1664 Pipeline Transportation
  2. ip dhcp snooping的设置
  3. Web应用中优化IBatis性能
  4. 安卓拍照上传php服务器,Android拍照上传至PHP服务器并写入MySql数据库(下)
  5. 利用SmsManager发送短信
  6. apk签名的重要性和方法
  7. android 4.0 屏蔽home键实现
  8. Android 中的Intent的某些用法
  9. 用 pre-commit hook 解决 Python 项目编码规范
  10. [网络流24题-9]试题库问题