前言:笔者在学习数据结构经典问题“四种方法求解最大子列和”时,遇到了一个需求:计时是重复动作,因此想创建一个可以为算法运行时间计时的函数。由于计时的特殊性(被计时的函数要被掐头又掐尾),因此要设计一个能调用函数的函数。这就涉及到 回调函数 / 函数指针 的应用了(初学C/C++时,不了解回调函数提出的意义,现在因为自己的需求明白了)。

附:最大子列和问题的四种解法为:暴力法O(n3)、不做重复加法O(n2)、二分法O(n log2(n))、在线处理法O(n),详细解析请见笔者的笔记算法实例:最大子列和,实现代码于ds_cou_1_maxSum.cpp。

文章目录

  • 需求分析
  • 检索解决需求的方案(回调函数)
  • 回调函数
    • 指针可以指向数值,当然也可以指向函数(函数指针)
    • 回调函数就是把函数指针放在参数表中的函数
  • 参考资料

需求分析

#include <time.h>
#include <stdio.h>#define MAXK 1e5
clock_t start, stop;
double duration;start = clock();
for (int i = 0; i < MAXK; i++)
{foo(10, 1.1);
}
stop = clock();
duration = ((double)(stop - start) / CLK_TCK / MAXK);
printf("ticks2 = %f\n", (double)(stop - start));
printf("duration2 = %6.2e\n", duration);

如上图,foo()为被计时函数,start与stop需要分别在foo()调用前后取值。现在要将计时功能封装,则其设计概念如下。

