1. 函数指针及其定义和用法,C语言函数指针详解

原文链接:http://c.biancheng.net/view/228.html

什么是函数指针

如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间, 这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作 函数指针变量,简称 函数指针。

那么这个指针变量怎么定义呢?

虽然同样是指向一个地址,但指向函数的指针变量同我们之前讲的指向变量的指针变量的定义方式是不同的。例如:

int(*p)(int, int);

这个语句就定义了一个指向函数的指针变量p

  • 首先,它是一个指针变量,所以要有一个*,即(*p)
  • 其次,前面的int 表示这个指针变量可以指向返回值类型为 int 型的函数;后面括号中的两个 int 表示这个指针变量可以指向有两个参数且都是 int 型的函数。
  • 所以合起来这个语句的意思就是:定义了一个指针变量pp可以指向返回值类型为int型,且有两个int型参数的函数。p 的类型为int(*)(int,int)

所以函数指针的定义方式为:

函数返回值类型 (* 指针变量名) (函数参数列表);

函数返回值类型表示该指针变量可以指向具有什么返回值类型的函数;
函数参数列表表示该指针变量可以指向具有什么参数列表的函数。这个参数列表中只需要写函数的参数类型即可。

我们看到,函数指针的定义就是将函数声明中的函数名改成(*指针变量名)

但是这里需要注意的是:(*指针变量名)两端的括号()不能省略,括号改变了运算符的优先级。如果省略了括号,就不是定义函数指针而是一个函数声明了,即声明了一个返回值类型为指针型的函数。

那么怎么判断一个指针变量是指向变量的指针变量还是指向函数的指针变量呢?

  • 首先看变量名前面有没有*,如果有*说明是指针变量;
  • 其次看变量名的后面有没有带有形参类型的圆括号(),如果有就是指向函数的指针变量,即函数指针,如果没有就是指向变量的指针变量。

最后需要注意的是,指向函数的指针变量没有++--运算。


如何用函数指针调用函数

给大家举一个例子:

int Func(int x);   /*声明一个函数*/
int (*p) (int x);  /*定义一个函数指针*/
p = Func;          /*将Func函数的首地址赋给指针变量p*/

赋值时函数 Func 不带括号,也不带参数。由于函数名 Func 代表函数的首地址,因此经过赋值以后,指针变量 p 就指向函数 Func() 代码的首地址了。


下面来写一个程序,看了这个程序你们就明白函数指针怎么使用了:

# include <stdio.h>
int Max(int, int);  //函数声明
int main(void)
{int(*p)(int, int);  //定义一个函数指针int a, b, c;p = Max;  //把函数Max赋给指针变量p, 使p指向Max函数printf("please enter a and b:");scanf("%d%d", &a, &b);c = (*p)(a, b);  //通过函数指针调用Max函数printf("a = %d\nb = %d\nmax = %d\n", a, b, c);return 0;
}int Max(int x, int y)  //定义Max函数
{int z;if (x > y){z = x;} else{z = y;}return z;
}

输出结果是:

please enter a and b:3 4<br>
a = 3<br>
b = 4<br>
max = 4<br>



2. 知乎问题:C++中函数指针有什么作用? 为什么不直接调用函数而要使用函数指针?

原文链接:https://www.zhihu.com/question/349498301

猫之公爵公之猫

12 人赞同了该回答

我觉得这个问题。。。可以去好好看看B站上有个讲设计模式的视频,讲的非常好。。。。

简单来讲,函数指针,和虚函数有着一样的用处(其实他们本质上也是一样的),都是为了一个作用:延时绑定(晚绑定)。

这也是一个语言中,框架和库的区别。。。

