📄 ex9.cpp
字号:
// 第9章 函数指针
// [例9.1]函数指针间接调用函数
#include<stdio.h>
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
void main()
{ int (*f)(int,int)=max; //定义int (*)(int,int)型的函数指针f并初始化为函数名max
printf("%d,%d\t",max(2,3),f(5,4));// max(2,3)是函数的直接调用,f(5,4)相当于max(5,4)
f=&min; //f获得min的入口地址, min(2,3)是函数的直接调用
printf("%d,%d\t",min(2,3),f(5,4)); //f(5,4) 是min函数的间接调用
} //输出:3,5 2,4
// [例9.2] 根据近似公式=[f(a)+f(a+h)+...+f(b)]h求定积分
#include<stdio.h>
#include <math.h>
double f(double x){ return exp(x)/(2.5+x*x); }
double g(double x){ return (1+x); }
double IntegralEny(double (*f)(double),double a,double b,int n=300)
{ const double h=(b-a)/n; double sum=0;
for( double x=a;x<=b;x+=h) sum+=f(x);
return sum*h;
} //积分函数算法过于简单,不足以解决复杂的收敛性和精度问题。
double IntegralOne(double a,double b,int n=300)
{ const double h=(b-a)/n; double sum=0;
for( double x=a;x<=b;x+=h) sum+=f(x);
return sum*h;
}
void main(void)
{ printf("%f\t",IntegralEny(&f,1,2)); printf("%f\n",IntegralEny(f,1,2,500));
printf("%f\n",IntegralOne(1,2));
printf("%f\t",IntegralEny(g,1,2)); printf("%f\n",IntegralEny(&g,1,2,600));
}
//[例9.3]区间二分法求单变量实函数的根(选讲)
#include<stdio.h>
#include<math.h>
typedef double real;
int single(real(*f)(real),real a,real b,real& x)
{ const real eps=1.0e-12;
if(f(a)*f(b)>0.0 ) return 0;
for(;;)
{ x = (a+b) / 2.0;
if (f(a)*f(x)<0.0) b = x;
else a = x;
if(b-a <= eps) { x =(a+b)/2.0; return 1; }
} //程序要求b>a
}
int muliply(real(*f)(real),real a,real b,int n,real xr[])
{ const real dx=(b-a)/n; // const 关键字冻结区间的步长增量dx
int m=0; //纪录区间的根的个数m
real x; //局部变量x用于传递分区间的实根
for(int k=0;k<n;k++) //从左到右搜寻每一个分区间
{ b=a+dx; //右端点
if(single(f,a,b,x)==1) //分区间求根成功
{ xr[m]=x; //实根存入数组中
m++; //根的个数加1
}
a=b; //右端点变为下一个迭代中的左端点
}
return m;
}
real f1(real x){ return ((x-2.0)*x-4.0)*x-7.0;} //三个示范的单变元函数
real f2(real x){ return exp(x)+x-2; }
real fm(real x){ return (((x-29.1)*x+196.2)*x+114.2)*x-782.6; }
void main(void)
{ real root;
single(f1,3,4,root); printf("f1(%f)=%16.13f\t",root,f1(root));
single(f2,0,2,root); printf("f2(%f)=%16.13f\n",root,f2(root));
real* const p=new real[4]; //四次多项式最多四个根,因此开辟四个元素的堆空间
int m=muliply(fm,0,100,100,p); //区间[0,100]中搜寻,步长为1
for(int k=0;k<m;k++) //显示所有求得的根
printf("fm(%9.6f)=%016.13f\n",p[k],fm(p[k]));
delete []p;
} /////////////程序运行输出结果://///////////////////
//[例9.4] 牛顿迭代法(选讲)
#include<stdio.h>
#include<math.h>
typedef double real;
int newtonroot(real(*f)(real),real(*df)(real),real x, real & root)
{ root=88888.8888; //设置一个醒目的初始值,仅求根成功该值重定义
const real eps = 1e-15, maxiterations=616, nearzero = 1e-20;
real lastx;
int i=0; // i控制循环的迭代变量
int erinfo = 0; // erinfo循环状态信息亦用于跳出循环
do{
//**/ if (fabs(x) > nearzero) { //**///程序屏蔽0向量解
if (fabs(df(x)) > nearzero) //算法要求切线刚度不靠近零
{ lastx = x;
x -= f(x) / df(x); //牛顿法核心迭代公式x = x -f(x) /df(x);
if(fabs(x-lastx)<=eps||fabs(f(x))<eps)//逻辑或收敛判断
{erinfo =1; root=x; } //收敛成功返回信息1且纪录收敛后的根
i++; //循环控制次数步进
}
else erinfo =111; //切线刚度靠近零返回信息111
//**/} else erinfo = 222; //**///0向量解返回信息222
} while ( i < maxiterations && erinfo == 0); //两个逻辑与约束,终止循环
if( i == maxiterations) erinfo = 333; //超过最大迭代次数返回信息333
return erinfo;
} //程序尽量在else分支下处理异常
real funct(real x) { return ((x-2.0)*x-4.0)*x-7.0; }
real dfunct(real x) { return (3.0*x-4.0)*x-4.0; }
void main(void)
{ real root;
switch(newtonroot(funct,dfunct,4,root))
{ case 111: printf("df/dx is near zero\n"); break;
//**/case 222: printf("root may be near zero\n"); break;
case 333: printf("iteration number passed max\n"); break;
case 1: printf("funct(%f)=%19.17e\n",root,funct(root));break;
}
} //输出:funct(3.631981)=2.66453525910037570e-015
//[例9.5]指针与重载函数,函数指针根据重载函数名的入口类型匹配
#include<stdio.h>
double& max(double& x,double& y){printf("&"); return x>y?x:y; }//引用版本求极大值
double* max(double* x,double* y){printf("*"); return *x>*y?x:y; }//指针版本求极大值
double* (*pmax)(double* ,double*) =max; //pmax获得指针版本的max地址
double& (*rmax)(double&,double& )=max; // rmax获得引用版本的max地址
void main(void)
{ const char* fmt="max(x=%2.0f,y=%2.0f)=%2.0f;";
double x=10, y=10;
rmax(x,y)+=10; // rmax(x,y)等价于(*rmax)(x,y)
printf(fmt,x,y,(*rmax)(x,y));
*pmax(&x,&y)+=10; //*pmax(&x,&y)等价于*(*pmax)(&x,&y)
printf(fmt,x,y,*(*pmax)(&x,&y));
typedef double* (*PFD)(double* ,double*); //声明函数指针别名PFD
rmax=(double&(*)(double&,double&))(PFD)max;//取重载函数地址并类型转换
*(( PFD)rmax)(&x,&y)+=10; //调用时函数指针予以复原
printf(fmt,x,y,*(*(( PFD)rmax))(&x,&y));
} //输出:&&max(x=10,y=20)=20; **max(x=10,y=30)=30;**max(x=10,y=40)=40
//[例9.6]返回函数指针的函数,工程文件分为两个源程序a.cpp和b.cpp
#include<stdio.h>// main程序在a.cpp源文件中
typedef void (*VFV)(void);
typedef void (*VFI)(int);
extern inline VFV GetFunct(int); //不能写成extern void (*)(void) GetFunct(int);
VFV pfm[]={GetFunct(3),GetFunct(2),GetFunct(1)};//定义全局函数指针数组并初始化
void main()
{ VFV pfn=GetFunct(1);
pfn(); (*GetFunct(2))(); GetFunct(3)();
((VFI)pfm[0])(2); (*pfm[1])();pfm[2]();
} //输出: f1(); f2(); f3(); f3(); f2(); f1();
#include<stdio.h> //如下程序在b.cpp源文件中
static void f1(void) { printf("f1();\t"); }
static void f2(void) { printf("f2();\t"); }
static void f3(int) { printf("f3();\t"); }
typedef void (*VFV)(void); //内部连接属性的函数通过extern函数过渡到其它模块
extern inline VFV GetFunct(int m) //返回函数指针的函数GetFunct
{ if(m==1) return f1; //返回类型为 void (*)(void)
else if(m==2) return &f2;
else return (void (*)(void))&f3; //函数指针的强制类型转换
} // GetFunct返回静态函数的地址
// [例9.7] 多路分支模拟函数菜单驱动
#include<stdio.h>
void f1(long x) { printf("f1(%d);\t",x); }
void f2(long y) { printf("f2(%d);\n",y); }
void main(void)
{ void (*ppfn[2])(long) ; //定义函数指针数组ppfn[2]
ppfn[0]=&f1; ppfn[1]=&f2;
void (**pfp)(long)=ppfn;
(*pfp++)(3); (**pfp)(2);
printf("请输入一个整数:"); int k;
scanf("%d",&k); //程序运行结果如下:
switch(k) //f1(3); f2(2);
{ case 1: (*ppfn[0])(k); break; //请输入一个整数:1(
case 2: ppfn[1](k); break; // f1(1);
default :break;
}
}
// [例9.8] 循环实现函数的动态绑定
#include<stdio.h>
typedef void (*PPFUNC)(long);//函数指针类型别名声明语句
void f1(long x) { printf("f1(%d);\t",x); }
void f2(long y) { printf("f2(%d);\t",y); }
void main(void)
{ PPFUNC fn[]={&f1,f2}; //等价于void (*fn[])(long)={f1,f2};
int num_fn=sizeof(fn)/sizeof(fn[0]);
int k=0;
do //运行结果如下:
{ (*fn[k])(k); // f1(0);请输入一个整数:1(
printf("请输入一个整数:"); // f2(1);请输入一个整数:2(
scanf("%d",&k); /*程序退出循环*/
}while(0<=k && k< num_fn);
}
//[例9.9] 函数指针的指针形参和引用形参(多学时选讲)
#include<stdio.h>
typedef void (*VFI)(int);
void f(int x) { printf("f(%d);\t",x); }
void g(int x) { printf("g(%d);\n",x); }
void SetFunctB(void (**ppf)(int),int m) //函数指针的指针形参ppf
{ if(m==1) *ppf= f; //ppf匹配void (*)(int)型的函数指针的地址
else *ppf= &g; //*ppf是void (*)(int)型的函数指针
}
void SetFunctA(VFI& pf,int m) //函数指针的引用形参pf
{ if(m==1) pf= f; //形参pf匹配void (*)(int)型的左值函数指针
else pf= &g;
}
void main()
{ VFI fp,gp;
SetFunctA(fp,1); (*fp)(10);
SetFunctB(&gp,2); gp(20);
} //输出结果:f(10); g(20);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -