文章目录
六、函数指针
顾名思义,函数指针就是指向函数的指针,即存放函数地址的指针。
void test()
{
printf("hehe\n");
}
int main()
{
printf("%p\n", test);
printf("%p\n", &test);
return 0;
}
输出结果:
我们发现函数名与取地址函数名内容相同,此处需要注意的是:
数组名 != &数组名
函数名 = &函数名
函数指针的定义:
与数组指针的定义类似,我们需要这样来定义一个函数指针:
int Add(int x , int y)
{
return x+y;
}
int main()
{
int (*pf)(int , int) = &Add;//定义一个函数指针
}
需要注意的是:
其中第一个int表示函数返回值类型,因为我们的Add()函数的返回值是int类型,所以此处用int。
(*pf)是表示pf是一个指针,为了让它先和*结合起来所以用括号圈起来,这和数组指针类似。
(int ,int)则表示Add()函数的参数类型。
举例:
对于void test(char *ptr){}
这个函数如何定义一个关于它的函数指针呢?
函数指针定义:void (*pt)(char *) = &test;
既然如此,那么如何去使用这个函数指针呢?请看下面代码:
int Add(int x, int y)
{
return x + y;
}
int main()
{
int (*pf1)(int, int) = &Add;//定义一个函数指针
int ret1 = (*pf1)(10, 6);//利用函数指针调用函数
int (*pf2)(int, int) = Add;//因为Add和&Add一样,所以此处这样写也没问题!
//由上面得出:Add === pf2
//既然Add === pf2,那么下面的用法:
int ret2 = pf2(10, 6);//这也是没问题的
printf("%d\n", ret1);
printf("%d\n", ret2);
return 0;
}
对pf1解应用(*pf1)就找到了这个函数,再传参就可以调用该函数。
注意,一定要加括号括起来:(*pf1)
但是,这里的*号其实是摆设,直接使用pf1(10,6)
也没啥问题!
当然啦,只有在函数指针这里这个*才可以省略!其他指针都不可省略解引用符号
输出结果:
阅读以下两个代码加深对函数指针的理解:
//代码1
(*(void (*)())0)();
//代码2
void (*signal(int , void(*)(int)))(int);
解释:
代码1:
(*(void (*)())0)();
从0处下手,(void (*)())0
中,void (*)()
表示一种类型,若为void (*p)()
则可以更明显的看出这是一个函数指针变量,指向的函数返回值为void
类型,不含参数。如果去掉p则表示一种函数指针类型(正如int a
表示整型变量,而(int)0
表示将0强制转化为int类型一样)。所以(void (*)())0
其实表示的就是将0强制转化为函数指针类型,即0这个数字被强制认为是一个函数的地址。前面加上*号表示将0地址处的函数指针解引用,而由前面的该函数指针类型可知函数没有参数,所以整个的(*(void (*)())0)()
表示:调用0地址处的函数,该函数没有参数,返回类型为void。
代码2:
void (*signal(int , void(*)(int)))(int);
先从signal入手,signal后面直接跟的圆括号,说明signal是一个函数,即:signal(int , void(*)(int))
,signal函数有两个参数,第一个参数是int类型,第二个参数是void(*)(int)类型,这是一个函数指针,指向一个参数为int,返回类型为void的函数。
既然signal是一个函数,它的函数名与参数都有了,它的返回类型呢?
如果将上面signal(int , void(*)(int))
这一块整体拿掉,剩下的void (*signal(int , void(*)(int)))(int) --> void(*)(int)就是这个函数的返回类型,所以signal这个函数的返回类型也是一个函数指针,该指针同样指向一个参数为int,返回类型为void的函数。
综上所述,这是一个关于signal函数的函数声明!
为了方便理解,可以这样认为:void (*)(int) signal(int , void(*)(int));
但是语法是不允许这样写的!那么能不能用一种方法让这个函数声明看起来更简洁明了呢?
这里需要用到typedef,它的作用是对类型重定义。比如typedef unsigned int u_int
就是将unsigned int这个类型重定义为u_int,那么以后可以直接使用u_int来定义变量了,比如u_int a;
对于函数指针类型的重定义也可以这样做,它的形式是这样的:typedef void (*p_fun)(int);
于是这样,代码2可以简洁表示为:
七、函数指针数组
7.1函数指针数组的定义
既然有存放整型指针的数组–指针数组–int *arr[10];
那么肯定有可以存放函数指针的数组—函数指针数组—int (*pArr[2])(int, int)—pArr和[]先结合说明是一个数组,去掉数组名+[]后只剩下:int (*)(int, int),这就是这个数组的类型,这个类型是函数指针类型,所以这个数组也就是函数指针数组!
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int main()
{
int (*pf1)(int, int) = Add;
int (*pf2)(int, int) = Sub;//两个函数指针
int (*pArr[2])(int, int) = {
A