以前的C程序想用别人的东西,大部分都是库,是一堆代码的集合,所以你要用库,就是调用它的功能,然后返回。。。框架的出现改变了这种情况,比如MFC框架(或者windows sdk),它要修改一个窗口的颜色,但是框架并不知道你的窗口是什么类型,它只关心它要修改的数据。。。这个时候就需要函数指针的帮助了。(注意,这个重点就在于,框架是不知道类型的,因为它写框架代码的时候,你还没有写窗口代码),我给一个例子,这个例子多少有点不合适,因为C++通用做法肯定是虚函数了。。。但是这个方法本质上就是用函数指针模拟虚函数,只不过虚函数机制是编译器生成的。

框架代码:

#include <iostream>// 框架代码
typedef void(ChangeColorFun)(Window* pWindow, int color);struct Window {ChangeColorFun* ChangeFun;
};struct FrameWord {void SetWindow(Window* pWindow) {m_pWindow = pWindow;}void Run() {m_pWindow->ChangeFun(m_pWindow, 1000);}Window* m_pWindow = nullptr;
};

用户代码:

// 用户代码struct LinuxWindow : public Window {int m_LinuxColor = 0;
};struct MacWindow : public Window {int m_MacColor = 0;
};void ChangeLinuxColor(Window* pWindow, int color) {LinuxWindow* pLinuxWindow = (LinuxWindow*)pWindow;pLinuxWindow->m_LinuxColor = color;
}void ChangeMaxColor(Window* pWindow, int color) {MacWindow* pLinuxWindow = (MacWindow*)pWindow;pLinuxWindow->m_MacColor = color;
}int main() {FrameWord Frame;                        // 框架代码Window* pWindow = new LinuxWindow;     // 用户代码pWindow->ChangeFun = ChangeLinuxColor; // 用户代码Frame.SetWindow(pWindow);              // 框架代码Frame.Run();                           // 框架代码 delete pWindow;
}

注意看,框架代码是写框架的人之前就确定的,特别是在这个函数

void Run(){m_pWindow->ChangeFun(m_pWindow, 1000);
}

中,框架是完全不知道它拿到的是什么东西的,但是通过函数指针,框架并不需要确定这个对象是什么,这样就做到了晚绑定机制,函数指针在这里就是提供了一个接口,这个接口规定了框架作者要做什么,用户代码要做什么。

现代C++框架机制错综复杂,大部分人写代码的时候是既要写服务代码,又要写用户代码,这个时候区分出来他们的区别是非常重要的,按照用户代码的思路写框架代码,你的代码会很难复用;反之按照框架代码的思路去写用户代码,你的代码实现会过因为过于灵活复杂难用且功能可能很多用不到。

题主估计写框架代码少,所以才问这个问题的


补上b的设计模式的链接。。。

https://b23.tv/wrqjt5

