zl程序教程

您现在的位置是:首页 >  后端

当前栏目

C语言进阶-回调函数

C语言 函数 进阶 回调
2023-09-27 14:22:51 时间

目录

前言

回调函数

回调型计算器

回调冒泡排序(模拟qsort库函数)

qsort函数原型

compar参数

代码演示

 冒泡排序(bubble_sort)


前言


  • 本文主要讲解
  • 回调函数的理解
  • 回调实现计算器
  • qsort各种功能的使用
  • 冒泡排序各种功能的实现

回调函数


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

回调型计算器

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

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;
}

int moveleft(int x, int y)
{
	return x << y;
}

int moveright(int x, int y)
{
	return x >> y;
}

int mici(int x, int y)
{
	if (y >= 2)
		return x * mici(x, y - 1);
	return x;
}

int xor(int x, int y)
{
	return x ^ y;
}
//写出相应功能的函数

void menu()
{
	printf("************************\n");
	printf("***1.add        2.sub***\n");
	printf("***3.mul        4.div***\n");
	printf("*5.moveleft 6.moveright*\n");
	printf("***7.xor       8.mici***\n");
	printf("******** 0.exit ********\n");
	printf("************************\n");
}

void cola(int (*p)(int, int))//回调函数 形参为函数指针,接受函数地址
{
	int x, y;
	printf("请输入两个操作数:\n");
	scanf("%d %d", &x, &y);
	int ret = p(x, y);//利用函数指针,即函数地址来调用相应的函数
	printf("得到结果为:%d\n", ret);
}

int main()//计算器逻辑模拟
{
	int intput = 0;
	do {
		menu();
		printf("请选择:\n");
		scanf("%d", &intput);
		switch (intput)
		{
		case 0:
			printf("退出成功!\n");
			break;
		case 1:
			cola(add);//传入的函数降维成函数地址
			break;
		case 2:
			cola(sub);
			break;
		case 3:
			cola(mul);
			break;
		case 4:
			cola(div);
			break;
		case 5:
			cola(moveleft);
			break;
		case 6:
			cola(moveright);
			break;
		case 7:
			cola(xor);
			break;
		case 8:
			cola(mici);
			break;
		default:
			printf("输入错误!\n");
			break;
		}
	} while (intput);
	return 0;
}
  • 示例2:

回调冒泡排序(模拟qsort库函数)

  • 首先演示一下qsort函数的使用

qsort函数原型

void qsort(
    void *base,
    size_t nmemb,
    size_t size,
    int (*compar)(const void *, const void *)
    );
  •   头文件:<stdlib.h>
  •   函数功能:qsort()函数的功能是对数组进行排序,数组有nmemb个元素,每个元素大小为size
  •   参数base : base指向数组的起始地址,通常该位置传入的是一个数组名
  •   参数nmemb :nmemb表示该数组的元素个数
  •   参数size :size表示该数组中每个元素的大小(字节数)
  •   参数(*compar)(const void *, const void *):此为指向比较函数的函数指针
  •   函数返回值:无

compar参数

定义:实现比较功能的函数

注意:两个形参是const void *型(便于接收不同指针类型参数)

内部需将const void *型转换成实际类型(访问元素对应的空间大小,空类型指针无法反问)

int compar(const void *p1, const void *p2)
{
}
  •   如果compar返回值小于0(< 0),那么p1所指向元素会被排在p2所指向元素的前面
  •   如果compar返回值等于0(= 0),那么p1所指向元素与p2所指向元素的顺序不确定
  •   如果compar返回值大于0(> 0),那么p1所指向元素会被排在p2所指向元素的后面
  • 方法一
 int compare (const void * a, const void * b)
 {
   if ( *(MyType*)a <  *(MyType*)b ) return -1;
   if ( *(MyType*)a == *(MyType*)b ) return 0;
   if ( *(MyType*)a >  *(MyType*)b ) return 1;
 }

注意:MyType是换成实际数组元素的类型

  • 方法二:

以实际元素是int为例

 int compare (const void * a, const void * b)
 {
     return ( *(int*)a - *(int*)b );
 }

注意:如果变量 a 指向一个较小的负整型数,b指向一个较大的正整型数,(*(int*)a - *(int*)b) 表达式会计算出一个正数,因此,比较int类型元素的大小可以使用大于、小于运算符来比较

代码演示

#include<stdio.h>
#include<stdlib.h>//qasort函数头文件
#include<string.h>//strcmp函数头文件

struct stu//构建结构体,结构体同样是一种类型
{                //注意结构体类型的作用域,放在前面,后面才能使用结构体
	char name[9];
	int age;
};

int cmp_int(const void* e1, const void* e2)//要实现多功能qsort,所以传入的地址类型会有多种形式
{                                          //而void*空指针类型可以来接收不同的类型,便于保持参数一致性,构成回调函数的特点,形参和返回类型一致
	return *(int*)e1 - *(int*)e2;//知道该使用什么类型,就将其先强制转成对应类型(访问空间大小与指针类型有关),再解引用得到空间内容        
}//e1 - e2为升序,e2-e1为降序

