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

    函数指针是指向函数的指针变量。 因而“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。如前所述,C在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后,可用该指针变量调用函数,就如同用指针变量可引用其他类型变量一样,在这些概念上是一致的。函数指针有两个用途:调用函数和做函数的参数。

    方法

      函数指针的声明方法为:
     
      数据类型标志符 (指针变量名) (形参列表);
     
      注1:“函数类型”说明函数的返回类型,由于“()”的优先级高于“*”,所以指针变量名外的括号必不可少,后面的“形参列表”表示指针变量指向的函数所带的参数列表。例如:
     
      int func(int x); /* 声明一个函数 */
     
      int (*f) (int x); /* 声明一个函数指针 */
     
      f=func; /* 将func函数的首地址赋给指针f */
     
      赋值时函数func不带括号,也不带参数,由于func代表函数的首地址,因此经过赋值以后,指针f就指向函数func(x)的代码的首地址。
     
      注2:函数括号中的形参可有可无,视情况而定。
     
      下面的程序说明了函数指针调用函数的方法:
     
      例一、
     
    #include<stdio.h>
    int max(int x,int y){ return(x>y?x:y);
    void main()
    {
    int (*ptr)(int, int);
    int a,b,c;
    ptr=max;
    scanf("%d,%d",&a,&b);
    c=(*ptr)(a,b);
    printf("a=%d,b=%d,max=%d",a,b,c);
    }
       ptr是指向函数的指针变量,所以可把函数max()赋给ptr作为ptr的值,即把 max()的入口地址赋给ptr,以后就可以用ptr来调用该函数,实际上ptr和max都指向同一个入口地址,不同就是ptr是一个指针变量,不像函数名称那样是死的,它可以指向任何函数,就看你想怎么做了。在程序中把哪个函数的地址赋给它,它就指向哪个函数。而后用指针变量调用它,因此可以先后指向不同的函数。不过注意,指向函数的指针变量没有++和--运算,用时要小心
     
      不过,在某些编译器中这是不能通过的。这个例子的补充如下。
     
      应该是这样的:
     
      1.定义函数指针类型:
     
      typedef int (*fun_ptr)(int,int);
     
      2.申明变量,赋值:
     
      fun_ptr max_func=max;
     
      也就是说,赋给函数指针的函数应该和函数指针所指的函数原型是一致的。
     
      例二、
     
    #include<stdio.h>
    void FileFunc()
    {
    printf("FileFunc\n");
    }
    void EditFunc()
    {
    printf("EditFunc\n");
    }
    void main()
    {
    typedef void (*funcp)();
    funcp pfun= FileFunc;
    pfun();
    pfun = EditFunc;
    pfun(); 
    }

    指针函数和函数指针的区别

      1,这两个概念都是简称,指针函数是指带指针的函数,即本质是一个函数。我们知道函数都又有返回类型(如果不返回值,则为无值型),只不过指针函数返回类型是某一类型的指针。
     
      其定义格式如下所示:
     
      返回类型标识符*返回名称(形式参数表)
     
      { 函数体}
     
      返回类型可以是任何基本类型和复合类型。返回指针的函数的用途十分广泛。事实上,每一个函数,即使它不带有返回某种类型的指针,它本身都有一个入口地址,该地址相当于一个指针。比如函数返回一个整型值,实际上也相当于返回一个指针变量的值,不过这时的变量是函数本身而已,而整个函数相当于一个“变量”。例如下面一个返回指针函数的例子:
     
    #include<iostream>
    using namespace std;
    void main()
    {
    float *find(float(*pionter)[4],int n);
    static float score[][4]={{60,70,80,90},{56,89,34,45},{34,23,56,45}};
    float *p;
    int i,m;
    cout<<"Enter the number to be found:";
    cin>>m;
    p=find(score,m);
    for(i=0;i<4;i++)
    {
    cout<<" "<<*(p+i);
    }
    float *find(float(*pionter)[4],int n)/*定义指针函数*/
    float *pt;
    pt=*(pionter+n);
    return(pt);
    }
       学生学号从0号算起,函数find()被定义为指针函数,起形参pointer是指针指向包含4个元素的一维数组的指针变量。pointer+1指向 score的第一行。*(pointer+1)指向第一行的第0个元素。pt是一个指针变量,它指向浮点型变量。main()函数中调用find()函数,将score数组的首地址传给pointer.
     
      2,“函数指针”是指向函数的指针变量,因而“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。如前所述,C在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后,可用该指针变量调用函数,就如同用指针变量可引用其他类型变量一样,在这些概念上一致的。函数指针有两个用途:调用函数和做函数的参数。
     

    函数指针数组的定义

      关于函数指针数组的定义方法,有两种:一种是标准的方法;一种是蒙骗法。
     
      第一种,标准方法:
     
      分析:函数指针数组是一个其元素是函数指针的数组。那么也就是说,此数据结构是一个数组,且其元素是一个指向函数入口地址的指针。
     
      根据分析:首先说明是一个数组:数组名[]
     
      其次,要说明其元素的数据类型指针:*数组名[].
     
      再次,要明确这每一个数组元素是指向函数入口地址的指针:函数返回值类型 (*数组名[])().请注意,这里为什么要把“*数组名[]”用括号扩起来呢?因为圆括号和数组说明符的优先级是等同的,如果不用圆括号把指针数组说明表达式扩起来,根据圆括号和方括号的结合方向,那么 *数组名[]() 说明的是什么呢?是元素返回值类型为指针的函数数组。有这样的函数数祖吗?不知道。所以必须括起来,以保证数组的每一个元素是指针。
     
      第二种,蒙骗法:
     
      尽管函数不是变量,但它在内存中仍有其物理地址,该地址能够赋给指针变量。获取函数地址的方法是:用不带有括号和参数的函数名得到。
     
      函数名相当于一个指向其函数入口指针常量。 那么既然函数名是一个指针常量,那么就可以对其进行一些相应的处理,如强制类型转换。
     
      那么我们就可以把这个地址放在一个整形指针数组中,然后作为函数指针调用即可。
     
      完整例子:
     
    #include "stdio.h"
    int add1(int a1,int b1);
    int add2(int a2,int b2);
    void main()
    {
    int numa1=1,numb1=2;
    int numa2=2,numb2=3;
    int (*op[2])(int a,int b);
    op[0]=add1;
    op[1]=add2;
    printf("%d %d\n",op[0](numa1,numb1),op[1](numa2,numb2));
    }
    int add1(int a1,int b1)
    {
    return a1+b1;
    }
    int add2(int a2,int b2)
    {
    return a2+b2;
    }

    定义成员函数函数指针类型


        typedef void (Class1::* Mem1) (void);

    成员函数指针, 静态函数指针,全局函数指针 区别

        C++的函数指针包括三种:  全局函数指针,类的static函数指针和成员函数指针。前两个几乎没有区别,最后一个与前面两个有本质的区别。是完全不同的类型。C++是强类型的语言,所以使用两类指针时,不能直接赋值。先来看一下他们定义和调用的语法吧:

    class C  
    {
    public:
    int mem_fun(int arg);
    static int static_fun(int arg);
    };

    int global_fun(int arg);

    typedef int (C::*Mem_fun)(int arg);
    Mem_fun pmf = &C::mem_fun; // &(C::mem_fun) is error

    C ci;
    (ci.*pmf)(1); // ci.(*pmf)(1) error; (ci.(*pmf))(1) error;

    typedef int (*C_Fun)(int arg);
    C_Fun p_static_fun = &C::static_fun;
    C_Fun p_global_fun = &global_fun;

        C++的member function pointer调用时,需要依赖具体的对象(或指针);而全局函数和类的static函数指针是可以直接调用的,两种指针的基类型完全不同,调用需要的参数也不同,不能转化。

    贴一下STL的 mem_fun_t  和 mem_fun_ref_t 的实现:

    template <class _Ret, class _Tp>  
    class mem_fun_t : public unary_function<_Tp*,_Ret>
    {
    public:
    explicit mem_fun_t(_Ret (_Tp::*__pf)())
    :_M_f(__pf)
    {
    }
    _Ret operator()(_Tp* __p) const
    {
    return (__p->*_M_f)();
    }
    private:
    _Ret (_Tp::*_M_f)();
    };

    template <class _Ret, class _Tp>
    class mem_fun_ref_t : public unary_function<_Tp,_Ret>
    {
    public:
    explicit mem_fun_ref_t(_Ret (_Tp::*__pf)())
    : _M_f(__pf)
    {
    }
    _Ret operator()(_Tp& __r) const
    {
    return (__r.*_M_f)();
    }
    private:
    _Ret (_Tp::*_M_f)();
    };

        这两个class 是成员函数指针的adapter, 方便泛型算法的调用。从 operator ()的实现中可以明确看出 member function pointer 的使用方法。


  • 相关阅读:
    每日总结
    每日总结
    每日总结
    每日总结
    每日总结
    每日总结
    每日总结
    实现微信小程序和支付宝小程序二维码合并
    Solr教程:1.下载和安装
    如何生成漫画风图片无需下载APP无需PS无需电脑
  • 原文地址:https://www.cnblogs.com/dongzhiquan/p/2093984.html
Copyright © 2011-2022 走看看