函数指针

2016-08-22  本文已影响44人  ganser

是什么?

函数定义:

函数的本质就是表达式的抽象,它在内存中对应的数据结构为堆栈帧,它表示一段连续指令序列,这段连续指令序列在内存中有一个确定的起始地址,它执行时一般需要传入参数,执行结束后会返回一个参数。

函数指针定义:

表示一个函数的入口地址。

为什么?

使用函数指针的好处就是在处理“在运行时根据数据的具体状态来选择相应的处理方式”这种需求时更加灵活。

怎么样?

1、有几种类型

//指向C语言函数和C++静态成员函数的函数指针
int (*pFunction)(float,char,char)=NULL;

//指向C++非静态成员函数的函数指针
int (MyClass::*pMemberFunction)(float,char,char)=NULL;
int (MyClass::*pConstMemberFunction)(float,char,char) const=NULL;

2、调用的规则

一般来说,不用太关注这个问题。调用规则主要是指函数被调用的方式,常见的有_stdcall,_fastcall,_pascal,_cdecl等规则。不同的规则在参数压入堆栈的顺序是不同的,同时在有调用者清理压入堆栈的参数还是由被调用者清理压入堆栈的参数上也是不同的。一般来说,如果你没有显式的说明调用规则的话,编译器会统一按照_cdecl来处理。

3、赋值和调用

//赋值
pFunction=func1;
pFunction=&func2;

//调用
pFunction(10.0,’a’,’b’);
(*pFunction)(10.0,’a’,’b’);

4、作为参数

只需要在函数的参数列表中,声明一个函数指针类型的参数即可,然后再调用的时候传给它一个实参就可以了。你可以这么想象,就是把函数指针的赋值语句的等号换成了形参和实参结合的模式就行。

#include<stdio.h> 
 
float add(float a,float b){return a+b;} 
 
float minus(float a,float b){return a-b;} 
 
float multiply(float a,float b){return a*b;} 
 
float divide(float a,float b){return a/b;} 
 
int pass_func_pointer(float (*pFunction)(float a,float b)) 
 
{ 
 
      float result=pFunction(10.0,12.0); 
 
      printf("result=%f\n",result); 
 
} 
 
int main() 
 
{ 
 
      pass_func_pointer(add); 
 
      pass_func_pointer(minus); 
 
      pass_func_pointer(multiply); 
 
      pass_func_pointer(divide); 
 
      return 0; 
 
} 

5、作为返回值

float (* func(char op) ) (float ,float)

其具体含义就是,声明了这样一个函数:

其名称为func,其参数的个数为1个;

其各个参数的类型为:op—char;

其返回变量(函数指针)类型为:float(*)(float,float)

6、作为数组

函数指针有意思的地方在于,它使用从0到n-1这个n个连续的整数下标直接映射到函数上。

和前面一样,我们也是类比着定义普通指针数组来定义函数指针数组。首先,考虑一个浮点数指针数组,数组的长度为10.我们都知道用下面的形式来定义:

float * pFloatArray[10];

从形式上分析,用中括号明确了是定义指针变量还是定义指针数组这个语义。用数字10明确了这个数组能容纳多少个函数指针这个语义。形式上看,中括号是紧接在指针名称的后面再中括号里面是一个需要在编译时期间就能够确定的常数。

现在我们来类比函数指针数组的定义,定义一个指向函数指针类型为:float (*)(float,float)的函数指针数组,数组长度为10.正确的形式为:

float(* pFunctionArray[10])(float,float)

从形式上看,这种定义方式和定义普通指针的定义方式是一致的:都是在指针名称后面紧接着一个中括号,然后里面是一个编译期间能够确定的常数。这种形式上的一致性,可以方便我们对形式的记忆,进而达到对内容的理解。

下面是一个例子程序:

#include<stdio.h> 
 
float add(float a,float b){return a+b;} 
 
float minus(float a,float b){return a-b;} 
 
float multiply(float a,float b){return a*b;} 
 
float divide(float a,float b){return a/b;} 
 
