函数指针的概念,在潭浩强先生的C语言程序设计这本经典的教程中提及过,在大多数情况下我们使用不到,也忽略了它的存在。函数名实际上也是一种指针,指向函数的入口地址,但它又不同于普通的如int*、double*指针,看下面的例子来理解函数指针的概念:
第一行代码首先定义了一个函数function,其输入为两个整型数,返回也为一个整型数(输入参数和返回值可为其它任何数据类型);后面又定义了一个函数指针fun,与int*或double*定义指针不同的是,函数指针的定义必须同时指出输入参数,表明这是一个函数指针,并且*fun也必须用一对括号括起来;并将函数指针赋值为函数function,前提条件是*fun和function的输入参数和返回值必须保持一致,否则无法通过编译。可以直接调用函数function(),也可以直接调用函数指针,二者是等效的。
声明函数指针
回调函数是一个程序员不能显式调用的函数;通过将回调函数的地址传给调用者从而实现调用。要实现回调,必须首先定义函数指针。尽管定义的语法有点不可思议,但如果你熟悉函数声明的一般方法,便会发现函数指针的声明与函数声明非常类似。请看下面的例子:
void f(); // 函数原型
上面的语句声明了一个函数,没有输入参数并返回void。那么函数指针的声明方法如下:
void (*) ();
函数存放在内存的代码区域内,它们同样有地址,我们如何能获得函数的地址呢?
如果我们有一个int test(int a)的函数,那么,它的地址就是函数的名字,这一点如同数组一样,数组的名字就是数组的起始地址。
定义一个指向函数的指针用如下的形式,以上面的test()为例:
int (*fp)(int a); //这里就定义了一个指向函数的指针
函数指针绝对不能指向不同类型,或者是带不同形参的函数,在定义函数指针的时候我们很容易犯如下的错误。
int *fp(int a); //这里是错误的,因为按照结合性和优先级来看就是先和()结合,然后变成了一个返回整形指针的函数了,而不是函数指针,这一点尤其需要注意!
例如函数原型为:
int fun(int *, int);
则函数指针可以声明为: int (*pf)(int *, int);
当然从上述例子看不出函数指针的优点,目的主要是想引出函数指针数组的概念。我们从上面例子可以得知,既然函数名可以通过函数指针加以保存,那们也一定能定义一个数组保存若干个函数名,这就是函数指针数组。正确使用函数指针数组的前提条件是,这若干个需要通过函数指针数组保存的函数必须有相同的输入、输出值。
如果赋了不同的值给函数指针,那么调用者将调用不同地址的函数。赋值可以发生在运行时,这样使你能实现动态绑定。
下面我们来看一个具体的例子:
typedef定义可以简化函数指针的定义,在定义一个的时候感觉不出来,但定义多了就知道方便了,上面的代码改写成如下的形式:
分享到:
相关推荐
浅谈 C 语言指针结构 本文主要探讨 C 语言中的指针结构,讨论了一维指针、二维指针、指针数组与数组指针的概念和应用。指针是 C 语言中广泛使用的一种数据类型,函数是构成 C 语言程序的基本单位,在 C 语言中,将...
"浅谈C语言指针的应用" 本文主要探讨C语言指针的应用,特别是多维数组和指针之间的关系。指针是C语言中一个重要的概念,也是C语言的一个重要特色。正确而灵活地运用指针,可以有效地表示复杂的数据结构;能够动态...
主要介绍了浅谈在Swift中关于函数指针的实现,是作者根据C语言的指针特性在Swifft中做出的一个实验,需要的朋友可以参考下
C语言中函数形参为指针类型的参数传递详解 在C语言编程中,函数形参是函数定义中声明的变量,用于接收函数调用时传递的参数。在函数形参中,指针类型的参数传递是一种常见的参数传递方式。指针类型的参数传递可以将...
在实际应用中,强制类型转换函数可以用于解决许多问题,例如将基本数据类型转换为其他类型、将基类指针转换为子类指针、将void指针转换为目标类型的指针等。但是,需要注意的是,强制类型转换函数可能会带来一些风险...
有人对 STM32 固件库里的回调函数有些好奇甚至纠结,这里...一般来讲,所谓回调函数,泛指基于事件触发而被调用执行的函数,简单点说,就是条件满足了就调用的函数,往往会跟函数指针结合起来通过函数指针实现调用。
代码如下:#include...//指针p是首地址 f(p);//调用 printf(“%d”,*p);//p的值是不会改变的 } 结果:21Press any key to continue 代码如下:#include<stdio> void z(int *p){ p = p+1; *p = 100; } void mian(){
list_del函数将一个节点从链表中删除,并将其next和prev指针设置为NULL。 5. 链表的遍历 链表的遍历可以通过list_for_each宏来实现。list_for_each宏是一个foreach循环,用于遍历链表中的每个节点。 6. 链表的...
指针在编程中有时很重要的作用 我们可以用它完成一些看似不可能完成的任务 #include using namespace std; void square(int *n){ *n=*n**n; } int main(){ int num = 2; cout<<The original number is <&...
在传统的观念里,都认为JavaScript函数传递的是引用传递(也称之为指针传递),也有人认为是值传递和引用传递都具备。那么JS的参数传递到底是怎么回事呢?事实上以下的演示也完全可以用于Java 首先来一个比较简单的,...
"浅谈C语言编程能力的培养" C语言是一种广泛应用于操作系统、嵌入式系统、数据库和其他领域的编程语言。培养C语言编程能力是软件开发、计算机科学和信息技术等领域的必备技能。以下是浅谈C语言编程能力的培养的知识...
// describe: 非虚函数情况下,将子类指针赋给积累指针,验证最终调用 // 基类函数还是子类函数。 //============================================================== #ifndef ANIMAL_H #define ANIMAL_H //======...
通过基类指针做虚函数调 用时(也就是做多态调用时),编译器静态地插入取得这个V P T R,并在V TA B L E表中查找函数地址的代码,这样就能调用正确的函数使晚捆绑发生。为每个类设置V TA B L E、初始化V P T R、为...
它和传统的函数指针很类似,但是有区别:block是inline的,并且它对局部变量是只读的。 Block的定义: int (^myBlock) (int a,int b) = ^(int a,int b){ return a+b; }; 定义了一个名为myBlock的blocks对象...
Java JVM 调优浅谈 Java 虚拟机(JVM)是 Java 语言的核心组件之一,负责加载、验证、执行 Java 字节码。JVM 的调优对于 Java 程序的性能和稳定性至关重要。下面对 JVM 调优的相关知识点进行了详细的解释。 数据...
虚函数调用属于运行时多态,在类的继承关系中,通过父类指针来调用不同子类对象的同名方法,而产生不同的效果。 C++ 中的多态是通过晚绑定(对象构造时)来实现的。 用法 在函数之前声明关键字 virtual 表示这是一个...
不加括号的,都是把函数名称作为函数的指针,用于传参,此时不是得到函数的结果,因为不会运行函数体代码。它只是传递了函数体所在的地址位置,在需要的时候好找到函数体去执行。 所以一般时候我们都是采用的是无...
在实现多态时, 当用基类指针操作派生类, 在析构时候防止只析构基类而不析构派生类。 2、例子: (1)、 #include using namespace std; class Base{ public: Base() {}; ~Base() {cout <&...
但是这个对象还有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。 请看经典的阶乘函数例子: 代码如下: function Factorial(num) { if (num <= 1) { return 1; } else ...
以元祖形式返回 return (a,b,……) 以元祖引用或(x,y,….)接受都...以上这篇浅谈python函数调用返回两个或多个变量的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持软件开发网。