double timeCal(function())
{clock_t start, stop;double duration;start = clock();for (int i = 0; i < MAXK; i++){function();  // 这个function需要能传入}stop = clock();duration = ((double)(stop - start) / CLK_TCK / MAXK);return duration;
}

检索解决需求的方案(回调函数)

搜索:C中,如何将函数作为参数在另一个参数中调用?

方案:使用回调函数。

“回调函数…这个名词好像在大一下的课上听过”,先不管那么多了…开始学习回调函数的使用,实现我的需求。

回调函数

指针可以指向数值,当然也可以指向函数(函数指针)

理解回调函数,首先要了解函数指针这个概念。

我们知道,数据是存储在计算机内存上的,计算机要使用这个数据时,要找到这个数据在内存上的位置,就是地址。

而指针,就是指向地址的变量。 如下图蓝线所示。

数据存在内存上,那函数存在哪里呢?

答:函数也存在内存上呗!函数说白了,就是一堆指令,也是一串01组成的数据。

那自然,也要有指针,用来指向函数的地址,就是函数指针。 如下图。

在c中,我们用星号(*)声明指针,自然,函数指针也是用星号声明的。例子如下。

int a = 1;              // 声明整数变量// (为变量a申请一块内容空间,并赋值)
int foo() { return 0; } // 声明函数int  *p_int = &a;       // p_int 是指针,值为a的地址
int (*p_func)() = foo;     // p_func 是指针,指向foo()函数

回调函数就是把函数指针放在参数表中的函数

理解了函数指针,就不难理解回调函数了:把函数指针放在参数表中的函数。

则,我们的计时函数可以写成:

double timeCal(int (*MaxSubseqSum)(int *, int), int A[], int N)
{clock_t start, stop;double duration;start = clock();for (int i = 0; i < MAXK; i++){MaxSubseqSum(A, N);}stop = clock();duration = ((double)(stop - start) / CLK_TCK / MAXK);return duration;
}

可以在main中如下调用:

int main()
{int a[15] = {-1, 4, -1, -3, 5, 1, -6, 3, 3, 5, -21, 1, -3, 6, -2};int N = 15;double duration[4];duration[0] = timeCal(MaxSubseqSum1, a, N);duration[1] = timeCal(MaxSubseqSum2, a, N);duration[2] = timeCal(MaxSubseqSum3, a, N);duration[3] = timeCal(MaxSubseqSum4, a, N);for (int i = 0; i < 4; i++)printf("duration_%d = %6.2e \n", i + 1, duration[i]);return 0;/*duration_1 = 1.46e-006duration_2 = 2.80e-007duration_3 = 2.70e-007duration_4 = 3.00e-008数据规模小,分而治之的方法与不做重复加法的方法相比,优势不明显。*/
}

其中,*MaxSubseqSum代表一个函数指针,而MaxSubseqSum()这一系列的函数要使用两个参数(一个整型数组 / 也可以是数组首个元素的地址、一个整型变量),因此我们要在回调函数中传入他们。

如上图,*MaxSubseqSum就好像一个…固定了形状的零件?根据main()指令,只要是符合【返回值类型为int,传入参数为int[]与int】这标准形状的,*MaxSubseqSum就可以变成它,并去调用,实现其功能。

参考资料

[1] 这个世界根本没有什么面向对象!
[2] C 函数指针与回调函数 | 菜鸟教程
[3] 函数指针与回调函数
[4] C语言:值传递,地址传递和引用传递(example:值交换)

【C/C++】一个实例看 回调函数 / 函数指针 应用与原理相关推荐

  1. 【FlexSim2019】自学笔记:一个实例看何为A连接?何为S连接?其意义的深入探讨

    A.S连接是仿真软件FlexSim 2019中常用的两种连接.那么,二者有什么区别?笔者在这篇文章里以实例,进行了讨论.了解二者意义,才能以不变应万变,具备独立处理问题的能力. 了解连接之前,先看看什 ...

  2. 查询优化器内核剖析第四篇:从一个实例看执行计划

    查询优化器内核剖析第四篇:从一个实例看执行计划 系列文章索引: 查询优化器内核剖析第一篇 查询优化器内核剖析第二篇:产生候选执行计划&执行计划成本估算 查询优化器内核剖析第三篇:查询的执行与计 ...

  3. 从一个实例看编程水平的步步提高

    很久很久前就想写这个话题的文章了,但是,总是找不到合适的例子.例子简单不足于说明问题,例子复杂可读性就会降低,就会达不到文章的目的.两难总让人激发解决问题的斗志,于是乎自己试着写写这个例子吧.这个例子 ...

  4. 从一个实例看jaxb的强大

    http://zyl.iteye.com/blog/33729 读取xml对于应用软件来说是一个必不可少的工作,当然现在的jdk也提供了很好的处理xml方式,读写xml的库也挺多,包括有名的dom4j ...

  5. 从一个实例看javascript几种常用格式的转换

    要对如图一所示的左侧table的数据按照"总量"进行排序 1,在前端实现 2,数据格式为object,如图二 原创文章,转载请注明:http://www.cnblogs.com/p ...

  6. 定义一个Dog类,包括体重和年龄两个数据成员及其成员函数,声明一个实例dog1,体重5,年龄10,使用I/O流把dog1的状态写入磁盘文件。再声明一个实例dog2,读取文件dog1的状态给dog2。

    定义一个Dog类,包括体重和年龄两个数据成员及其成员函数,声明一个实例dog1,体重5,年龄10,使用I/O流把dog1的状态写入磁盘文件.再声明一个实例dog2,通过读取文件dog1的状态赋给dog ...

  7. python描述符(descriptor)、属性(property)、函数(类)装饰器(decorator )原理实例详解

    2019独角兽企业重金招聘Python工程师标准>>> 1.前言 Python的描述符是接触到Python核心编程中一个比较难以理解的内容,自己在学习的过程中也遇到过很多的疑惑,通过 ...

  8. android JNI层线程回调Java函数

    今天,简单讲讲android的jni如何使用jni回调java函数. 之前,我写了部分jni的博客,讲的都是如何从android的java代码调用jni的函数.最近,需要做一个新的功能,在jni的C函 ...

  9. Python 3.X 调用多线程C模块,并在C模块中回调python函数的示例

    由于最近在做一个C++面向Python的API封装项目,因此需要用到C扩展Python的相关知识.在此进行简要的总结. 此篇示例分为三部分.第一部分展示了如何用C在Windows中进行多线程编程:第二 ...

最新文章

  1. 面试官问你MyBatis SQL是如何执行的?把这篇文章甩给他
  2. 圆的半径java_css中的圆形边界半径工件
  3. 三大运营商回复 4G 降速;微信上线语音转文字功能;IntelliJ IDEA 2019.2.1 发布 | 极客头条...
  4. python哈姆雷特英文词频统计_MOOC《Python语言程序设计》第6周练习题
  5. 分类器对未见过类别的识别问题
  6. python就业方向-学完Python的7大就业方向,哪个赚钱多?
  7. 【概率论与数理统计】1.4 条件概率
  8. c语言键盘符号大全,求c语言各种符号 并且意义。。在键盘上没有的 如何打?...
  9. 不想重置路由器,如何由已连接设备快速获取wifi密码?
  10. 2019第二届中国天津国际智慧消防高峰论坛
  11. 谷歌将发布全新搜索引擎,你期待吗?
  12. wkhtmltox 中文显示一半_免费!联合国官员孩子上的中文课,这次我get到了~
  13. hpm128无法共享打印_HP M128fn打印机共享后无法打印
  14. 141.如何个性化推荐系统设计-1
  15. 【毕业设计_课程设计】汉语多音字注音研究
  16. android自动添加包,android nfc写入应用程序包名与网址 自动打开应用程序与网址...
  17. 利息计算的方式及实现
  18. flutter应用启动页面-防白屏
  19. SPI Flash数据移位
  20. 商城项目解析(如果通过输入商品分类显示商品规格参数,在用户输入完商品信息后,又如何把对应的数据Spu,Sku,库存Stock,创建时间,最后一次更新时间等输入到数据库当中)

热门文章

  1. 域 禁用计算机,域成员 在 Windows 10 (禁用计算机帐户) - Windows security | Microsoft Docs...
  2. 移动端点击出现阴影 css解决方案
  3. Ubuntu 16.04下用Wine运行的软件出现方块的解决思路(应该是兼容现在所有平台的Wine碰到这个的问题)
  4. 解决nuxt.js新建项目报错的问题
  5. PLSQL无法连接64位Oracle数据库/Database下拉框为空的解决方法
  6. 关于跨域获取cookie问题的解决
  7. 大O,您如何计算/近似?
  8. 在Chrome中禁用同一来源政策
  9. win11白屏死机怎么办 Windows11白屏死机的解决方法
  10. Win11推送如何操作 Windows11推送的详细步骤方法