指针进阶详解(下)
- 前言
- 1. 函数指针
- 1.1 两端有趣代码
- 2. 函数指针数组
- 2.1 函数指针数组的用途之一:转移表
- 3. 指向函数指针数组的指针
- 4. 回调函数
- 5. 结尾
前言
在指针进阶详解(上)中,我们已经介绍了部分指针进阶相关知识,接下来我们将继续介绍指针进阶相关知识。
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;
}
冒泡排序模拟实现qsort()函数
5. 结尾
本篇博客到此就结束了。创作不易,如果对你有帮助记得三连哦!感谢您的支持!!
指针进阶详解(上)
指针和数组笔试题解析