前言
在指针进阶详解(上)中,我们已经介绍了部分指针进阶相关知识,接下来我们将继续介绍指针进阶相关知识。
1. 函数指针
我们知道数组指针,是一个指向数组的指针。同理,函数指针是一个指向函数的指针。
既然是函数指针,就需要取出函数的地址。那函数的地址如何得到呢?
首先我们先看以下代码:
void test() { printf("hehe\n"); } int main() { printf("%p\n", test); printf("%p\n", &test); return 0; }
运行结果:
输出的两个地址就是test()函数的地址。那函数的地址如何保存起来呢?
下面再来看看这段代码:
void test() { printf("hehe\n"); } //下面pfun1和pfun2那个有能力存放test函数的地址呢? void (*pfun1)(); void* pfun2();
首先,能存储地址,要求pfun1或pfun2是指针,那哪个可以?答案是:
pfun1可以存放。pfun1先和*结合,说明pfun1是一个指针;在和()结合,说明指针指向的是一个函数;最后和int结合,说明函数的返回类型是int。即,fun1指向一个返回int类型数据的函数。
1.1 两端有趣代码
//代码一 (*(void (*)())0)() //解读:首先假设有一个数子:OX23FC11。如果仅是这个数字,我们可以认为他是一个地址,也可以是一个16进制数字 //同理,这里0也可以理解为一个地址,只是值比较特殊为0 //1.将0强制类型转换为void(*)() //2.调用0处的函数 //代码二 void (*signal(int, void (*)(int)))(int); //signal函数的一个声明 //1.signal函数有两个参数,第一个参数是int类型;第二个参数为int无返回值的函数指针类型 //2.signal函数的返回值是也是void(*)(int)函数指针类型,该函数指针指向的函数有一个int类型的参数,返回类型是void
代码二太复杂,如何简化呢?
typedef void(*pfun_t)(int) pfun_t signal (int, pfun_t)
2. 函数指针数组
数组是一个存放相同类型数据的存储空间,我们已经介绍过指针数组,比如:
int *arr[10]; //数组的每个元素是int*
那要把函数的地址存放到一个数组中,那这个数组就叫函数指针数组。
那函数指针数组如何定义?
int (*parr1[10])(); //parr1先和[]结合,说明parr1是一个数组;数组的每个元素是int (*)()函数指针类型。
2.1 函数指针数组的用途之一:转移表
使用函数指针数组实现简单计算器:
#include <stdio.h> int add(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; } int mul(int a, int b) { return a * b; } int div(int a, int b) { return a / b; } int main() { int input = 0; int (*p[5])(int x, int y) = { NULL, add, sub, mul, div };//转移表 do { int x = 0; int y = 0; int ret = 0; printf("XXXXXXXXXXXXXXXXXXXXXX\n"); printf("XXXX 1.add 2.sub XXXX\n"); printf("XXXX 3,mul 4.div XXXX\n"); printf("XXXX 0.exit XXXXX\n"); printf("XXXXXXXXXXXXXXXXXXXXXX\n"); printf("请选择:>\n"); scanf("%d", &input); if (input >= 1 && input <= 4) { printf("输入操作数:"); scanf("%d %d", &x, &y); ret = p[input](x, y); printf("%d\n", ret); } else { printf("输入错误,重新输入\n"); } } while (input); return 0; }
3. 指向函数指针数组的指针
指向函数指针数组的指针是一个指针,指针指向一个数组,数组的元素是数组指针。
如何定义?
void test(const char* str) { printf("%s\n", str); } int main() { //函数指针pfun void (*pfun)(char*) = test; //函数指针的数组pfunArr void (*pfunArr[5])(char*) = test; //指向函数指针的数组pfunArr的指针ppfunArr void (*(*pfunArr)[5])(char*) = test; return 0; }
- 不建议初学者直接上手写最终结果,而是根据上面过程一步步修改添加得到。
4. 回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是有函数的实现方直接调用,而是在特定的事件或条件发生时有另一方调用,用于对该事件或条件进行响应。
回调函数的应用
#include <stdio.h> #include <stdlib.h> //库函数中有一个函数qsort()是用来排序的 int cmp(const void* p1, const void* p2) { //升序 return *(int*)p1 - *(int*)p2; //降序 //return *(int*)p2 - *(int*)p1; } int main() { int arr[] = { 12,43,87,34,56,3,5,1,86 }; int sz = sizeof(arr) / sizeof(arr[0]); qsort(arr, sz, sizeof(arr[0]), cmp);//通过指针调用cmp函数,所以cmp()函数为回调函数 for (int i = 0; i < sz; i++) { printf("%d ", arr[i]); } return 0; }
5. 结尾
本篇博客到此就结束了。创作不易,如果对你有帮助记得三连哦!感谢您的支持!!