指向函数的指针

1 定义和调用
程序在编译后,每个函数都有一个首地址(也就是函数第一条指令的地址),这个地址称为函数的指针。可以定义指向函数的指针变量,使用指针变量间接调用函数。下面通过一个简单的例子来说明:
float max(float x,float y)
{
return x>y?x:y;
}
float min(float x,float y)
{
return x<y?x:y;
}
main()
{
float a=1,b=2, c;
float (*p)(float x, float y);
p=max;
c=(*p)(a,b); /*等效于 max(a,b)*/
printf("\nmax=%f",c);
p=min;
c=(*p)(a,b); /*等效于min(a,b)*/
printf("\nmin=%f",c);
}
程序运行的结果为:
max=2.000000
min=1.000000

说明:
(1)[color=red]语句float (*p)(float x, float y);定义了一个指向函数的指针变量。函数的格式是:返回值为float型,形式参数列表是(float x, float y)。p定义后,可以指向任何满足该格式的函数[/color]。
(2)定义指向函数的指针变量的格式为:
(3)[color=red]数据类型(*指针变量名称)(形式参数列表)[/color];
(4)其中数据类型是函数返回值的类型,形式参数列表是函数的形式参数列表。
(5)形式参数列表中,参数名称可以省略。比如,float (*p)(float x, float y);可以写为:
(6)float (*p)(float, float);
(7[color=red])注意指针变量名称两边的括号不能省略[/color]。
(8)语句p=max;将max函数的首地址值赋给指针变量p,也就是使p指向函数max。C语言中,函数名称代表函数的首地址。
(9)第一个c=(*p)(a,b);语句:由于p指向了max函数的首地址,(*p)(a,b)完全等效于max(a,b)。函数返回2.0。注意*p两边的括号不能省略。
(10)语句p=min; 将min函数的首地址值赋给指针变量p。p是一个变量,p的值实际上是一个内存地址值,可以指向max,也可以指向min,但指向函数的格式必须与p的定义相符合。
(11)第二个c=(*p)(a,b);语句:由于p指向了min函数的首地址,(*p)(a,b)完全等效于min(a,b)。函数返回1.0。
(12)将函数首地址赋给指针变量时,直接写函数名称即可,不用写括号和函数参数。
(13)利用指针变量调用函数时,要写明函数的实际参数。

提示:定义一个指向函数的指针变量时,一定要使用括号。比较下面的两个定义:
float (*p1)(int x, long y);
float *p2(int x, long y);
[color=red]第一个语句定义了一个指向函数的指针变量p1;第二个语句声明了一个函数p2,p2的形式参数为(int x, long y),返回值为一个float型的指针[/color]。
2 指向函数的指针作为函数参数
有时候,许多函数功能不同,但它们的返回值和形式参数列表都相同。这种情况下,可以构造一个通用的函数,把函数的指针作为函数参数,这样有利于进行程序的模块化设计。比如下面的例子中,我们把对2个float型数进行加、减、乘、除操作的4个函数归纳成一个数学操作函数MathFunc。这样,在调用MathFunc函数时,只要将具体函数名称作为函数实际参数,MathFunc就会自动调用相应的加、减、乘、除函数,并计算出结果。下面是程序的代码:
float Plus(float f1, float f2);
float Minus(float f1, float f2);
float Multiply(float f1, float f2);
float Divide(float f1, float f2);
float MathFunc(float (*p)(float, float), float para1,float para2);
main()
{
float a=1.5, b=2.5;
printf("\na+b=%f", MathFunc(Plus, a,b));
printf("\na-b=%f", MathFunc(Minus, a,b));
printf("\na*b=%f", MathFunc(Multiply, a,b));
printf("\na/b=%f", MathFunc(Divide, a,b));
}

float Plus(float f1, float f2)
{
return f1+f2;
}

float Minus(float f1, float f2)
{
return f1-f2;
}

float Multiply(float f1, float f2)
{
return f1*f2;
}

float Divide(float f1, float f2)
{
return f1/f2;
}

float MathFunc(float (*p)(float, float), float para1,float para2)
{
return (*p)( para1, para2);[color=red]//此处(*p)和p的效果一样,原因是常的函数名字fun就是代
//表一个指针,函数调用时严格的完整格式是(*fun)(x);但是C语言支持函数调用时的缩写
//即省去指着标示,可写为:
//fun(x);
//同样,一个指向函数的指针p,也可以按照省略形式书写。你要想追求代码清晰可以采用完//全书写。[/color]
}

程序运行的结果为:
a+b=4.000000
a-b=-1.000000
a*b=3.750000
a/b=0.600000

例 8-10 利用指向函数的指针,求如下函数在一个区段内的最小值。
本题可以利用指向函数的指针。虽然所给的函数互不相同,但其在一定区间内求最小值的算法都是通用的。因此,可以写一个通用的函数float GetMin(float (*p)(float), float fPos1,float fPos2),用于计算不同函数的最小值。该函数的第一个参数p是一个指向函数的指针,p指向包含一个float型参数的函数。
对应于题目的要求,分别写三个数学函数。
在主函数中,调用GetMin时,第一个参数分别使用上述数学函数的名称,后两个参数传入区间值。这样,调用三次GetMin即可以求出三个函数在给定区间的最小值。
#include "math.h"
float f1(float x)
{
return x*x+2*x+1; /*f1的表达式*/
}
float f2(float x)
{
return 2*sin(x); /*f2的表达式*/
}
float f3(float x)
{
return 2*x+1; /*f3的表达式*/
}
/*p为指向函数的指针,fPos1和fPos2为左右区间的值*/
float GetMin(float (*p)(float), float fPos1,float fPos2)
{
float f,t, fMin, fStep=0.01; /* fStep为步长值*/

/*在fPos1至fPos2的区间内,以fStep为步长,依次比较最小f值*/
fMin=(*p)(fPos1);
for(f=fPos1;f<=fPos2;f+=fStep)
{
t=(*p)(f);
if(t<fMin)
fMin=t;
}
/*返回求出的最小值*/
return fMin;
}
main()
{
/*直接计算并输出结果*/
printf("\nMin value of f1: %f",GetMin(f1,-1,1));
printf("\nMin value of f2: %f",GetMin(f2,1,3));
printf("\nMin value of f3: %f",GetMin(f3,-1,1));
}
程序运行的结果为:
Min value of f1: 0.000000
Min value of f2: 0.282244
Min value of f3: -1.000000
主函数main调用GetMin函数时,传入了函数名称和区间值。GetMin函数在计算函数最小值时,根据传入的函数指针p调用相应的函数。
灵活使用指向函数的指针可以提高程序的扩充性。比如本题,如果要增加条件,计算一个f4(x)=2*logx+1在(0,5)内的最小值,那么我们只需要增加一个f4函数的定义,然后在main函数中就可以直接进行计算GetMin(f4,0,5),GetMin函数不用进行任何修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值