前言
`在上篇,我们已经讲了指针和数组的深入关系,现在讲讲指针和函数的深入关系。
一、函数指针
什么是函数指针?例如数组指针,是指向数组的指针。那么函数指针则是 指向函数的指针,或许有人说指针存储的是地址,那么函数也有地址嘛?我们先来看一段代码:
从图中我们可以发现,输出的是两个地址,且是函数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。 元素不互换
而比较完后,会自动传递下一位元素与下下一位元素比较
数组和函数与指针的深层关系介绍完了,若有不懂,评论区留言或者私聊我哦。