函数指针,顾名思义就是函数的指针。如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。
函数指针的定义
先来看一段代码:
#include<stdio.h>
void test()
{
printf("hehe\n");
}
int main()
{
printf("%p\n", test);
printf("%p\n", &test);
return 0;
}
此时输出的两个地址就是test函数的地址
在明确函数确实是有地址之后我们就要考虑如何定义函数指针变量了,它和以往我们所使用的指针变量定义略有不同
给一个例子
int(*p)(int,int)
这就是一个函数指针,首先因为是指针所以是(),()前面的int表示的是接受的返回值类型,而int(*)后面的(int,int)表示这个指针变量可以指向有两个参数且都是 int 型的函数,所以可以理解为该指针指向一个返回值是int型并且参数类型是两个int型的函数。
> 所以函数指针的定义方式为: 函数返回值类型 ( 指针变量名) (函数参数列表)
int Add(int a, int b)
{
}
int main()
{
printf("%p\n", &Add);
printf("%p\n", Add);//这两个都是获得函数地址只是写法不同,但是意义是相同的,这里不要和数组相联系
}
输出的都是Add的地址
函数指针的简单使用
我们该如何使用这个指针呢?
int Add(int a, int b)
{
return a + b;
}
int main()
{
int (*pf)(int, int) = Add;//将存储在p中,p就是函数指针变量
int sum = (*pf)(4, 6);
printf("%d\n", sum);
}
让我们来判断一下以下哪一个是函数指针
练习1
A.int* test(inta, intb);
B.int (*test)(int a, char b);
C.(int*) test(int a, int b);
D.int(*) test(int a, char b);
答案是B 第一三四并没有什么区别,带的括号并不影响优先级,都是返回值类型为int*的函数
练习2
定义一个函数指针,指向的函数有两个int形参并且返回一个函数指针,返回的指针指向一个有一个int形参且返回int的函数?下面哪个是正确的?( )
A.int (*(*F)(int, int))(int)
B.int (*F)(int, int)
C.int (*(*F)(int, int))
D.*(*F)(int, int)(int)
答案是B 首先排除D选项,因为D的定义并不完整。题目中定义一个函数指针要求返回值是一个函数指针,那么排除B选项,返回的指针指向一个有一个int形参且返回int的函数,那么此时我们可以删除之前的函数名和参数列表 即:将int (*(F)(int, int))(int)删除后是int ()(int),所以答案是B
附加题
请思考一下这两段代码是什么意思?
//代码1
(*(void (*)())0)();
//代码2
void (*signal(int , void(*)(int)))(int);
注 :推荐《C陷阱和缺陷》
这本书中提及这两个代码。
附加题1
void ()()是一个函数指针类型
(void ()()) 将一个类型放在括号里面就是强制类型转换
(void ()())0的意思就是对0进行强制类型转换,将0强制类型转换成一个函数指针我们认为0地址处
放着一个返回类型为void参数类型为空的函数
((void ()())0) 相当于对0地址处解应用访问void ()()这个函数
((void ()())0)() 此时调用这个函数,传的参数为空
附加题2
signal(int, void()(int)) signal是函数名,和括号先结合,形成一个函数,signal的参数第一个是int类型,第二个参数是函数指针类型,
我们回顾一下函数指针的定义 函数返回值类型(指针变量名) (函数参数列表) 那么此时还缺少的是函数返回类型
void (signal(int, void()(int)))(int) 删去signal(int, void()(int)) 变为 void ()(int)
void ()(int)是什么?又是一个函数指针,说明它的返回值就是一个函数指针
所以signal是一个函数声明,其参数第一个是int类型的,第二个是void()(int)类型的
signal函数的返回值类型也是void(*)(int)类型的
函数指针数组
我们现在已经了解了什么是函数指针,那么函数指针数组也就容易理解很多了。
数组是一个存放相同类型数据的存储空间,我们学过很多数组:
函数指针数组的定义
int main()
{
int* arr[10];//整形指针数组
char* arr2[10];//字符型指针数组
}
那函数指针的数组如何定义呢?
int (*parr1[10])();
int *parr2[10]();
int (*)() parr3[10];
答案是:parr1
parr1 先和 [] 结合,说明 parr1是数组,数组的内容是什么呢?
是 int (*)() 类型的函数指针。
int Add(int a, int b)
{
return a + b;
}
int Sub(int a, int b)
{
return a - b;
}
int Mul(int a, int b)
{
return a * b;
}
int Dil(int a, int b)
{
return a / b;
}
int main()
{
int (*pf1)(int, int) = Add;
int (*pf2)(int, int) = Sub;
int (*pf3)(int, int) = Mul;
int (*pf4)(int, int) = Div;
int (*pf[4])(int, int) = { Add, Sub, Mul, Div };
return 0;
}
在我们明白函数指针数组的定义及简单使用后,可能读者会有疑问,这个函数指针数组有什么用途呢?
函数指针数组的用途:简易计算器的实现
#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
int Add(int a, int b)
{
return a + b;
}
int Sub(int a, int b)
{
return a - b;
}
int Mul(int a, int b)
{
return a * b;
}
int Div(int a, int b)
{
return a / b;
}
int main()
{
int input = 1;
int x, y;
int ret = 0;
int (*pf1)(int, int) = Add;
int (*pf2)(int, int) = Sub;
int (*pf3)(int, int) = Mul;
int (*pf4)(int, int) = Div;
int (*pf[5])(int, int) = { 0 ,Add, Sub, Mul, Div };
while (input)
{
printf("*****************************\n");
printf(" 1:add 2:sub \n");
printf(" 3:mul 4:div \n");
printf(" 0.exit \n");
printf("*****************************\n");
printf("请选择所需要的功能:");
scanf("%d", &input);
if (input == 0)
{
printf("退出程序\n");
}
if (input <= 4 && input>=1)
{
printf("请输入操作数x:");
scanf("%d", &x);
printf("请输入操作数y:");
scanf("%d", &y);
printf("%d\n", ret = (*pf[input])(x, y));
}
if (input < 0 || input>4)
{
printf("输入错误");
}
}
return 0;
}
对于函数指针及函数指针数组的讲解到此解释,如有错误还请读者斧正!