继上一章【指针的进阶(1)】,继续完善第二章内容
含义:指向函数的指针
#include
int Add(int x, int y)
{
return x + y;
}
int main()
{
int arr[10] = { 0 };
printf("%p\n", Add);
//函数名是函数的地址
printf("%p\n", &Add);
//&函数名也是函数的地址
int(*pf)(int,int) = &Add;//函数指针
return 0;
}
思路: 把函数地址存起来,存到变量pf里,pf是用来存放函数地址的,所以pf类型是函数指针。
函数指针写法:去掉指针变量pf,剩下的其实就是函数指针类型 int(*)(int,int) 左边是返回类型,右边是参数类型
和数组指针很像,int(ptr)[5]=&arr,去掉指针变量ptr,剩下的就是数组指针类型 int()[5]
可以通过指针间接访问函数,调用这个函数
int Add(int x, int y)
{
return x + y;
}
int main()
{
int (*pf)(int, int) = &Add;
int r = Add(3, 5);
printf("%d\n", r);
int m = pf(4, 5);
printf("%d\n", m);
return 0;
}
int main()
{
(*(void(*)()) 0)();
}
解读这段代码的意思是:
void( * )() 是函数指针类型
( void( * )() ) 把0强制类型转换成函数指针类型
* (void( * )() ) 是对地址解引用
* (void( * )() ) () 最后面的括号是调用这个函数
其实就是
1.将0强制类型转换成void(*)() 函数指针类型的地址
2.调用0地址处的函数
int main()
{
void ( * signal(int, void(*)(int) ) ) (int);
return 0;
}
解读这段代码的意思是:
这段代码太过复杂,解读性不高,可以使用 typedef 可以简化
例如
typedef unsigned int uint;
对unsigned int重命名为uint
typedef int * ptr;
对指针重命名为ptr,int* p1;
等同于 ptr p2;
typedef void(*ptr_t)(int);
ptr_t signal(int, ptr_t);
注意 指针函数重命名是在( * )里面换,如把 void(*)(int)重命名为ptr_t,写法是 void(*ptr_t)(int)。signal 函数的返回类型也是void( * )(int)函数指针类型,所以最后简写成了ptr_t signal(int, ptr_t);
数组的每个元素是函数指针类型
类比
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x-y;
}
int Mul(int x, int y)
{
return x * y;
}
int Div(int x, int y)
{
return x / y;
}
int main()
{
int(*pf1)(int,int)= Add;
int(*pf2)(int,int) = Sub;
int(*pf3)(int,int) = Mul;
int(*pf4)(int,int) = Div;
return 0;
}
存放四个函数的函数指针的类型都是一样的,使用函数指针数组更简便
写法如下:
int main()
{
int(*pfarr[4])(int, int) = { Add,Sub,Mul,Div };
return 0;
}
写一个计算器,有加减乘除功能,一般的写法如下:
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int Mul(int x, int y)
{
return x * y;
}
int Div(int x, int y)
{
return x / y;
}
void menu()
{
printf("***************************\n");
printf("***** 1.add 2.sub ******\n");
printf("***** 3.mul 4.div ******\n");
printf("***** 0.exit ******\n");
printf("***************************\n");
}
int main()
{
int input = 0;
int x = 0;
int y = 0;
int ret = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
printf("请输入两个操作数:");
scanf("%d %d", &x, &y);
ret = Add(x, y);
printf("ret = %d\n", ret);
break;
case 2:
printf("请输入两个操作数:");
scanf("%d %d", &x, &y);
ret = Sub(x, y);
printf("ret = %d\n", ret);
break;
case 3:
printf("请输入两个操作数:");
scanf("%d %d", &x, &y);
ret = Mul(x, y);
printf("ret = %d\n", ret);
break;
case 4:
printf("请输入两个操作数:");
scanf("%d %d", &x, &y);
ret = Div(x, y);
printf("ret = %d\n", ret);
break;
case 0:
printf("退出计算器\n");
break;
default:
printf("选择错误,重新选择\n");
break;
}
} while (input);
return 0;
}
mani函数里有很多重复性的代码,过于冗余,如果要添加更多的函数进去,就要写更多的case语句,工作量大又麻烦。
而使用函数指针数组将大大提高效率
用函数指针数组的方式实现
思路:函数指针数组的使用 - 也叫转移表,意思是函数的下标对应一个数字,通过下标找到某个函数地址,继而调用某个函数。
在使用计算器的时候,通常会出现三种情况,第一种不想使用了,想退出计算器,第二种选择了正确的数字(函数的下标),实现计算;第三种选了大于函数下标的数字,则要重新选择。
对于三种情况,显然用if,else if,else语句最合适不过,因为数组的下标是从0开始的,那么可以让NULL占了0的下标,让函数从下标1开始,会更方便选择。
int (* pfArr[5])(int, int) = {NULL, Add, Sub, Mul, Div};
// 0 1 2 3 4
先选择一个数字,如果数字大于0小于下标数字,则进入循环
if (input >= 1 && input <= 4)
再输入两个数字,进行计算,打印。
printf("请输入两个操作数:");
scanf("%d %d", &x, &y);
ret = pfArr[input](x, y);
printf("ret = %d\n", ret);
如果选择的数字为0,则退出计算器;
else if(input == 0)
{
printf("退出计算器\n");
}
如果选的数字大于下标数字,则选择错误,重新选择。
else
{
printf("选择错误,重新选择\n");
}
想选择多次计算的话,把if,else if,else语句放在dowhile()循环里面进行,整个过程就可以循环起来。
具体代码如下:
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int Mul(int x, int y)
{
return x * y;
}
int Div(int x, int y)
{
return x / y;
}
//...可以添加更多的函数
void menu()
{
printf("***************************\n");
printf("***** 1.add 2.sub ******\n");
printf("***** 3.mul 4.div ******\n");
printf("***** 0.exit ******\n");
printf("***************************\n");
}
int main()
{
int input = 0;
int x = 0;
int y = 0;
int ret = 0;
int (* pfArr[5])(int, int) = {NULL, Add, Sub, Mul, Div};
// 0 1 2 3 4
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
if (input >= 1 && input <= 4)
{
printf("请输入两个操作数:");
scanf("%d %d", &x, &y);
ret = pfArr[input](x, y);
printf("ret = %d\n", ret);
}
else if(input == 0)
{
printf("退出计算器\n");
}
else
{
printf("选择错误,重新选择\n");
}
} while (input);
return 0;
}
本章对函数指针和函数指针数组进行了详细地讲解,如果对您有帮助的话,不妨来一个关注吧!