http://book.51cto.com/art/200908/146363.htm

5.1.2 指向函数的指针

C语言通过&和*操作符来操作数据的地址,但它并没有提供一个用一般的方式来操作代码的地址。然而,C语言并没有完全切断程序员操作代码地址的可能,它提供了一些"受限制的"方式来操作代码的地址。之所以说这些方式是"受限制的",那是因为这些方式并不像操作数据地址那样自由和灵活。

在C语言中,指针变量也可以指向一个函数。我们已经知道代码也是有地址的,一个函数在编译时会被分配给一个入口地址,这个入口地址就是该函数中第一条指令的地址,这就是该函数的指针。当调用一个函数时除了通过函数名来调用以外,还可以通过指向该函数的指针变量来调用。一个指向函数的指针其初始值不能为空,因为它在使用之前必须被赋予一个真实的函数地址。指向函数的指针变量的一般定义形式如下(其中的函数类型是指函数返回值的类型):

  1. 函数类型 (*指针变量名) ();

请看下面这段示例代码,它使用普通的函数名方式来实现函数的调用,此函数用于实现矩形法求解

函数定积分的功能。

  1. #include "stdio.h"
  2. #include "math.h"
  3. //intergal(x^2)
  4. double func1(double a , double b)
  5. {
  6. double sum = 0.0;
  7. double length = 0.000001;
  8. double x = a;
  9. while(x < b)
  10. {
  11. sum += x*x*0.000001;
  12. x+=0.000001;
  13. }
  14. return sum;
  15. }
  16. void main()
  17. {
  18. double result = 0.0;
  19. result = func1(0.0, 1.0);
  20. printf("%g\n", result);
  21. }

现在我们改写上面的代码,使用一个指向函数的指针变量来调用函数。

  1. #include "stdio.h"
  2. #include "math.h"
  3. //intergal(x^2)
  4. double func1(double a , double b)
  5. {
  6. double sum = 0.0;
  7. double length = 0.000001;
  8. double x = a;
  9. while(x < b)
  10. {
  11. sum += x*x*0.000001;
  12. x+=0.000001;
  13. }
  14. return sum;
  15. }
  16. void main()
  17. {
  18. double result = 0.0;
  19. double (*p)(double, double);
  20. p = func1;
  21. result = (*p)(0.0, 1.0);
  22. printf("%g\n", result);
  23. }

关于上面的代码,有如下几点需要说明。

①语句"double (*p)(double, double);"定义p是一个指向函数的指针变量,此函数的返回值类型为double型。特别地,double (*p) ()并非是指向某一固定函数的,它仅仅表示定义了这样一个类型的变量,在程序中可以将不同的函数地址赋给它,由此它所指向的函数就会随之变化。

②(*p)两侧的括号不能省略,这样的语法意味着p先与*结合,是一个指针变量;再与后面的括号()结合,表示此指针变量指向函数而非变量。如果将*p两侧的括号去掉,则变成double *p(),这样表示的意思是函数p()的返回值类型是一个指向double型变量的指针。本书前面也介绍过因为()的优先级高于*,所以p会先与()结合,由此就声明了一个函数而非指针。

③赋值语句"p = func1;"的意思是将函数func1的入口地址(即函数中首条指令的地址)赋给指针变量p。易见,在给函数指针变量赋值时,只需要给出函数名即可,并不需要给出参数,因此如果将上面的赋值语句改写成"p = func1(0.0, 1.0);"则是错误的!但是由于这里仅仅使用了函数名,而不带括号和参数,为了不让编译器将其与变量混淆,必须在使用之前进行声明,表明func1是函数名而非变量名,这样编译时它们才会被当作函数名来处理。

④在使用函数指针时,只需将(*p)替代函数名即可,但是需要在其后的括号里显式地添加实参,即使函数不传递任何参数,该括号也不可省略。

⑤数组名可以代表数组的起始地址(数组中首元素的地址),所以函数名也可以代表函数的入口地址(函数中的首条指令的地址)。但是对于指向函数的指针变量,它只能指向函数的入口处而无法指向函数中某一条具体的指令,因此对于p+n、p++等指针运算对于指向函数的指针是没有意义的。

