指针进阶详解(下)

前言

指针进阶详解(上)中,我们已经介绍了部分指针进阶相关知识,接下来我们将继续介绍指针进阶相关知识。

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. 结尾

本篇博客到此就结束了。创作不易,如果对你有帮助记得三连哦!感谢您的支持!!
指针进阶详解(上)
指针和数组笔试题解析

猜你喜欢

转载自blog.csdn.net/Zhenyu_Coder/article/details/131703049