int main() 
 
{ 
 
      float(*func_pointers[4])(float,float)={add,minus,multiply,divide}; 
 
      int i=0; 
 
      float a=10.0,b=5.0; 
 
      for(i=0;i<4;i++) 
 
      { 
 
             printf("result is %f\n",func_pointers[i](a,b)); 
 
      } 
 
      return 0; 
 
} 

7、使用typedef

从哲学角度讲,形式过于复杂的话,还是抽象的层次太低。如果我们使用多层次的抽象,这样最上层的表示就会简化很多。这就是引入typedef的原因,使用typedef可以简化函数指针的定义,因为typedef可以定义新的类型:

同样,在使用typedef定义函数指针类型的时候,也和普通的使用typedef引入新类型的方式不一样。我们和前面一样对照着普通的定义方式来学习:

typedef int bool;

这在C语言中很常用,由于C语言中没有bool类型,这样定义之后可以从形式上引入一个bool类型,提高代码可读性。所以形式为: typedef 已知类型 新类型;

现在我们要将float ()(float,float)类型声明为一种新类型,按照上面的方式,貌似为:typedef float()(float,float) fpType;然而,前面的经验告诉我们应该这样定义啊:

typedef float(*fpType)(float,float);

这样我们就可以用fpType来表示float ()(float,float)这种类型了。所以定义一个新的指向float ()(float,float)类型的指针变量的时候,我们就可以采用下面这种形式了:

fpType pFunction;

在定义函数指针数组的时候可以这样定义:

fpType pFunctions[10];

在定义函数指针类型参数时可以这样定义:

void func(fpType pFunction);

在定义函数指针类型的返回值时可以这样定义:

fpType func(int a);

现在我们再来看一下,unix中的那个signal函数,其形式为:

void (signal)(int signo,void (func)(int)))(int);

现在我们定义一个类型为:

typedef void (*pSgnType)(int);

这样上面的函数就能表达为:

pSgnType signal(int signo,pSgnType func);

这样是不是看起来清爽多了。

其实上面的signal函数也能这样定义:

首先引入新类型:

typedef void SgnType(int)

然后signal函数的声明改为:

SgnType *signal(int signo,SgnType *func);

按照前面对这些形式的解释,理解这个应该没难度~~

现在在引入最后一个例子,关于使用typedef来简化函数指针定义的:

#include<stdio.h> 
 
#include<stdlib.h> 
 
#include<string.h> 
 
float add(float a,float b){return a+b;} 
 
float minus(float a,float b){return a-b;} 
 
float multiply(float a,float b){return a*b;} 
 
float divide(float a,float b){return a/b;} 
 
  
 
typedef float (*pArithmeticOperations)(float,float); 
 
typedef float ArithmeticOperations(float,float); 
 
  
 
int main() 
 
{ 
 
      pArithmeticOperations pao=add; 
 
      pArithmeticOperations paos[4]={add,minus,multiply,divide}; 
 
      
 
      ArithmeticOperations *ao=add; 
 
      ArithmeticOperations *aos[4]={add,minus,multiply,divide}; 
 
      float a=10.0,b=5.0; 
 
      float result=0.0; 
 
      int i=0; 
 
      result=pao(a,b); 
 
      printf("the result of pao is %f\n",result); 
 
      
 
      printf("the results of paos are:\n"); 
 
      for(i=0;i<4;i++) 
 
      { 
 
             result=paos[i](a,b); 
 
             printf("result=%f\n",result); 
 
      } 
 
      
 
      result=ao(a,b); 
 
      printf("\n\nthe result of ao is :%f\n",result); 
 
      
 
      printf("the results of aos are:\n"); 
 
      for(i=0;i<4;i++) 
 
      { 
 
             result=aos[i](a,b); 
 
             printf("result=%f\n",result); 
 
      } 
 
      return 0; 
 
} 

引用:
1、http://hipercomer.blog.51cto.com/4415661/792302
2、http://www.newty.de/fpt/index.html

上一篇下一篇

猜你喜欢

热点阅读