目录
什么是函数指针?
我们来类比一下
int* pa; //整型指针
char* pb; //字符指针
int(*pc)[3]; //数组指针,指向存放3个int的数组
char(*pd)[3]; //数组指针,指向存放3个char的数组
顾名思义,函数指针是一个指向函数的指针
函数指针标准
函数名的意义
我们在学习数组时知道数组名表示数组的首元素地址,&数组名表示整个数组的地址,因为数组在空间中占一段连续的空间,函数同样如此。函数名表示函数的地址,但和数组名有一点区别:&函数名和函数名等价。
#include<stdio.h>
void aa(void) { //定义aa函数
printf("123");
}
int main(void) {
void(*p)(void); //定义一个函数指针,先不用管这个
p = aa;
printf("%p\n", p);
printf("%p\n", *p);
printf("%p\n", aa);
printf("%p\n", &aa); //四个结果的完全相同
}
函数中()的意义
我们一般调用函数的时候,是一个函数名加上一个(),()里变看情况放着相应的参数。还记得数组的【】吗?表示对左侧的指针进行运算后解引用。()表示对于左侧的地址将参数传入后进行访问(这里并不能用*对其访问,()在设计时就限定了函数)。
一个函数指针
int Add(int a,int b){} //一个函数定义
int (*p)(int, int); //一个函数指针变量定义,p先于*结合知道是一个指针
//再与()结合,表示指向函数。
//在与int,int结合表示所指向的函数有两个参数
//最后与int结合,表示所指向函数返回一个int
//关于为什么要加括号,因为p会先于右边的()结合而导致是一个返回值为int*类型的函数
//优先级*<[]<()
函数指针的赋值及使用
在数组指针赋值时,我们是将数组的地址赋给它,可以认为是一个比一级指针高一级的一个类型(&数组名)。函数指针同样如此,我们将函数的地址赋给函数指针变量,可以认为是一个比函数地址高一级的一个类型,所以我们在使用时需要进行访问一次,效果才等同于函数名。
#include<stdio.h>
int Add(int a, int b) {
printf("%d\n", a + b);
return a + b;
}
int main(void) {
int (*p)(int, int);
p = Add; //对其进行赋值
Add(2, 3);
(*p)(2, 3); //p=Add,但是转化类型后要高一级,所以这里*p
printf("%d", (*p)(2, 3)); //程序在这步会打印两次5
}
两个有趣的函数指针
No.1
(*(void(*)())0)()
//先看 void(*)() 这是一个函数指针类型
//对0进行强制类型转换 (void(*)())0
//你可能会疑惑,0也能强制类型转换吗?之前说过数据在内存中,就是空间+方式(规则)
//也就是类型,所以类型转换在计算机中除非特殊规定,否则就是“强制”。
//这个时候就相当于定义了一个指向0的数组指针变量 (void(*)())0 这里用p表示一下
//将其替换,(*p)(),调用这个函数。
也可以写成这样
void(*p)();
p = 0;
(*p)(); //将p看成 (void(*)())0 即可
No.2
void(*signal(int, void(*)(int)))(int);
//首先我们看到signal,()优先级大于*,这是一个函数
//参数为整型和函数指针类型,没有变量可知是一个函数声明
//返回值呢?我们来看一下正常点的函数
int Add(int , int );
int //将函数名和()去掉剩下的就是返回值的类型
//将signal(int,void(*)(int))去掉
//剩下void(*)(int),就是返回值的类型:函数指针类型
,描述:
//signal是一个函数说明
//signal函数的参数有两个,第一个是int。第二个是函数指针,该函数指针指向的函数的参数是int,返回类型是void
//signal函数的返回类型是函数指针,该函数指针指向的函数的参数是int,返回类型是void
void(*)(int) signal (int, void(*)(int));
//可以这么理解,但不能这么写
No.2的简化——typedef
我们知道typedef可以对名字复杂的类型增加名字,这里同样可以对函数指针类型名字使用
typedef void(*)(int) fun_p; //正常来说是这样写的,但函数指针有点特殊
typedef void(*fun_p)(int); //应该这样写
fun_p signal(int, fun_p); //函数声明就可以进行简化