关键词搜索

源码搜索 ×
×

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

发布2023-01-07浏览419次

详情内容


前言

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


一、函数指针

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

从图中我们可以发现,输出的是两个地址,且是函数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;
    }
    
      22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    现在解释一下快排函数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]);
    	}
    }
    
      22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    而如果使用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。 元素不互换
      而比较完后,会自动传递下一位元素与下下一位元素比较

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

      相关技术文章

      点击QQ咨询
      开通会员
      返回顶部
      ×
      微信扫码支付
      微信扫码支付
      确定支付下载
      请使用微信描二维码支付
      ×

      提示信息

      ×

      选择支付方式

      • 微信支付
      • 支付宝付款
      确定支付下载