进阶指针大全(下篇)---函数指针和回调函数


前言

`在上篇,我们已经讲了指针和数组的深入关系,现在讲讲指针和函数的深入关系。


一、函数指针

什么是函数指针?例如数组指针,是指向数组的指针。那么函数指针则是 指向函数的指针,或许有人说指针存储的是地址,那么函数也有地址嘛?我们先来看一段代码:
在这里插入图片描述

从图中我们可以发现,输出的是两个地址,且是函数test的地址,那么指针存储的是地址,那么指针也能存储函数。
那存储的方法是什么呢?举个例子吧

函数是: int Text(int x,int y);
则定义函数指针: int (*p)(int ,int);
并且需要初始化指针:p=Text;
指针的使用: p(2,3);

由此看见函数指针的定义方法是: ret (*p)(args, …);
注:ret为函数的返回值类型,p是函数指针 ,(args,…)则是函数的形参列表,就相当于把函数名换成了指针


二、函数指针数组

数组是一个存放相同类型数据的存储空间,那函数指针数组,很明显是存放函数指针的数组。而函数指针则是存放的是函数地址,所以函数指针数组存放的是函数的地址
那又如何定义呢?

在进阶指针的上部里,我们可以看见 指针数组:int* arr[10] arr先和[]结合,为整形数组,而类型是int*,所以存放的是整形指针。
同理把函数指针存放入数组,例如:返回值类型 (p[长度])(形参,形参…) ,可以说是直接在函数指针的指针后面写[长度 ]

2.1代码实现

敲个代码促进理解

//函数指针数组,与函数相同的返回值类型,相同的形参列表
void (*p[4])(int, int) = { NULL,text1,text2,text3};

void text1(int x, int y)
{
	printf("hehe\n");
}
void text2(int x, int y)
{
	printf("hehe\n");
}
void text3(int x, int y)
{
	printf("hehe\n");
}
int main()
{
	int a = 0;
	scanf("%d", &a);	//当a=1时,调用text1
	p[a](2, 3); 		//当a=2时,调用text2........
}

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

顾名思义,指针指向一个数组,数组里是存放着函数的地址 。

函数指针数组:void (* *p[4])(int, int) = { NULL,text1,text2,text3};
则指针是:int( * (*ppf)[5])(int,int)=&p;


四、回调函数

回调函数:通过函数指针调用的函数,而具体例子则是使用库函数中的快排函数qsort
简单的说就是:调用一个函数A,传参里有函数B,而接收的是函数指针,然后在A函数里通过函数指针再调用函数B

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

void cale(int(*p)(int, int))
{
	int x = 0;
	int y = 0;
	printf("请输入2个数");
	scanf("%d %d", &x, &y);
	printf("%d\n",p(x, y)); //函数指针再调用对应的函数
}

int main()
{

	cale(add);
	//调用cale函数 传add函数,int(*p)(int, int)接收		
	cale(sub);

	cale(mul);
	return 0;
}

现在解释一下快排函数qsort,存在标准库函数里,头文件是<stdlib.h>
void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );

void *base接收的是首地址,size_t num接收的是字节大小,size_t width接收的是元素的大小,int (__cdecl *compare )(const void *elem1, const void *elem2 ) 这个很明显接收的是函数。

用途:排列元素顺序。
我们可以使用 冒泡排序 的方法来实现qsort函数,对qsort进行一个深入了解

4.2冒泡排序实现qsort代码:

int cmp_int(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}
void swap(char* q, char* w, int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char trm = *q;
		*q = *w;
		*w = trm;
		q++;
		w++;
	}
}

void bubblesort(void* base, size_t a, size_t width, int(*p)(const void* e1, const void* e2))
{

	for (size_t i = 0; i < a - 1; i++)
	{
		for (size_t j = 0; j < a - i - 1; j++)
		{
			if (p((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				swap((char*)base + j * width, (char*)base + width * (j + 1), width);
			}
		}
	}
}

int main()
{
	int arr[] = { 3,2,4,8,1,6,9,7,5,41 };
	int a = sizeof(arr) / sizeof(arr[0]);
	//实现qsort函数
	bubblesort(arr, a, sizeof(arr[0]), cmp_int);
	for (int i = 0; i < a; i++)
	{
		printf("%d ", arr[i]);
	}
}

而如果使用qsort函数则更为简便,比较大小之后,会自动帮你排序

4.3qsort快排代码:

int cmp_int(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
     //当大于0;则e1
}

void Text2()
{
	int arr[] = { 3,2,4,8,1,6,9,7,5,41 };
	int a = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, a, sizeof(arr[0]), cmp_int);
	for (int i = 0; i < a; i++)
	{
		printf("%d ", arr[i]);
	}
}

int main()
{
	Text2();
}

在qsort中的com_int函数传递2个参数去比较时,需要传递的是地址,比较之后确定位置。
如果返回值 < 0,则表示 s1 小于 s2。 元素不互换
如果返回值 > 0,则表示 s1 大于 s2。 元素互换
如果返回值 = 0,则表示 s1 等于 s2。 元素不互换
而比较完后,会自动传递下一位元素与下下一位元素比较

数组和函数与指针的深层关系介绍完了,若有不懂,评论区留言或者私聊我哦。

  • 15
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

tq02

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

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

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

打赏作者

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

抵扣说明:

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

余额充值