【指针的进阶(2)】——函数指针和函数指针数组


前言

继上一章【指针的进阶(1)】,继续完善第二章内容


一、函数指针

含义:指向函数的指针

1.1 函数指针的写法

#include<stdio.h>
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]

1.2 函数指针的用法

可以通过指针间接访问函数,调用这个函数

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;
}

1.3 练习题

int main()
{
    
    
	(*(void(*)()) 0)();
}

解读这段代码的意思是:
void( * )() 是函数指针类型
( void( * )() ) 把0强制类型转换成函数指针类型
* (void( * )() ) 是对地址解引用
* (void( * )() ) () 最后面的括号是调用这个函数
其实就是
1.将0强制类型转换成void(*)() 函数指针类型的地址
2.调用0地址处的函数



int main()
{
    
    
	void ( * signal(int, void(*)(int) ) ) (int);

	return 0;
}

解读这段代码的意思是:

  • signal是一个函数声明
  • signal(int, void( * )(int) )说明:signal函数有两个参数,第一个参数的类型是int,另一个参数的类型是void( * )(int)函数指针类型,该函数指针指向的函数有一个int类型,返回类型是void
  • signal 函数的返回类型也是void( * )(int)函数指针类型,该函数指针指向的函数有一个int类型,返回类型是void

1.4 typedef简化代码

这段代码太过复杂,解读性不高,可以使用 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 * arr[5]; 整型指针数组
  • char * arr2[5]; 字符指针数组

2.1 函数指针数组的写法

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;
}

2.2 函数指针数组的用处

写一个计算器,有加减乘除功能,一般的写法如下:

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;
}

总结

本章对函数指针函数指针数组进行了详细地讲解,如果对您有帮助的话,不妨来一个关注吧!

猜你喜欢

转载自blog.csdn.net/2301_76496134/article/details/131775396