Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4843086
  • 博文数量: 930
  • 博客积分: 12070
  • 博客等级: 上将
  • 技术积分: 11448
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-15 16:57
文章分类

全部博文(930)

文章存档

2011年(60)

2010年(220)

2009年(371)

2008年(279)

分类: C/C++

2008-11-14 19:38:07

    在进行数值算法的程序设计时,往往需要实现程序的通用性,即同一个程序可以对不同的问题进行求解,如:计算函数f(x)的数值积分的程序,我们需要写一个 通用的数值积分程序——Integr(),使其可以对不同的f(x)函数均可以进行积分计算,而不需要每计算一个函数的积分就重新写一个Integr() 程序,仅需要另写一个f(x)的表达式程序即可。

    若使用Matlab实现,则显然少不了eval(),和feval()函数的使用,即把需要进行积分计算的函数f(x)写完之后保存为.m文件,然后在积分程序中只需要把f(x)的文件名作为参数传递给Integr()即可。

    若是把f(x)函数名作为字符串传入,则在Integr()中只需将f(x)函数名及其参数写为一个字符串,使用eval(字符串)执行即可,如:

function result=integr(a,b,n,fun)
%定义积分函数,a为积分下限,b为积分上限,n为划分区间的个数,fun为需进行计算

%的函数的文件名
h=(b-a)/n;
x=[a:h:b];
y=eval([fun,'(x)']);
%将函数名fun和其参数x合成一个字符串并执行字符串,即执行计算fun(x)

%注意不能丢了fun的括号。
result=sum(y);

定义需要积分计算的函数fun之后,直接作为integr()的参数引用即可,如任意定义函数如下:

function r=ff(x)
r=sin(x).*(1+x.*x);

则,在命令窗口引用即可:将'ff'换为其他函数名字符串即可进行计算其数值积分。

integr(0,1,1000,'ff')

使用feval()函数则更加方便,integr()函数如下定义:

function result=integr(a,b,n,fun)
h=(b-a)/n;
x=[a:h:b];
y=fun(x
);%fun为传入的函数指针,可以直接作为引用
result=sum(y);

则可以通过如下方式使用:

integr(0,1,1000,@ff)%‘@’即表示ff作为函数指针传入

    Matlab为通过命令解释方式执行程序,而不需要对源程序进行编译,因此可以将函数名作为一个字符串参数传入,然后执行时将字符串解释为函数命令即可。 而其他语言,如C语言则必须首先进行编译,得到可执行文件后再使用,因此在C语言中无法采用将函数名作为字符串的形式作为字符参数传入。因此便想到了C语 言的函数指针,当时在初学C语言时对函数指针并没有重视,现在重新回顾函数指针,发现通过它便可解决数值计算程序的通用性的问题。仍然以数值积分为例:

    integr()函数的定义如下:(为了方便直接保存为integr.h)

#include <stdio.h>
#include <stdlib.h>
#include "math.h"
double integr(double a,double b,int n,double (*f)(double));
double integr(double a,double b,int n,double (*f)(double))
{
   int i;
   double y=0,h,x;
    h=(b-a)/n;
    x=a;
   for(i=0;i<=n;i++)
   {
      y+=(*f)(x);/*****此处对函数指针f的引用方式比较灵活,可以使用如上:y=(*f)(x)的方式,也可以直接使用指针名引用,即:y=f(x)   ******/
      x+=h;
   }
    y*=h;
   return y;
}

任意定义一被积函数ff如下:(为了方面被主函数包含,保存为ff.h)

#include <stdio.h>
#include <math.h>
double ff(double x);
double ff(double x)
{
  return 2*x*(1+x-x*x);
}

    由于C语言不能通过命令解释方式执行,必须编译为可执行文件,因此需具有主函数,这里定义一个可接受参数的main()函数,如下:

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "integr.h"
#include "ff.h"
int main(int argc,char *argv[])/***由argv[]接受积分参数****/
{
    int n;
    double a,b;
    if(argc!=4)/****由外部传入3个参数,加上程序名argv[0]共四个,否则提示出错***/
    {
        printf("parameters error!!\n");
        return 0;
    }         /***argv[0]为所运行的程序的文件名****/
     a=atof(argv[1]);/**将第二个参数argv[1]转化为积分下限a**/
     b=atof(argv[2])
;/**将第三个参数argv[2]转化为积分上限b**/
     n=atoi(argv[3]);/**将第四个参数argv[3]转化为积分区间个数n**/
    printf("result=%f\n",integr(a,b,n,ff));
/**此处对ff可以直接引用其函数名ff,也可以先定义一个函数指针变量在对函数指针变量进行赋值和引用***/
}

编译测试,命令行运行main()函数,如下:

./main 0 1 1000

   由于函数名本身就是函数的首地址,所以函数名与函数指针本质上是等效的,函数名是一个指针常量,而自定义的函数指针是一个指针变量,所以函数名和函数指针的赋值与引用方式比较灵活。如:
定义函数指针:    

double (*fun)(double); /**fun为一个指向带有一个double型参数,返回值为double型的函数的指针**/

为指针赋值:  

fun=&ff;/**将ff的地址值赋给fun,这种赋值方式与直接用:fun=ff; 是等价的**/

引用指针:    

y=(*fun)(x);/**这种引用方式与 y=fun(x);也是等价的**/

我们一般对函数的引用都采用类似数学函数的方式,如求-5的绝对值,即: 也可以使用:     熟悉了函数名作为参数传递的方式,便可以把一些数值算法写为通用程序了,在C语言中算法程序是通用的,如上述integr(),但主程序(main()函数)仍然需要每次重新改写,main()函数一般仅有几句赋值与引用的代码即可,并不麻烦。

y=abs(-5);

y=(*abs)(-5);

的方式,两种方式等价,但显然前一种方式更方便一些。
(以上C程序为在Linux系统gcc/g++编译环境下测试) 
阅读(1541) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~