如果在程序中定义了一个函数,在编译时,编译系统为函数代码分配一段存储空间,这段存储空间的起始地址(又称入口地址)称为这个函数的指针。可以定义一个指向函数的指针变量,用来存放某一个函数的起始地址,这意味这此指针变量指向该函数。如:int(*p)(int, int),定义p是一个指向函数的指针变量,它可以指向函数的类型为整型且有两个整型参数的函数,p的类型是int(*)(int, int)。
指向函数的指针变量的一个重要用途是把函数的地址作为参数传递给其他函数,有点像个套接口。在很多应用程序中常用菜单提示输入一个数字,然后根据输入的不同值调用不同的函数,实现不同的功能。当然也可以不用指针变量,而用if或者switch语句进行判断,调用不同的函数,但是显然使用指针变量使程序更加简洁和专业。
基本概念略去不谈,这里我关键想能够通过例子说明一点点用法,这里给出我自己编写的一个使用指向函数指针的例子程序(在Visual C++ 6.0中编译通过)。
/*
*使用指向函数的指针实现对多个函数积分的测试程序
*时间:2012.10.13
*作者:江武
*版本:1.0
*/
#include <stdio.h>
#include <math.h>
#define DETA 0.00001 //每一小步积分的间隔,DETA越小误差越小
int main() {
//函数声明
double f1(double, double); //积分函数y = x + 1;
double f2(double, double); //积分函数y = 2*x + 3;
double f3(double, double); //积分函数y = exp(x) + 1;
double f4(double, double); //积分函数y = (x+1)^2;
double f5(double, double); //积分函数y = x^3;
double integral(double a, double b, double(*fun)(double, double)); //统一调用函数的函数接口,使用指向函数的指针
int n; //标志输入的对函数的选择
double a, b; //a,b为函数积分的上下限
while(1) {
printf("==========================================\n");
printf("要求解的函数:(1~5为如下选择,0为重新选择,-1退出:)\n");
printf("1.y = x + 1;\n");
printf("2.y = 2*x + 1;\n");
printf("3.y = exp(x) + 1;\n");
printf("4.y = (x + 1)^2;\n");
printf("5.y = x^3;\n");
printf("您要求的积分函数为:");
scanf("%d", &n);
if(n == 0)
continue; //n==0时重新选择函数
if(n == -1)
break; //n==-1时跳出循环
printf("==========================================\n");
printf("请输入求积分的上限和下限:");
scanf("%lf%lf", &a, &b);
printf("==========================================\n");
switch(n) {
case 1: //n==1时调用f1求积分,下同
printf("积分为:%7.2lf\n", integral(a, b, f1));
break;
case 2:
printf("积分为:%7.2lf\n", integral(a, b, f2));
break;
case 3:
printf("积分为:%7.2lf\n", integral(a, b, f3));
break;
case 4:
printf("积分为:%7.2lf\n", integral(a, b, f4));
break;
case 5:
printf("积分为:%7.2lf\n", integral(a, b, f5));
break;
default :
break;
}
}
return 0;
}
double integral(double a, double b, double(*fun)(double, double)) {
double result;
result = fun(a, b);
return result;
}
double f1(double a, double b) {
double x = a, y;
double area = 0;
double temp;
//b > a正常计算,a < b时交换a,b的值,计算出的积分值取相反数即可,f2、f3、f4、f5一样
if(b > a) {
for(x = a; x <= b; x = x + DETA) {
y = x + 1;
area = area + DETA*y;
}
return (area);
} else {
temp = a;
a = b;
b = temp;
for(x = a; x <= b; x = x + DETA) {
y = x + 1;
area = area + DETA*y;
}
return (-area);
}
}
double f2(double a, double b) {
double x = a, y;
double area = 0;
for(x = a; x <= b; x = x + DETA) {
y = 2*x + 3;
area = area + DETA*y;
}
return area;
}
double f3(double a, double b) {
double x = a, y;
double area = 0;
double temp;
if(b > a) {
for(x = a; x <= b; x = x + DETA) {
y = exp(x) + 1;
area = area + DETA*y;
}
return area;
} else {
temp = a;
a = b;
b = temp;
for(x = a; x <= b; x = x + DETA) {
y = exp(x) + 1;
area = area + DETA*y;
}
return (-area);
}
}
double f4(double a, double b) {
double x = a, y;
double area = 0;
double temp;
if(b > a) {
for(x = a; x <= b; x = x + DETA) {
y = (x + 1)*(x + 1);
area = area + DETA*y;
}
return area;
} else {
temp = a;
a = b;
b = temp;
for(x = a; x <= b; x = x + DETA) {
y = (x + 1)*(x + 1);
area = area + DETA*y;
}
return (-area);
}
}
double f5(double a, double b) {
double x = a, y;
double area = 0;
for(x = a; x <= b; x = x + DETA) {
y = x*x*x;
area = area + DETA*y;
}
return area;
}
每次用指向函数的指针都让我觉得它有点多余,其实用switch和if能够很好的完成对应的功能,而且在本例中也用到了switch。我的观点是尽可能地让自己看起来更牛B一些。如果您了解使用指向函数的指针有明显的优势,请您告诉我。
另外我想提出一个问题,至今我还没有找到答案。请看以下程序:
#include <stdio.h>
int main()
{
int max(int, int); //函数声明
int (*p)(int, int); //定义指向函数的指针变量p
int a, b, c;
p = max; //p指向max函数
printf("Please enter a and b:");
scanf("%d%d", &a, &b);
c = (*p)(a, b); //通过指针变量调用max函数
printf("a = %d\nb = %d\nmax = %d\n", a , b, c);
return 0;
}
int max(int x, int y)
{
int z;
return z = x>y?x:y;
}
程序中使用c = (*p)(a, b)来等价调用max函数,在Visual C++ 6.0中编译通过并得到正确结果。
但是我这样想,既然使用p = max来存放max()函数的入口地址,那么(*p)是地址存放的值,而不是地址,所以程序编译不能通过。而是应该使用c = p(a, b)来等价调用max()函数。巧的是,这样调用也同样能得到正确结果。也就是说c = (*p)(a, b)和c = p(a, b)是等价的(至少对于现在的我来说)。正如在前面我的自己的程序使用的就是后者。现在能力有限,如果您知道这是为什么,我很荣幸能跟您讨论!
另外,使用指向函数的指针时,对应的数据类型最好能够相同,如前两个例子中所示,这样做是有道理的。如第二个例子中,int max(int, int)和int (*p)(int, int),对用的参数和返回值类型都是相同的。