目录
前言
- 本文主要讲解
- 回调函数的理解
- 回调实现计算器
- 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;
}