⑥获得一个函数地址的方法与获得一个变量地址的方法一样,于是前面程序中的语句"p = func1;"也可以写作"p = &func1; "。但是,必须保证函数func1已经在某个地方被声明过了。

指向函数的指针可以获得函数的入口地址,但它并不能像操作数组一样获得函数中每一条指令的地址,这样的操作是相对受限的。但人们不禁要问,这种语法有什么用处呢?函数指针最常用的地方是作为参数传递给其他的函数。指向函数的指针也可以作为参数以实现函数地址的传递,也就是将函数名传递给形式参数。但是我们知道,在某个函数中调用另外一个函数仅仅需要在此函数中直接调用所需的函数就可以了,这是C语言所支持的非常基本的函数调用语法。如此看来,将函数指针作为参数来传递,然后在函数体中使用实在是多此一举、画蛇添足。然而,将函数指针作为参数来使用还是非常有用的,尤其当每次函数所调用的其他函数无法固定时,这就显得尤为重要了。假设有函数fun,在某次执行过程中需要调用函数func1,而下一次就需要调用函数func2,再下一次又可能调用func3。如果使用函数指针,则不必对函数fun进行修改,只需要让其每次调用函数时通过不同的函数名来作为形参传递即可。这种方法极大地增加了函数使用的灵活性,我们可以编写一个通用的函数来实现各种专用的功能,这是符合结构化程序设计思想的方法。

下面通过一个简单的示例程序来说明这种方法的应用。该例子编写了一个求定积分的通用函数,用它可以分别求得3个函数的定积分:。可见,每次需要求定积分的函数并不相同,但是我们可以使用一个通用的函数integral,并通过3个形式参数:上限 b、下限a和指向函数的指针变量fun来显示各自专用的定积分求解函数。其中,函数func1用于求解函数  的定积分,func2用于求解函数 的定积分,func3用于求解函数  的定积分。

  1. #include "stdio.h"
  2. #include "math.h"
  3. //intergal(x^2)
  4. double func1(double a , double b)
  5. {
  6. double sum = 0.0;
  7. double length = 0.000001;
  8. double x = a;
  9. while(x < b)
  10. {
  11. sum += x*x*0.000001;
  12. x+=0.000001;
  13. }
  14. return sum;
  15. }
  16. //intergal(sinx)
  17. double func2(double a , double b)
  18. {
  19. double sum = 0.0;
  20. double length = 0.000001;
  21. double x = a;
  22. while(x < b)
  23. {
  24. sum += sin(x)*0.000001;
  25. x+=0.000001;
  26. }
  27. return sum;
  28. }
  29. //intergal(e^(x^-2))
  30. double func3(double a , double b)
  31. {
  32. double sum = 0.0;
  33. double length = 0.000001;
  34. double x = a;
  35. while(x < b)
  36. {
  37. sum += exp(sqrt(x))*0.000001;
  38. x+=0.000001;
  39. }
  40. return sum;
  41. }
  42. void intergal(double a, double b, double (*fun)(double, double))
  43. {
  44. double result = 0.0;
  45. result = (*fun)(a, b);
  46. printf("%g\n", result);
  47. }
  48. void main()
  49. {
  50. printf("计算x^2在0~1上的定积分结果:");
  51. integral(0.0, 1.0, func1);
  52. printf("计算sinx在0~ 上的定积分结果:");
  53. integral(0.0, 3.141593, func2);
  54. printf("计算e^(x^-2)在0~1上的定积分结果:");
  55. integral(0.0, 1.0, func3);
  56. }

完成编码后,编译并运行程序。

转载于:https://www.cnblogs.com/davidwang456/p/3456963.html

