一、指向函数的指针
首先请大家先看这样一条语句,并在看的过程中思考这条语句的意义:
int (*p)(int,int);
经过几分钟的思考,不知道大家是否有了一些想法。如果还是没有思绪,那就请继续看下去吧。
我们可以先将上面的语句进行一个小小的更改:int *p(int,int);不知道大家是否感觉熟悉了一些,这个写法有点类似于函数声明,函数名称为p,两个参数都为int类型,返回值为int *。为了进一步说明,我们要再回忆一点C语言基础知识。在C语言中我们讲到,对于short a[3][4];这条语句,我们可以把远离a的一个括号放到前面去,也就是这样:short[4] a[3];,那就意味着,short a[3][4];这条语句实际上是定义了一个一维数组a,a中有3个元素,每一个元素的类型是short[4]!那么类似的,我们就可以把上面的语句变成:int(int,int) *p;这条语句后半部分的p显然是一个指针,那么前半部分的int(int,int)要怎么理解呢?先看一个这样的例子吧,int fun(int,int);,显而易见,这条语句是一个函数声明,函数名为fun,两个参数都为int,返回值为int。有了这样的基础,我们就可以把int(int,int)理解为“所有拥有两个int类型形参变量,并且返回值为int类型的函数的普适性表达”。
到了这里,我们就对int (*p)(int,int);所表达的意思完全明了了。即,这条语句定义了一个指针变量p,p所指向的元素的类型为int(int,int)(就是说,指针变量p指向了这样一类函数:返回值为int,两个形参类型为int)。
二、实例
为了证实以上的说法,也让大家有一个更直观的认识,下面用一段代码来加深大家的理解:
#include <stdio.h>
int add(int one,int other);
int sub(int one,int other); //两个函数声明
int add(int one,int other){
return one + other;
} //两数相加的函数
int sub(int one,int other){
return one - other;
} //两数相减的函数
int main(){
int m = 10;
int n = 4;
int result;
int (*p)(int,int); //指针变量p的声明
p = add;
result = (*p)(m,n);
printf("%d\n",result);
p = sub;
result = (*p)(m,n);
printf("%d\n",result);
return 0;
}
这段代码的编译输出结果如下:
通过这个结果,我们发现,通过指向函数的指针p,我们也可以完成对一个函数的调用。
这里的核心代码如下:
p = add;
result = (*p)(m,n);
printf("%d\n",result);
在以前的C语言基础学习中,我们已经知道了函数名称的本质就是:该函数的首地址常量,也就是,这个函数的第一条指令的首地址!那么该段函数的第一句p=add; 就是:将add表示的add()函数的第一条指令的首地址赋值给指针变量p的4B空间,使得p指向add()函数。该函数的第二句result = (*p)(m,n); ,就是对add()函数的调用,即,传入两个参数m,n,执行了add()函数。
这就是所谓的“指向函数的指针”!!
三、应用
在彻底明白了什么是指向函数的指针以后,相信大家都有点疑惑,这种指针到底要应用在什么场景呢?
在这里让我们先提出一个名词——“消费未来”。什么是消费未来呢?在编程中就是指:一个将来要实现的函数或者方法,现在不知道它具体要怎么实施,但是当下必须要定义下来。这就是所谓的“消费未来”!!
让我们先来设想一种情况:当我们编写一个线性表工具时,这个表中的数据类型是不确定的,这就意味着表的数据类型是要由今后使用这个工具的用户来具体确定的。那么我们在编写这个工具时排序操作或者找到用户指定的某个数据的下标函数要怎么编写呢?由于这两种操作都需要进行数据的比较,而不同的数据类型比较方法是不同的(若用户定义的数据类型为结构体,就无法直接进行比较)。所以最好的方法就是把这个比较的方法留给用户来编写。我们在自己编写的工具里,函数的参数中可以定义一个指向函数的指针。这样一来,用户使用时只需将自己写好的比较函数名传入我们工具的方法中,就实现了所谓的“消费未来”!
比如,当我们要在工具中编写一个函数用于找到用户指定的数据的下标时,函数代码如下:
int elementIndexOf(const LINEAR *head, USER_TYPE data,
boolean (*eq)(USER_TYPE, USER_TYPE)) { //这里的第三个参数就是一个指向函数的指针,将来的比较函数将由用户自己编写,传参进来即可
if (NULL == head || isLinearEmpty(head)) {
return NOT_FOUND;
}
int index;
for (index = 0; index < head->count; index++) {
if (eq(data, head->data[index])) {
return index;
}
}
return NOT_FOUND;
}
通过以上这样的方法,就完成了“消费未来”的操作。
本文讲解的或许有些浅薄,若有讲解不周或有误的地方,欢迎各位大佬指正。