玩透指针系列(三)—— 得心应手,指针应该这么玩!

1.函数指针

我们知道,整型指针是指向整型的指针;数组指针是指向数组的指针;以此类推,那么 函数指针就是指向函数的指针
和其他指针一样,在讲解函数指针之前,首先明白这三点:
1.( )的优先级高于 *
2.定义一个变量是,除去变量名,剩下的就是它的变量类型
3.一个指针变量去除变量名和 * 剩下的就是指针指向的内容的类型

对于函数指针,举个栗子:

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int(*p)(int, int) = &Add;//取出函数的地址放在函数指针p中
	return 0;
}

此时的变量 p 就为一个函数指针变量。
那么如何定义函数指针的呢?图示如下:
在这里插入图片描述
即定义一个函数指针时,指针的类型要与函数的类型一致。

例如

void test ( char* str ) 为一个函数,那么定义一个指向它的函数指针就为:
void ( * p ) ( char * )

补充说明一点:
对于数组而言: 数组名 != &数组名
对于函数而言: 函数名 = &函数名( 规定)

那么如何使用函数指针呢?
看如下代码:

int add(int x, int y)
{
	return x + y;
}
int main()
{
	int (*p)(int, int) = &add;
	int ret = (*p)(3, 5);//对p解引用,然后再传入参数即可
	printf("%d\n", ret);
	return 0;
}

在这里插入图片描述
即通过对函数指针解引用找到该函数,然后传入参数就可实现函数的调用。
深入探究:

对于 int (*p)(int, int) = &add; 此行代码,我们又知道 函数名 = &函数名,
那么代码也可写成 int (*p)(int, int) = add; 因为指针p中存放的为函数add的地址,所以我们就能这样理解:p == add ,即 p 与函数名 add 为一回事,所以当我们调用函数时,可以写:
add ( a , b ) == p ( a , b ) == (*p) ( a , b ) ---- 经过代码验证,输入的结果一样。
这样一来,我们就知道了 ( *p ) ( 3, 5) 中的 解引用符号 * 是没有任何意义的,在写程序时,可写可不写。

2.函数指针数组

我们知道,数组是一个存放相同数据类型的空间,例如:

int arr[ 10 ] 为一个整型数组,存放10个元素,每个元素 int 型整数
char* arr[ 10 ] 为一个指针数组,存放10 个元素,每个元素为 char* 型指针
. . .

那么如果要将函数指针存放在一个数组中,那么这个数组就为函数指针数组
如何定义函数指针数组?例如:

定义 int (*parr[10])( int , int )

parr[10] 就为一个函数指针数组,可以存放10个函数指针,每个函数指针的类型为 int (* )( int , int ) 型。
所以简单来说,创建一个函数指针,只需要在原有的函数指针的形式下加上
[ ] 即可,例如:

存在函数指针:int (*p)(int, int) = &add
此时要创建一个存放指针 p 的数组,那么函数指针数组定义为:
int ( * parr[10] )( int , int )
该函数指针数组能存放 10 个与指针p类型一样的函数指针

函数指针数组的应用:转移表
举个栗子:模拟计算器

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 = 1;
	int (*p[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("************************\n");
		scanf("%d", &input);
		if (input >= 1 && input <= 4)
		{
			int i = 0;
			int j = 0;
			printf("请输入运算数:");
			scanf("%d %d", &i, &j);
			int ret = (*p[input])(i,j);
			printf("结果为:%d\n", ret);
		}
		else
		{
			printf("输入错误!\n");
		}
	}
	return 0;
}

在这里插入图片描述
这里就巧妙地运用了函数指针数组,将运算的函数存放在函数指针数组p中,
再通过数组的下标找到相应函数,解引用后传参就可调用相应函数。
相比于switch-case语句来每次调用函数,使用函数指针数组更为方便,且代码量相对少,避免代码冗余。

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

说明:
指向函数指针数组的指针是一个 指针,
该指针指向一个 数组 ,数组的元素都是 函数指针 ;

如何定义?

void test(const char* str)
{
printf("%s\n", str);
}
int main()
{
void (*pfun)(const char*) = test;//函数指针 pfun

void (*pfunArr[5])(const char* str);//函数指针数组 pfunArr

pfunArr[0] = test;
void (*(*ppfunArr)[10])(const char*) = &pfunArr;
//指向函数指针数组 pfunArr 的指针 ppfunArr
return 0;
}

void ( * ( * ppfunArr )[10])(const char*) = &pfunArr; 即为指向函数指针数组的指针 ppfunArr 的定义
在这里插入图片描述

对于指向函数指针数组的指针的讲解就不多说了,仅作了解即可。

4.回调函数

所谓回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
举个简单的栗子:

void test2()
{
	printf("Hello world!");
}

void test1(void (*p)()) //形参用函数指针接收,该指针指向 test2
{
	p(); //调用函数指针
}

int main()
{
	test1(test2); //将函数test2作为参数,即将函数test2的地址传过去
	return 0;
}

在这里插入图片描述
类似以上程序中函数的调用机制就很好的利用了回调函数。
回调函数的意义就在于可以通过一个函数从而实现多个函数的调用,可以有效的减少代码冗余的出现。

回调函数机制的运用在这里先不做说明,我会在下一篇博客中做具体详解。
希望大家多多关注哦!!!

  • 20
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值