【c++】23.【函数指针】定义? 为什么不直接调用函数而要使用函数指针?相关推荐

  1. html函数中怎么写超链接,如何调用html超链接中的函数

    好的,我已经在这里搜索了很多问题,并且我已经从中获得了我所能做到的,但它似乎仍然没有工作. (我是相当新的的JavaScript/jQuery的.)如何调用html超链接中的函数 var showPh ...

  2. 函数指针作为函数参数 定义、使用、调用简例

    //函数定义 char *info_1(int wp, char *ctx) {//功能实现,省略 } char *info_2(int wp, char *ctx) {//功能实现,省略 }//函数 ...

  3. 函数声明放在头文件中,函数的定义放在实现文件中,然后在主函数中调用

    1.文件的组织结构如下图: 2.Menu.h内容如下: #ifndef MENU_H #define MENU_H int add(int a,int b); int minus(int a, int ...

  4. 【二级指针--定义、初始化赋值、解引用;特殊指针--空指针、void类型的指针】(学习笔记12--指针下)

    目录 一.二级指针 指针的指针 二级指针的定义 二级指针的初始化与赋值 二级指针的解引用 二级指针与指针数组 main函数的参数 二.特殊指针 空指针 void类型的指针 新星计划第六篇博文,下面是上 ...

  5. c++语言程序中,要调用的函数必须在main()函数中定义,惠州学院C++考试复习题

    惠州学院C++复习题 一.选择题 1.C++的源文件的扩展名是_____C____. A.h B.obj C.cpp D.exe 2.下列选项能够作为C++变量名的是___C____. A.false ...

  6. 【C语言】七、函数(定义调用嵌套参数储存等)

    这里写目录标题 1 函数的定义与调用 1.1 函数的定义 1.1.1 函数的分类 1.1.2 函数的定义 1.2 函数的返回值与函数类型 1.3 对被调用函数的说明和函数原型 函数声明 1.4 函数的 ...

  7. 在python中、正确的函数定义格式为_Python函数的定义与实现

    1. 函数的介绍 函数是 实现具有特定功能的代码块 Python中预制了许多内置函数,也可以根据自己的需求创建自定义的函数 隐藏实现功能的细节 代码的复用 提高可读性,便与调试 def 函数名(形参1 ...

  8. Python中函数的定义和参数传递

    前言 什么是函数,为什么它又叫做函数? 一.函数的定义 以前在中学阶段我们就学习过函数,那时的函数的定义是给定一个数集A,假设其中的元素为x,对A中的元素x施加对应法则f,记作f(x),得到另一数集B ...

  9. 《Swift 权威指南》——第6章,第6.1节函数的定义和调用

    本节书摘来自异步社区<Swift 权威指南>一书中的第6章,第6.1节函数的定义和调用,作者 李宁,更多章节内容可以访问云栖社区"异步社区"公众号查看 第6章 丰富多彩 ...

  10. 7 类与对象,方法和函数的定义和使用,返回值,权限修饰符 public default protected private(重点)

    文章目录 1 面向对象 1 面向对象概述 2 类与对象 2.1 概述 2.2 Java中类的定义万物皆对象. 2.3Java中对象的定义和使用 3 方法和函数的定义和使用 3.1 什么是方法,函数 3 ...

最新文章

  1. oracle分区表执行计划分区合并,利用ORACLE分区技术提高管理和性能_PART2
  2. Python函数之初体验
  3. delphi 2010 调整图片的比例
  4. 【渝粤教育】国家开放大学2018年春季 0341-21T高级英语听力(2) 参考试题
  5. php如何实现购物时数量增减,1、vuex状态管理--购物车数量增减
  6. linux 多个定时器,timer: 一个Linux下的超级精简的多重定时器:可实现成千上万个定时任务,定时精度可达纳秒级别,且同一时间点可添加不同的任务!适用于云后台服务和嵌入式等各种环境。...
  7. oracle 区管理系统,oracle区管理和段空间管理详细介绍
  8. 吴恩达机器学习1——单变量线性回归、梯度下降
  9. 重复抽样与非重复抽样
  10. Leetcode 刷题笔记(二十六) ——动态规划篇之经典问题:打家劫舍
  11. 单片机TM4C123学习(一):GPIO模块的应用
  12. matlab-模拟退火算法
  13. 云南省湖泊河流ArcGIS地形图shp图层文件下载
  14. 一款比较简单的PDF解密工具注册码分析
  15. App下载的视频导进电脑中生成.mp4文件的方法
  16. 如何授权接入芝麻小客服系统?
  17. OpenNLP入门实验
  18. 卷积的拉普拉斯变换等于拉普拉斯变换的乘积
  19. 光敏电阻型号怎么命名和其主要参数
  20. 常见网络摄像机的端口及RTSP地址

热门文章

  1. 神奇的互换身体术--java的类型擦除
  2. spring容器加载完毕做一件事情(利用ContextRefreshedEvent事件)
  3. struts深入原理之RequestProcessor与xml
  4. Lesson 13.4 Dead ReLU Problem与学习率优化
  5. Python数据结构与算法(第四天)
  6. springboot高级——消息队列相关
  7. 从自我学习到深层网络
  8. 一个19岁美国少年眼中的各种社交应用
  9. 用gdb调试core dump文件
  10. IDEA 启动 Tomcat 乱码 解决办法