zoukankan      html  css  js  c++  java
  • 函数指针

     一旦函数被编译并载入计算机中执行,它就会占用一块内存,这块内存有一个地址,因此函数也有地址。

    1. 定义一个函数指针

    示例代码如下:

    void (*funcPtr)();

    这个例子将funcPtr定义为一个指向函数的指针,这个函数没有参数,返回值为空。

    :*funcPtr 两侧的括号是必须的,如果去掉括号,

        void *funcPtr(); // 这表示funcPtr是一个函数,它返回类型为 void*

    由于直接定义一个函数指针显得冗长,我们可以使用typedef对其进行简化,如下:

    typedef void (*FuncPtrType)();

    此时我们将FuncPtrType定义为了一个函数指针类型,

    接下来我们可以使用这个类型来定义变量:

    FuncPtrType funcPtr; // 这个funcPtr与void (funcPtr*)();中的含义是一样的。

    许多C/C++的面试题都喜欢出一些关于指针的题目,比如:说出下列式子的含义,

    复制代码
    1 void * (*(*fp1)(int))[10];
    2  
    3 float (*(*fp2)(int, int, float))(int);
    4  
    5 typedef double (*(*(*fp3)())[10])();
    6 fp3 a;
    7  

    8 int (*(*fp4)[10])(); 

    复制代码

     

    对于fp1:

    我们从里向外一点一点分析,首先(*fp1)(int),这说明fp1是一个函数指针,它有一个int类型的参数;然后我们来找这个函数指针类型的返回值,注意到*(*fp1)(int),所以我们可以断定它的返回值是一个指针,指针指向什么呢?

    我们可以看到最外层剩余的部分是void* [10],因此这个函数的返回值是一个指针,这个指针指向一个包含十个void*类型数据的数组。

    综上:fp1是一个函数指针,它所指向的函数有一个int类型的参数,并且这个函数的返回值是一个指针,这个指针指向一个包含10个void*元素的数组。

    对于fp2

    就不再赘述了。fp2是一个函数指针,它所指向的函数有三个参数,参数类型分别为int,int,float;它的返回值是一个函数指针,这个函数指针所指向的函数具有一个int类型的参数,且返回类型为float。

    对于fp3

    fp3被定义为一个函数指针类型,这种函数指针所指向的函数的参数为空;它的返回值是一个指针,这个指针指向一个包含10元素的函数指针数组,这些函数指针所指向的函数的参数为空,返回值为double。

    对于fp4

    fp4是一个指针,这个指针指向一个包含10元素的函数指针数组,这些函数指针所指向的函数的参数为空,返回值为int。

    2. 使用函数指针

    在使用函数指针之前,我们首先要弄明白什么是函数指针。

    先看一段代码:、

    复制代码
     1 void func(){
     2     cout<<"hello.\n";
     3 }
     4  
     5 typedef void (*FuncPtr)();
     6  
     7 int main(){
     8     func();
     9     (*func)();  // 输出:hello. 注意这一行
    10         
    11     FuncPtr fp = func;
    12     fp();      // 输出:hello.
    13     fp = &func;
    14     fp();      // 输出:hello.
    15     (*fp)();   // 输出:hello.
    16 }
    复制代码

    当这段代码成功被执行的时候,我自己也有点迷糊了,产生这样一个疑问:

    函数名到底是什么东东?

    我最初的认识是函数名就是代表了一段代码。但是(*func)();这行代码却可以正确地运行,那函数名是一个函数指针?但是fp = &func;这一行代码也没有错啊,Oh, My Dog.

    在《C陷阱与缺陷》中有这样一段描述:

    fp是一个函数指针,那么*fp就是该指针所指向的函数,所以(*fp)()就是调用该函数的方式。ANSI C标准允许程序员将上式简写为fp(),但是一定要记住这种写法只是一种简写形式。

    在表达式(*fp)()中,*fp两侧的括号非常重要,因为函数运算符()的优先级要高于单目运算符*。如果*fp没有括号,那么*fp实际上与*(fp())的含义完全一致,ANSI C把它写作*(*(fp)())的简写形式。

    根据以上的描述,我们似乎可以得到这样一个结论:

    1. func是一个函数指针

    2. func()是(*func)()的一个简写形式

    3. &func是&(*func)的简写形式

    如果这样理解正确的话,那么上面那段代码就顺理成章了。

    有一种使用函数指针的方式很常用,叫做表驱动编码(table-driven code),使用这种方法可以根据不同的状态码来选择执行不同的函数。如果你用过MFC的话,应该对那个MESSAGE_MAP印象深刻吧,它本质上也是使用了这种思想,根据不同的消息ID来选择消息处理函数。

    我们可以列出这种方式的一个框架,

    复制代码
     1 typedef void (FuncPtr*)();// 这里就不要参数了
     2 struct Msg{
     3     int ID;
     4     FuncPtr func; 
     5 };
     6  
     7 FuncPtr func1, func2, func3; // 声明三个函数指针
     8 // 对函数指针赋值
     9 initialFuncPtr();
    10  
    11 Msg arrMsg[] = {1, func1, 2, func2, 3, func3, 0, NULL}; // 最后一个赋值为0
    12  
    13 int ID = GetMsgID();
    14 for (int i=0; arrMsg[i].ID; ++i){
    15     if (ID == arrMsg[i].ID)
    16         arrMsg[i].func();
    17 }
    复制代码

    参考博客:https://www.cnblogs.com/hdtianfu/archive/2011/12/10/2283009.html

  • 相关阅读:
    Python的time模块随笔。
    生成器递归解决八皇后问题(勉强理解)
    Python历史「解密」Python底层逻辑 及Python 字节码介绍(转帖)
    可迭代(Interable),迭代器(Iterator),生成器(generator)的手记(11月26日再次修改)
    __getattr__,__setattr__,__delattr__,__getattribute__,记录
    关于property的一些记录,以及描述符(descriptor)中__get__,__set__,__delete__的属性使用。
    Python魔法方法之容器部方法(__len__,__getitem__,__setitem__,__delitem__,__missing__)(更新版本)
    Mac下PyCharm快捷键大全!(每天记住几个)
    开笔了,就写一下,hasattr,getattr,setattr。
    GUI
  • 原文地址:https://www.cnblogs.com/home123/p/15575102.html
Copyright © 2011-2022 走看看