一,函数指针:即指向函数的指针
函数指针定义格式:函数返回数据类型 (*指针名)(传入数据的数据类型)
函数指针的类型是怎样的呢?去掉指针名就是类型,即:函数返回数据类型 (*)(传入数据的数据类型) 如上面这个函数指针的类型是 int(*)(int, int)
下面看两个代码:
1,(*(void (*)())0)()
首先void (*)()是一个函数指针,将0强制转化为函数指针的数据类型,之后前面的*对这个指针进行解引用,后面的括号是调用这个函数
2,void (*signal(int,void(*)(int)))(int)
首先要知道函数去掉函数名和传入参数就是函数返回类型
这个signal (int ,void(*)(int))是一个函数,其参数是int 和void(*)(int),原代码去掉这些是void (*)(int)说明这个函数的返回值是一个函数指针,参数是int 无返回值
综上:上面这个代码是一个函数,函数名是 signal,其参数是int 和void(*)int ,返回值void(*)int
解释:
signal是一个函数声明
signal有两个参数,一个是int,一个是函数指针,该函数指针指向的函数参数是int,返回类型是 void
signal函数的返回类型是一个函数指针,该函数指针指向的函数参数是int,返回值是void
这样看着是不是很复杂,还记得我们学过typedef对数据类型进行重新定义吗?
下面进行从新定义:
以往:typedef unsigned int unit :将unsigned int定义成 unit
但是对于函数指针的重命名有所不同
typedef void(*)(int) pfunt 这种重定义不对
正确的应该是:typedef void(* pfunt)(int) ,将void(*)(int)定义为pfunt
这样上面的复杂形式就可以写成:pfunt signal (int,pfunt)
函数指针的调用:
上面这几个都可以调用函数指针p指向的函数,*有无和多少并无关系,可以不解引用直接使用
但是这里建议使用前两种,避免产生误解。
二,函数指针数组
是一个数组,存放的是函数指针
创建:函数返回类型 (*数组名 [数组元素个数])(传入参数类型)
注意,这些指针类型要相同,即都是:函数返回类型 (*)(传入参数类型)
看下面的运用
利用函数指针数组实现简单的运算器
这种算法将函数指针存在一个数组中,通过输入值来确定调用的函数运算,同时方便后期扩展,加入其他运算,只需要改一下菜单,将新加入的函数放到数组中,再改一下if判断条件。
上面这个程序可以通过switch语句实现,但是效果并不好。
三,指向函数指针数组的指针
是一个指针,指向一个数组,这个数组里面的元素都是函数指针
总结:数组指针: 数组数据类型 (*指针名)[元素个数]
函数指针:函数返回数据类型 (*指针名)(传入参数类型)
函数指针数组:函数返回类型 (*数组名[元素个数])(传入参数类型)
指向函数指针数组的指针:函数返回类型(*(*指针名)[元素个数])(传入类型)
四,回调函数
通过函数指针调的函数,把一个函数的地址传给另外一个函数,,当这个指针被用来调用其所指的函数时,我们就说这是回调函数,回调函数不是由该函数的实现方直接调用,而是再特定的事件或条件发生时由另外的一方调用的
这个代码,通过test函数调用函数print,这里的print就被称为回调函数
接下来里了解一个库函数,qsort,这是一个对任意数据类型进行排序的函数
void* :无具体类型指针,可将任何数据类型用这个指针定义,都不出错
void*类型的指针可以接受任何类型的地址
对于void*不可以进行解引用,因为没有数据类型,解引用不知道访问几个字节,也不可以进行+-
有关qsort的使用:
1,引头文件:#include<stdlib.h>
2,看写入的参数
void qsort(
void *base,
size_t num,
size_t width,
int (__cdecl *compare )(const void *elem1, const void *elem2 )
)前三的都很好理解,分别是:排序数组首元素地址,写数组名即可;排序数组元素个数;每个元素大小;
第四个是比较方法,需要自己根据不同数据类型自己写的一个函数,函数指针的两个参数是要比较的两个元素地址,返回值是int
之前写的冒号排序
用qsort实现:
什么数据类型就要进行怎么样的强制类型转化
浮点数的排序
结构体进行排序:
年龄:
名字:
qsort内部逻辑: