详解C语言—进阶指针(二)

目录

1.函数指针数组

用途:转移表

2.指向函数指针数组的指针

3.回调函数

案例:

 qsort函数

排序数组 :

 排序结构体:


1.函数指针数组

数组是一个存放相同类型数据的存储空间,

那要把函数的地址存到一个数组中,那这个数组就叫函数指针数组

那函数指针的数组如何定义呢?

int (*pf[10])(int, int);

 pf与[10]结合,说明pf是数组,数组的内容是int(*)( )类型的函数指针。

数组大小可以不写,但一定要赋初值。

用途:转移表

计算器中我们可以用到转移表 。

首先我们写出实现计算器“加减乘除”功能的函数。

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;
}
int Div(int x, int y)
{
	return x / y;
}

 再写个具有提示作用的开始菜单。

void menu()
{
	printf("****************************\n");
	printf("***  1.add        2.sub  ***\n");
	printf("***  3.mul        4.div  ***\n");
	printf("***  0.exit              ***\n");
	printf("****************************\n");
}

在计算器中实现转移表,需要用到函数指针数组。

int main()
{
	int input = 0;
	int x = 0,y = 0;
	do {
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		int (*pfArr[])(int, int) = { NULL,Add,Sub,Mul,Div };
		if (input == 0)
			printf("退出计算器\n");
		else if (input >= 1 && input <= 4) {
			printf("请输入两个整数\n");
			scanf("%d %d", &x, &y);
			int ret = pfArr[input](x, y);
			printf("ret = %d\n", ret);
		}
		else
			printf("选择错误,重新选择!\n");
	} while (input);
	return 0;
}

通过do—while语句开始执行程序,由input的值觉得程序是否运行。

首先输入input的值,然后创建函数指针数组int (*pfArr[ ])(int, int),

并为其赋值  {NULL,Add,Sub,Mul,Div },数组下表为0处赋值NULL,以便输入input值从1开始。

int (*pfArr[ ])(int, int) = { NULL,Add,Sub,Mul,Div };这就是转移表

将加减乘除函数储存(转移)到pfArr[ ]函数指针数组中。

然后通过input的值选择是否进行计算、进行什么计算

如果进行计算,则输入参与运算的两个整数,通过int ret = pfArr[input](x, y)调用函数指针数组中储存的对应函数,并传输输入的”x“和“y”进行计算。

最后输出计算结果ret的值。

2.指向函数指针数组的指针

指向函数指针数组的指针是一个 指针
指针指向一个 数组 ,数组的元素都是 函数指针 

void test(const char* str)
{
 printf("%s\n", str);
}
int main()
{
    //函数指针pfun
    void (*pfun)(const char*) = test;
    //函数指针的数组pfunArr
    void (*pfunArr[5])(const char* str);
    pfunArr[0] = test;
    //指向函数指针数组pfunArr的指针ppfunArr
    void (*(*ppfunArr)[5])(const char*) = &pfunArr;
    return 0;
}

3.回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个
函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数
的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进
行响应。

案例:

请看这段代码:
void calc(int (*pf)(int, int))
{
	int x = 0, y = 0;
	int ret = 0;
	printf("请输入2个操作数:");
	scanf("%d %d", &x, &y);
	ret = pf(x, y);
	printf("ret = %d\n", ret);
}

int main()
{
	int input = 0;
	int x = 0, y = 0;
	do {
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			calc(Add); break;
		case 2:
			calc(Sub); break;
		case 3:
			calc(Mul); break;
		case 4:
			calc(Div); break;
		case 0:
			printf("退出计算器\n");
			break;
		default:
			printf("选择错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

通过switch—case语句实现输入不同input值进行不同运算,每次都通过calc函数实现计算器功能。

然后创建calc函数,参数定义为一个函数指针pf,pf有两个整型参数,用于接收进行计算的两个整数,将不同功能的加减乘除函数作为参数通过传入calc函数,定义ret = pf(x, y)调用传入pf的函数,然后返回函数输出结果。

当需要进行对应计算时,将所需加减乘除函数作为参数传递给calc函数储存在函数指针pf中,通过自定义变量ret调用pf实现传入的对应加减乘除函数,这就是回调函数。 

 qsort函数

 qsort是一个库函数,包含在<stdlib.h>头文件中,底层使用快速排序的方式,对数据进行排序,可以直接使用,可以用来排序任意类型的数据。

//void* 类型指针不能进行解引用操作符,也不能进行+-整数的操作符
//void* 是用来存放任意类型数据的地址
//void*  无具体类型的指针
void qsort(void* base,  //待排序数组的第一个元素
			size_t num, //待排序数组的元素个数
			size_t size,//待排序数组中一个元素的大小
			int (* cmp)(const void* e1,const void* e2))//函数指针指向比较函数
			//e1和e2中存放的是需要比较的两个元素的地址
//排序整型数据,两个整型可以直接使用>比较
//排序结构体,两个结构体数据可能不能直接使用<>比较
//也就是不同类型数据,比较大小,方法有差异

排序数组 :

#include <stdio.h>
#include <stdlib.h>
void print_arr(int arr[], int sz)
{
	for (int i = 0; i < sz; i++) {
		printf("%d", arr[i]);
	}
	printf("\n");
}

int cmp_int(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}

void test1()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	print_arr(arr, sz);
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	print_arr(arr, sz);
}

int main()
{
	test1();
	return 0;
}
  1. 定义函数print_arr用于打印排序结果。
  2. 创建cmp_int比较函数,传入参数类型可以是任意, 使用 const 关键字修饰函数参数表示这些参数是只读的,无法修改.
  3. 将 e1 和 e2 强制转换为指向整数的指针 (int*)。e1 和 e2 通常被声明为 const void*,这是因为 qsort 函数要求比较函数的参数是 const void* 类型,因此在比较之前需要将它们强制转换回整数指针。
  4. *(int*)e1 和 *(int*)e2:这部分是解引用操作,它们将指针转换为指向的整数值。因为 e1 和 e2 已经被强制转换为整数指针,所以 *(int*)e1 和 *(int*)e2 分别表示两个整数。
  • 减法操作符用于计算两个整数之间的差值。
  • 整个表达式计算两个整数的差值,然后将结果返回。
  • 如果结果为正数,则表示第一个整数大于第二个整数。
  • 如果结果为负数,则表示第一个整数小于第二个整数。
  • 如果结果为零,则表示两个整数相等。

 排序结构体:

学会qsort之后,我们还可以排序各种类型,比如结构体类型。

#include <stdio.h>
#include <stdlib.h>
struct Stu
{
	char name[20];
	int age;
};

//结构体输出函数
void print_arrr(struct Stu arr[], int sz)
{
	for (int i = 0; i < sz; i++) {
		printf("%s: %d\n", arr[i].name, arr[i].age);
	}
}

 //按照年龄比较
int cmp_stu_by_age(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
void test2()
{
	struct Stu arr1[] = { {"zhangsan",20},{"lisi",30},{"王五",12} };
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	qsort(arr1, sz, sizeof(arr1[0]), cmp_stu_by_age);
	print_arrr(arr1, sz);
}
 
 //按照名字比较
#include <string.h>
int cmp_stu_by_name(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
void test3()
{
	struct Stu arr1[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 12} };
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	qsort(arr1, sz, sizeof(arr1[0]), cmp_stu_by_name);
	print_arrr(arr1, sz);
}
int main()
{
	test2();
	test3();
	return 0;
}

注意:结构体成员 name 和 age 不需要解引用操作,因为它们是直接存储在结构体中的数据,而不是指针。

下面让我们进入C语言—进阶指针(三)的学习吧!!!

猜你喜欢

转载自blog.csdn.net/m0_73800602/article/details/132765169