指向函数的指针--转相关推荐

  1. 20返回指针的函数与指向函数的指针

    一.返回指针的函数 指针也是C语言中的一种数据类型,因此一个函数的返回值肯定可以是指针类型的. 返回指针的函数的一般形式为:类型名 * 函数名(参数列表) 比如下面这个函数,返回一个指向char类型变 ...

  2. C七:指向函数的指针 ------ 函数指针(function pointer)

    函数具有可赋值给指针的物理内存地址,一个函数的函数名就是一个指针,它指向函数的代码.一个函数的地址是该函数的进入点,也是调用函数的地址.函数的调用可以通过函数名,也可以通过指向函数的指针来调用.函数指 ...

  3. (转)函数指针,指针函数,指向函数的指针,返回指针的函数

    摘要: 在学习C语言时,一个比较容易混淆的概念就是函数指针.指针函数.返回值为指针的函数.本文将对这三个概念进行区分.指针函数就是返回值为指针的函数,两个本质上是同一事物,只是叫法不同.函数指针就是一 ...

  4. ios 调用c语言函数指针,第09天C语言(08):指向函数的指针的应用场景

    #pragma mark 指向函数的指针的应用场景 ###pragma mark 概念 ###pragma mark 代码 #include int sum(int v1,int v2) { retu ...

  5. 【C/C++学习】之七、指向函数的指针

    什么是指向函数的指针 函数指针是指向函数的指针变量,不是指向对象的指针!函数指针本身应该是"指针变量": "在C语言中,函数本身不是变量,但可以定义指向函数的指针,这种指 ...

  6. 指向函数的指针 - C语言

    欢迎访问我的新博客:http://www.milkcu.com/blog/ 原文地址:http://www.milkcu.com/blog/archives/1368947400.html 基本概念 ...

  7. C++老话题:用指向函数的指针作函数参数

    用指向函数的指针作函数参数 在C语言中,函数指针变量常见的用途之一是作为函数的参数,将函数名传给其他函数的形参.这样就可以在调用一个函数的过程中根据给定的不同实参调用不同的函数. 例如,利用这种方法可 ...

  8. 指向函数的指针数组(C++)

    我们能够创建一个指向函数的指针数组.为了选择一个函数,只需要使用数组的下标,然后间接引用这个指针.这种方式支持表格式驱动码的概念:可以根据状态变量去选择被执行函数,而不用条件语句或case语句.这种设 ...

  9. typedef 指向函数的指针

    对复杂变量建立一个类型别名的方法很简单,你只要在传统的变量声明表达式里用类型名替代变量名,然后把关键字typedef加在该语句的开头就行了. // 定义四个函数 int add(int, int); ...

最新文章

  1. B2B行业网站10种经营模式研究及组合方案
  2. uoj#268. 【清华集训2016】数据交互(动态dp+堆)
  3. python访问序列元素的编号用什么括起来_Python 序列通用操作介绍
  4. [POJ3253]Fence Repair
  5. python中configparser_python中confIgparser模块学习
  6. 使用Lambda表达式遍历Iterator迭代器
  7. mysql保存表出错1075_navicat出现错误1075怎么办
  8. Mycat快速入门(六): Mycat管理命令和监控
  9. ASME Y14.5 2018重要更新
  10. 记一次win7 配置Windows Update 失败,还原更改,无法进入系统
  11. NOIP模拟19/07/22
  12. JavaScript 事件委托
  13. HTML5CSS3基础:HTML的图片、音频、视频(3)
  14. QT起一个线程实时监测某个进程是否正常运行
  15. 2022年云南最新建筑八大员(市政)模拟考试题库及答案
  16. nodejs:underscore模块介绍
  17. 对一些内存名词术语的解释(bank ECC等)——转载
  18. rsa public key not find
  19. python+selenium+new——窗口——网页——切换窗口——切换frame——alert弹窗
  20. 【自动控制原理】燃烧卡路里_系统分析实例-笔记

热门文章

  1. linux安装oracle 操作系统内核参数 aio,Linux安装Oracle 11G过程(测试未写完)
  2. 转 Oracle 删除表,oracle 中删除表 drop delete truncate 的区别
  3. java c3p0 配置文件_【c3p0】 C3P0的三种配置方式以及基本配置项详解
  4. java语言修饰符$_Java语言中的修饰符
  5. mac mysql start 失败_mac mysql 启动出错,请教解决办法
  6. .net 连接mysql的字符串_asp.net连接数据库字符串
  7. 面向对象的一个实例 (银行管理系统)
  8. 图片本地化 php,php抓取远程图片本地化函数,很好用的.喜欢的拿去
  9. 社会阶层及由此引起的社会动力学现象
  10. Leetcode 62.不同路径 (每日一题 20210701)