int cmp_char(const void* e1, const void* e2)
{
	return *(char*)e1 - *(char*)e2;//字符类型直接比较,比较的是对应的ASCII码值
}

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

int cmp_stu_name(const void* e1, const void* e2)
{
	return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);//name是字符串,比较需要使用strcmp函数
}//结构体指针->成员 这样访问便捷

int cmp_stu_age(const void* e1, const void* e2)
{
	return ((struct stu*)e1)->age - ((struct stu*)e2)->age;//age为整型,直接比较
}

int main()
{
	char ch[] = { 'e','g','a','f','p','b' };
	int arr1[] = { 6,4,5,9,1,2,4,6,3 };
	double arr2[] = { 5.00,4.00,9.00,3.00,7.00 };
	struct stu s[] = { {"zhangsan",18},{"lisi",20},{"wangwu",22} };
	qsort(ch, sizeof(ch) / sizeof(ch[0]), sizeof(ch[0]), cmp_char);
	for (int i = 0; i < sizeof(ch) / sizeof(ch[0]); i++)
	{
		printf("%c ", ch[i]);
	}printf("\n");

	qsort(arr1, sizeof(arr1) / sizeof(arr1[0]), sizeof(arr1[0]), cmp_int);//最后的形参是函数,传入的是函数地址,qsort也相当于是一个回调函数
	for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
	{
		printf("%d ", arr1[i]);
	}printf("\n");

	qsort(arr2, sizeof(arr2) / sizeof(arr2[0]), sizeof(arr2[0]), cmp_double);
	for (int i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++)
	{
		printf("%lf ", arr2[i]);
	}printf("\n");

	qsort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]), cmp_stu_name);
	for (int i = 0; i < sizeof(s) / sizeof(s[0]); i++)
	{
		printf("%s ", s[i].name);
	}printf("\n");

	qsort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]), cmp_stu_age);
	for (int i = 0; i < sizeof(s) / sizeof(s[0]); i++)
	{
		printf("%d ", s[i].age);
	}printf("\n");
                //qsort函数相应比较的功能函数需要自己写
	return 0;
}
  • 输出结果:

 冒泡排序(bubble_sort)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct stu
{
	char name[9] ;
	int age;
};

void sway(char* e1, char* e2,int size)//交换函数 使用char*指针指向一个字节,还需要宽度,才能将元素对应的空间完全交换,实现交换元素
{
	for (int k = 0; k < size; k++)
	{
		char temp = *e1;
		*e1 = *e2;//解引用实现内容交换
		*e2 = temp;
		e1++;//指向下一个字节空间地址
		e2++;
	}
}

void bubble_sort(void* base, int count, int size, int (*cmp)(const void*, const void*))//模拟qsort函数
{
	for (int i = 0; i < count - 1; i++)//趟数
	{
		for (int j = 0; j < count - 1 - i; j++)//一趟中相邻比较对数
		{
			if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)//调用函数 升序
			{
				sway((char*)base + j * size, (char*)base + (j + 1) * size,size);//不符合就交换
			}
		}
	}
}

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

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

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

int cmp_stu_name(const void* e1, const void* e2)
{
	return strcmp(((struct stu*)e1)->name ,((struct stu*)e2)->name);
}

int cmp_stu_age(const void* e1, const void* e2)
{
	return ((struct stu*)e1)->age-((struct stu*)e2)->age;
}
//实现比较不同类型函数的功能

int main()
{
	char ch[] = {'e','g','a','f','p','b'};
	int arr1[] = { 6,4,5,9,1,2,4,6,3 };
	double arr2[] = { 5.00,4.00,9.00,3.00,7.00 };
	struct stu s[] = { {"zhangsan",18},{"lisi",20},{"wangwu",22} };
	bubble_sort(ch, sizeof(ch) / sizeof(ch[0]), sizeof(ch[0]), cmp_char);
	for (int i = 0; i < sizeof(ch) / sizeof(ch[0]); i++)//打印
	{
		printf("%c ", ch[i]);
	}
	printf("\n");

	bubble_sort(arr1, sizeof(arr1) / sizeof(arr1[0]), sizeof(arr1[0]), cmp_int);
	for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
	{
		printf("%d ", arr1[i]);
	}
	printf("\n");

	bubble_sort(arr2, sizeof(arr2) / sizeof(arr2[0]), sizeof(arr2[0]), cmp_double);
	for (int i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++)
	{
		printf("%lf ", arr2[i]);
	}
	printf("\n");

	bubble_sort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]), cmp_stu_name);
	for (int i = 0; i < sizeof(s) / sizeof(s[0]); i++)
	{
		printf("%s ", s[i].name);
	}
	printf("\n");

	bubble_sort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]), cmp_stu_age);
	for (int i = 0; i < sizeof(s) / sizeof(s[0]); i++)
	{
		printf("%d ", s[i].age);
	}
	printf("\n");

	return 0;
}