C/C++ 函数指针 总结
什么是函数指针
就像某一变量的地址可以存储在相应的指针变量中一样,指向函数的指针中保存着函数代码起始处的地址
函数指针的声明
当声明一个函数指针时,必须声明它指向的函数类型。要指定函数类型,就要指出函数的返回类型和参数列表,如:
void (* pf)(int, int); //pf是一个函数指针,它指向的函数类型为:返回值为void,参数列表为(int, int)
函数指针的赋值
函数名本身即代表函数的地址,因此给函数赋值时可以不加&符号,如:
void func(char *);
void (* pf)(char *);
pf = func; //可以
pf = &func; //可以
函数指针的使用
一般来说,函数指针有以下两个用处:
调用函数
此时函数指针可看作函数的别名,如下面三条语句等价:
func("abc");
pf("abc"); //可以
(* pf)("abc"); //可以
将函数作为其他函数的参数
这是函数指针最普遍的用法,如:
void show(void (* pf)(char *), char * str); //第一个参数为函数指针
注意:函数指针实参可以指向不同函数,但这些函数类型(返回类型和参数列表)必须一样
使用函数指针作为函数参数的典型例子有库函数qsort( )
在C++类中使用函数指针
typedef 返回类型(类名::*新类型)(参数表)
class CA
{
public:
char lcFun(int a){ return; }
};
CA ca;
typedef char (CA::*PTRFUN)(int);
PTRFUN pFun;
int main()
{
pFun = CA::lcFun;
ca.(*pFun)(2);
}
在这里,指针的定义与使用都加上了“类限制”或“对象”,用来指明指针指向的函数是那个类的这里的类对象也可以是使用new得到的。比如:
CA *pca = new CA;
pca->(*pFun)(2);
delete pca;
而且这个类对象指针可以是类内部成员变量,你甚至可以使用this指针。比如:
类CA有成员变量PTRFUN m_pfun;
void CA::lcFun2()
{
(this->*m_pFun)(2);
}
一句话,使用类成员函数指针必须有“->*”或“.*”的调用。
函数指针的应用
标准模板库中的sort排序
template<class RandomAccessIterator, class Predicate>
void sort(RandomAccessIterator first, RandomAccessIterator last, Predicate comp);
sort允许使用自己定义的比较函数(第三个参数)
// 比较分数
bool compareScore(const FightAttr& a, const FightAttr& b)
{
return a.score< b.score;
}
用指向函数的指针作函数参数
在C语言中,函数指针变量常见的用途之一是作为函数的参数,将函数名传给其他函数的形参。这样就可以在调用一个函数的过程中根据给定的不同实参调用不同的函数。
例如,利用这种方法可以编写一个求定积分的通用函数,用它分别求5个函数的定积分:每次需要求定积分的函数是不一样的。可以编写一个求定积分的通用函数integral,它有3个形参:
下限a上限b,以及指向函数的指针变量fun函数原型可写为
double integral (double a,double b,double (*fun)(double));
分别编写5个函数f1,f2,f3,f4,f5, 用来求上面5个函数的值。然后先后调用integral函数5次,每次调用时把a,b以及f1,f2,f3,f4,f5之一作为实参,即把上限、下限以及有关函数的入口地址传送给形参fun,在执行integral函数过程中求出各函数定积分的值。
函数指针与指针函数的区别
1、函数指针
函数指针其实就是指向一个函数地址的指针,我们知道数值和函数一样都有自己的存在空间,也都有程序的首地址,数组名表示着整个数组代码占用内存的首地址,同理函数名也就是整个函数代码占用内存的首地址,函数指针就是指向函数占用内存的首地址,其定义格式如下:
type (*name)(参数列表);//函数返回值 (*函数指针)(参数列表)
例如我们可以定义一个函数返回值为int型的,参数列表为(int x)的函数,然后定义一个函数指针来指向他。
int func(int x);//定义函数
int (*f)(int x);//定义函数指针
f=func;//这样函数指针*f就指向函数func了
需要注意的是:函数指针的返回值和参数列表要和指向的函数的必须完全一样,这样才可以对其进行赋值。
2、指针函数
一个函数不仅可以带回一个整型数据的值,字符类型值和实型类型的值,还可以带回指针类型的数据,使其指向某个地址单元。
返回指针的函数,一般定义格式为:
类型标识符 *函数名(参数表)
int *f(x,y);
其中x,y是形式参数,f是函数名,调用后返回一个指向整型数据的地址指针。f(x,y)是函数,其值是指针。
如:char *ch();表示的就是一个返回字符型指针的函数。
函数指针与typedef
1、定义函数指针类型
// 定义一个原型为int Fun( int a );的函数指针
typedef int (*PTRFUN) ( int aPara );
2、函数指针变量的定义
PTRFUN pFun; // pFun 为函数指针变量名
int (*pFun2) ( int a ); // pFun2也是函数指针变量名
函数指针与动态绑定
// 获得函数指针的大小
unsigned psize = sizeof (void (*) ());
// 为函数指针声明类型定义
typedef void (*pfv) ();
pfv是一个函数指针,它指向的函数没有输入参数,返回类行为void。使用这个类型定义名可以隐藏复杂的函数指针语法。
指针变量应该有一个变量名:
void (*p) (); //p是指向某函数的指针
p是指向某函数的指针,该函数无输入参数,返回值的类型为void。左边圆括弧里星号后的就是指针变量名。有了指针变量便可以赋值,值的内容是署名匹配的函数名和返回类型。例如:
void func()
{
/* do something */
}
p = func;
p的赋值可以不同,但一定要是函数的地址,并且署名和返回类型相同。
传递回调函数的地址给调用者
现在可以将p传递给另一个函数(调用者)- caller(),它将调用p指向的函数,而此函数名是未知的:
void caller(void(*ptr)())
{
ptr(); /* 调用ptr指向的函数 */
}
void func();
int main()
{
p = func;
caller(p); /* 传递函数地址到调用者 */
}
如果赋了不同的值给p(不同函数地址),那么调用者将调用不同地址的函数。赋值可以发生在运行时,这样使你能实现动态绑定。
其他
1.总之,函数指针赋值时,&可加可不加;函数指针取值时(即作为函数别名进行调用时),*可加可不加
2.要注意带有返回值的函数,如:
func1(sqrt); //将函数地址作为参数传递
func2(sqrt(4.0)); //将函数返回值作为参数传递
区别在于函数名后跟不跟参数列表
example:
void sort(int a[], int n); //sort函数
void (*p)(int a[], int n) = NULL; //p就是指向void (int a[], int n)类型的函数指针
p = sort; //函数名就是函数地址
int arry[3] = {1, 2, 3};
sort(arry, 3);
p(arry, 3); //可以直接调用
C/C++ 函数指针 总结的更多相关文章
- C++虚函数和函数指针一起使用
C++虚函数和函数指针一起使用,写起来有点麻烦. 下面贴出一份示例代码,可作参考.(需要支持C++11编译) #include <stdio.h> #include <list> ...
- 为什么 C++ 中成员函数指针是 16 字节?
当我们讨论指针时,通常假设它是一种可以用 void * 指针来表示的东西,在 x86_64 平台下是 8 个字节大小.例如,下面是来自 维基百科中关于 x86_64 的文章 的摘录: Pushes a ...
- C++函数指针总结
学习c++的过程中,指针是难点,熟悉了指针之后,还有一个让人很蛋疼的难点,那就是函数指针了.本博文详细介绍一下常见的各种坑爹的函数指针. 至于指针的详细学习,推荐这篇博文C++指针详解 与数据一样,函 ...
- C与指针(结构体指针,函数指针,数组指针,指针数组)定义与使用
类型 普通指针 指针数组(非指针类型) 数组指针 结构体指针 函数指针 二重指针 定义方式 int *p; int *p[5]; int (*p)[5]; int a[3][5]; struct{.. ...
- 结构体内嵌函数指针实现C语言面向对象
结构体内嵌函数指针 #include<stdio.h> void say(int age) { printf("我%d岁了\n",age); } struct stud ...
- 用typedef定义函数指针的问题
在学习windows API的时候,遇到下面这段代码 以前见过的typedef的用法都是给一个数据类型取一个别名 typedef oldTypeName newTypeName 这种给数据类型 ...
- 你必须知道的指针基础-7.void指针与函数指针
一.不能动的“地址”—void指针 1.1 void指针初探 void *表示一个“不知道类型”的指针,也就不知道从这个指针地址开始多少字节为一个数据.和用int表示指针异曲同工,只是更明确是“指针” ...
- objective-c中的@selector()和 c /c++的函数指针
先看tomcat里用到的代码: //然后开始动画 //把图片放到animationImages,接受数组参数 self.tom.animationImages = arrayImage; //设置时间 ...
- C++基础——函数指针 函数指针数组
==================================声明================================== 本文版权归作者所有. 本文原创,转载必须在正文中显要地注明 ...
- QT中使用函数指针
想仿命令行,所以定义了一个类,让一个String 对应一个 function,将两者输入list容器. 类中定义了 QString commandStr; void (MainWindow::*com ...
随机推荐
- Jquery获取radio单选按钮的value与后面的文字
一组单选按钮如图: <input name="classId" value="8afa94f45ba3e2c1015ba3fac6c00000" type ...
- No.18 selenium学习之路之批量执行测试用例
diascover方法,加载所有测试用例 1.discover方法里面有三个参数: -case_dir:测试用例的目录 -pattern:这个是匹配脚本名称的规则,test*.py意思是匹配test开 ...
- 2018JAVA复习摘要
由于公司内部原因,2018年感觉自己可能会换个新环境:虽然时间尚未确定,但还是得提前做好防范,毕竟面试复习是需要时间好好准备才能拿到自己理想的offer.打算从清明节之后开始好复习基本知识要点,先整理 ...
- MICROSOFT SQLSERVER 总结
--语 句 功 能--数据操作Select --从数据库表中检索数据行和列Insert --向数据库表添加新数据行Delete --从数据库表中删除数据行Update --更新数据库表中的数据--数据 ...
- 关于URL编码(针对URL含有中文的参数)
http://www.ruanyifeng.com/blog/2010/02/url_encoding.html 一.问题的由来 URL就是网址,只要上网,就一定会用到. 一般来说,URL只能使用英文 ...
- Asp.net Vnext 实现IView
概述 Iview定义很简单,就是根据View上下文和TextWriter对象实现对View的呈现. 实现 实现IViewEngine public class TestViewEngine : IVi ...
- day5模块学习--shutil模块
shutil模块 高级的 文件.文件夹.压缩包 处理模块 os模块提供了对目录或者文件的新建/删除/查看文件属性,还提供了对文件以及目录的路径操作.比如说:绝对路径,父目录…… 但是,os文件的操作 ...
- 关键字final和override
final关键字 限制某个类或结构体不能被继承 直接对类声明: class A final{}; class B : public A {}; 或这类内有final函数,类可以被继承,但是final函 ...
- Numpy的简单用法
Numpy的简单用法 import numpy as np 一.创建ndarray对象 列表转换成ndarray: >>> a = [1,2,3,4,5] >>> ...
- ffmpeg 添加filter步骤
a). 自己写一个XXX.c文件,比如vf_transform.c,放在libavfilter目录下.代码可以参考其他filter: b) 在libavfilter/allfilters.c添加一行: ...