前言
- 本文主要讲解
- 回调函数的理解
- 回调实现计算器
- 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; }vv
输出结果:
冒泡排序(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; }