C语言——指针的进阶详解(2)

        前言

        紧接上篇,之前我讲解了指针的进阶详解1,大家没看过的可以先去看那篇,接下来,我来讲一讲指针的另一部分内容:函数指针,函数指针数组和回调函数。

目录

        一.函数指针

         1.函数指针定义:可以理解为指向函数的地址的指针

2.函数指针的介绍与写法

3.函数指针的用途

二.函数指针数组   

        1.定义

      2.  函数指针数组的用途 

三.指向函数指针数组的指针


        一.函数指针

         1.函数指针定义:可以理解为指向函数的地址的指针

        有人会问了,函数也有地址吗?答案也是毋庸置疑的,有!那么我来给大家展示一下函数的地址。

#include<stdio.h>
void test() {
	return 0;
}

int main() {
	printf("%p\n", test); 
	printf("%p\n", &test);
    return 0;
    }

        在上面的代码中,我随意创建了一个函数,通过打印,函数也有地址 。

         总结:函数地址不分首地址和整体地址,函数有且只有一个地址,可以直接用函数名表示,也可以加&符合表示。

        而指针的作用就是取出某个变量,数组,指针的地址,那么函数也不例外,由此引出函数指针。

2.函数指针的介绍与写法

int Add(int x, int y) {
	return x + y;
}
int main() {

	int a, b;
	printf("请输入两个操作数:\n");
	scanf("%d %d", &a, &b);
	int ret = Add(a, b);

        这是一般情况下对函数的调用,函数名+()调用操作符,即可使用函数的功能实现;

        而函数指针也可以用来调用函数实现其功能:

int Add(int x, int y) {
	return x + y;
}
   
 int main(){
//接下来使用函数指针去调用
	int (*pf)(int, int) = Add;	
	printf("方法3的写法:%d\n",pf(2, 3));
	printf("方法2的写法:%d\n", (*pf)(2, 3));
	printf("普通函数的调用:%d\n", Add(2, 3));
    return 0;
    }
    

        由此可知我们在main函数中进行函数的调用有两种方法,那么函数指针是如何进行创建的?

         函数指针的创建需要根据据函数的返回值类型,函数的参数多少去定义。

        例: 在上面的Add函数中,函数的参数有两个,且都是int类型形参,而且函数的返回值类型是int型,指针肯定是*,那么随便起一个指针名就行。通过这几个信息我们就可以创建函数指针。

        函数指针的类型为:(填写指向函数的返回值类型)(*)(填写指向函数的参数数量);

     (你们可以理解为万能模板,以后写函数指针就可以采用这个模板复刻!hhh).

3.函数指针的用途

        用人会问:函数指针这么麻烦,还不如就用普通函数法去调用。这是因为我们现阶段接触的代码并不算多,等级也不算高,若是以后在公式做项目时,项目会有成千上万行的代码,函数也多得不计其数,使用函数指针就可以简化调用步骤。下面来给大家看一看使用函数指针到底有什么好处?

#include<Windows.h>
#include<stdio.h>

void menu() {
	printf("**********计算器使用界面*************\n");
	printf("**************1.Add.*****************\n");
	printf("**************2.Sub.*****************\n");
	printf("**************3.Mul.*****************\n");
	printf("**************4.Div.*****************\n");
	printf("**************0.exit.****************\n");
}

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 input = 0;
	int a, b;
	int ret = 0;
	do {
		menu();
		printf("请输入你的选择:\n");
		scanf("%d", &input);
		
		switch (input) {
		case 1:
			printf("请输入两个操作数:\n");
			scanf("%d %d", &a, &b);
			int ret = Add(a, b);
			printf("%d\n", ret);
			break;

		case 2:
			printf("请输入两个操作数:\n");
			scanf("%d %d", &a, &b);
			 ret=Sub(a, b);
			printf("%d\n", ret);
			break;
		case 3:
			printf("请输入两个操作数:\n");
			scanf("%d %d", &a, &b);
			 ret = Mul(a, b);
			printf("%d\n", ret);
			break;
		case 4:
			printf("请输入两个操作数:\n");
			scanf("%d %d", &a, &b);
			 ret = Div(a, b);
			printf("%d\n", ret);
			break;
		case 0:
			printf("即将退出计算器\n");
			exit(0);
		default:
			printf("输入错误\n");
			break;
		}
	} while (input);
	return 0;
}

        以上代码为计算器的功能实现方式,我们可以在主函数中看到switch多分支选择语句case中有着大量的代码冗余,造成了空间上的巨大浪费,现在只是写了加减乘除四个功能,若是再加十多个异或,左右移,按位与或等功能,代码量想必会更加多。这时,就到了函数指针关键救场的时候了,通过函数指针可以优化冗余代码,使每个分支语句的计算器功能只用一条语句实现,如下:

#include<stdio.h>
#include<Windows.h>
void menu() {
	printf("**********计算器使用界面*************\n");
	printf("**************1.Add.*****************\n");
	printf("**************2.Sub.*****************\n");
	printf("**************3.Mul.*****************\n");
	printf("**************4.Div.*****************\n");
	printf("**************0.Add.*****************\n");
}
void calc(int(*pf)(int ,int)) {	

	int a, b;
	int ret = 0;
	printf("请输入两个操作数:\n");
	scanf("%d %d", &a, &b);
	 ret = pf(a, b);
	printf("%d\n", ret);
}

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 input = 0;
	int a, b;
	int ret = 0;
	do {
		menu();
		printf("请输入你的选择:\n");
		scanf("%d", &input);

		switch (input) {
		case 1:
			calc(Add);
			break;
		case 2:
			calc(Sub);
			break;
		case 3:
			calc(Mul);
			break;
		case 4:
			calc(Div);
			break;
		case 0:
			printf("即将退出计算器\n");
			exit(0);
		default:
			printf("输入错误\n");
			break;
		}
	} while (input);
	return 0;
}

        通过创建函数calc,因为加减乘除四个函数的返回值类型,函数参数都相同,由此在calc中创建出函数指针,可以通过函数指针pf 指向加减乘除中的任何一个函数,借此调用该函数,实现其功能,大家可以看到,我只用到了一个函数就可以实现对其他计算器功能函数的调用,大量简化代码,若没有函数指针,我们根本无法做到如此简化的代码,想必大家也都认识到了函数指针的重要性!


二.函数指针数组   

        1.定义

        那要把一个乃至多个函数的地址存到一个数组中,那这个数组就叫函数指针数组

        我们来看几个例子,请各位判断一下下列哪个是函数指针数组?

int (*parr1[10])();

int *parr2[10]();

int (*)() parr3[10]; 

       

        答案其实是第一个,parr1 先和 [] 结合,说明 parr1是数组,数组的内容是什么呢? 是 int (*)() 类型的函数指针。 

      2.  函数指针数组的用途 

         它的用途我们还是用刚才对计算器功能实现的代码来看:

        其实通过代码我们发现switch多分支选择语句有些多余,我们已经了解了函数指针数组,那我们可以采用数组遍历的方式,数组中既然存入了函数的地址,我们可以通过输入某个数,程序就自动进入到数组的那一个位置,然后去找到该数组元素(函数)的地址,进而调用函数实现该功能!

#include<Windows.h>
#include<stdio.h>
void menu() {
	printf("**********计算器使用界面*************\n");
	printf("**************1.Add.*****************\n");
	printf("**************2.Sub.*****************\n");
	printf("**************3.Mul.*****************\n");
	printf("**************4.Div.*****************\n");
	printf("**************0.exit.****************\n");
}

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 input = 0;
	int a, b;
	int ret = 0;
	//函数指针的数组,将计算机功能都放在数组中,因为下标从0开始,所以数组首元素加个0。
	int(*arr[5])(int, int) = {0,Add,Sub,Mul,Div };
	while (1) {
		menu();
		printf("请输入你的选择:\n");
		scanf("%d", &input);
		if (input>= 1 && input < 5) {	//输入哪个数就选择数组中的哪个数,进而调用此数位置的函数
			printf("请输入两个操作数:\n");
			scanf("%d %d", &a, &b);
			ret = arr[input](a, b);
			printf("%d\n", ret);
		}
		else if (input == 0) {
			printf("即将退出程序\n");
			exit(0);
		}
		else {
			printf("输入错误\n");
		}
	}
	return 0;
}

        大家若想增加计算器中的更多功能,只需要写出该功能的函数,扩大数组的大小,将函数地址放入数组,增加input输入值的上限即可,方便又快捷! 


三.指向函数指针数组的指针

        若是大家看过我前面写的指针进阶详解 (1),想必就知道函数指针数组这又是一个套娃名词,数组指针,数组指针的数组,指向数组指针的数组的指针......实乃无限套娃之无限套娃啊~!!!

        

名词解析:

指向函数指针数组的指针是一个 指针

指针指向一个 数组 数组的元素都是 函数指针

void test(const char* str)
{
 printf("%s\n", str);
}
int main()
{
 //函数指针pfun
 void (*pfun)(const char*) = test;
 //函数指针的数组pfunArr
 void (*pfunArr[5])(const char* str);
 pfunArr[0] = test;
 //指向函数指针数组pfunArr的指针ppfunArr
 void (*(*ppfunArr)[5])(const char*) = &pfunArr;
 return 0;
}

         具体的就不再过多讲解了,大家有兴趣的话可以深入了解了解这方面的知识内容。

         

        好了,关于指针的进阶详解2就讲到这里,大家觉得对自己帮助挺大的话,点个赞吧!以后会有更多精彩内容,点个关注不要迷路哟!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橙予清的zzz~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值