博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
函数指针
阅读量:6540 次
发布时间:2019-06-24

本文共 2803 字,大约阅读时间需要 9 分钟。

一、普通的函数指针

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

 

1. 定义一个函数指针

示例代码如下:

void (*funcPtr)();

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

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

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

 

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

typedef void (*FuncPtrType)();

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

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

FuncPtrType funcPtr; // 这个funcPtrvoid (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类型的参数,并且这个函数的返回值是一个指针,这个指针指向一个包含10void*元素的数组。

对于fp2

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

对于fp3

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

对于fp4

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

 

C陷阱与缺陷》中以下面一个例子对函数指针进行了讲解,如下:

(*(void(*)())0)();

如果能明白上边几个例子的含义,那么这个简直就是小case啊!

同学们,你们能说出它的含义么???

 

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 }

 

二、成员函数的指针

class A{private:	int data;public:	A(int i=0):data(i){}	string equal(const A& m){		if(m.data==data)			return "true";		else			return "false";	}};int main(){	A a1(8),a2(4);	string (A::*p)(const A&);	p=&(A::equal);	cout<<(a1.*p)(a2)<

转载于:https://www.cnblogs.com/engineerLF/p/5393167.html

你可能感兴趣的文章
Summary Day30
查看>>
逆向输出回环数组
查看>>
自己动手,实现“你的名字”滤镜
查看>>
高清摄像头MIPI CSI2接口浅解【转】
查看>>
C# CancellationTokenSource和CancellationToken的实现
查看>>
PCIE BAR空间
查看>>
winform命名规范
查看>>
如何用数学课件制作工具画角平分线
查看>>
VS2015 中统计整个项目的代码行数
查看>>
Anaconda入门使用指南
查看>>
UWP控件与DataBind
查看>>
bash: php: command not found
查看>>
XVIII Open Cup named after E.V. Pankratiev. Eastern Grand Prix
查看>>
数据恢复软件如何换机使用?
查看>>
《高性能mysql》到手
查看>>
(转)关于如何学好游戏3D引擎编程的一些经验
查看>>
使用Kotlin为你的APP自定义一个统一的标题栏
查看>>
EF各版本增删查改及执行Sql语句
查看>>
拓扑排序
查看>>
jQGrid API
查看>>