当前位置: 首页 > news >正文

老会计手把手教做帐官方网站彩票网站建设要多少钱

老会计手把手教做帐官方网站,彩票网站建设要多少钱,导购网站做基础销量,成都快速建网站目录 思维导图 回调函数 案例1—计算器 案例2—qsort函数 关于qsort函数 演示qsort函数的使用 案例3—冒泡排序 整型数据冒泡排序 回调函数搞定各类型冒泡排序 cmp_int比较大小 cmp传参数 NO1. NO2. 解决方案 交换swap 总代码 今天我们学习指针难点之回调函数…

目录

思维导图

回调函数

案例1—计算器

案例2—qsort函数

关于qsort函数  

演示qsort函数的使用

案例3—冒泡排序 

整型数据冒泡排序

回调函数搞定各类型冒泡排序

cmp_int比较大小

 cmp传参数

NO1.

NO2.

解决方案

交换swap

总代码


今天我们学习指针难点之回调函数🆗🆗🆗。

首先我们用思维导图回顾一下前面的内容。

思维导图

回调函数

回调函数就是一个通过函数指针调用的函数。

如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数

回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

案例1—计算器

就前文我们学习的计算器,我们再用回调函数来解决一下!🆗🆗🆗

#define _CRT_SECURE_NO_WARNINGS 1
//计算器
#include<stdio.h>
void meau()
{printf("**************************\n");printf("** 1.add   2.sub      ****\n");printf("** 3.mul   4.div      ****\n");printf("** 0.exit            *****\n");printf("**************************\n");
}
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 main()
{int input = 0;int x = 0;int y = 0;int ret = 0;do{meau();printf("请选择>");scanf("%d", &input);switch (input){case 1:printf("请输入2个操作数:");scanf("%d %d", &x, &y);ret = Add(x, y);printf("ret=%d\n", ret);break;case 2:printf("请输入2个操作数:");scanf("%d %d", &x, &y);ret = Sub(x, y);printf("ret=%d\n", ret);break;case 3:printf("请输入2个操作数:");scanf("%d %d", &x, &y);ret = Mul(x, y);printf("ret=%d\n", ret);break;case 4:printf("请输入2个操作数:");scanf("%d %d", &x, &y);ret = Div(x, y);printf("ret=%d\n", ret);break;case 0:printf("退出游戏");break;default:printf("选择错误,重新选择\n");break;}} while (input);return 0;
}

回调函数 

#define _CRT_SECURE_NO_WARNINGS 1
//计算器
#include<stdio.h>
void meau()
{printf("**************************\n");printf("** 1.add   2.sub      ****\n");printf("** 3.mul   4.div      ****\n");printf("** 0.exit            *****\n");printf("**************************\n");
}
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 calc(int(*p)(int, int))//函数指针传参
{int x = 0;int y = 0;printf("请输入两个操作数\n");scanf("%d %d", &x, &y);int ret = p(x, y);//函数调用printf("ret=%d\n", ret);
}
int main()
{int input = 0;do{meau();printf("请选择>\n");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("退出游戏");break;default:printf("选择错误,重新选择\n");break;}} while (input);return 0;
}

解释如下: 

在main函数中,没有直接去调用函数。而是把函数指针传参给另外的一个函数calc,在calc内部使用函数指针调用,通过函数指针就可以找到指针指向的函数,此刻被指向的函数就是回调函数。

像上图所示,通过calc函数调用Add函数指针,找到Add函数,就把Add函数称为回调函数

calc称为回调函数的机制

老板>>组长>>员工

案例2—qsort函数

那出了上面回调函数的案例,还有一个经典回调函数的案例:qsort

 qsort是一个库函数,底层使用的是快速排序的方式,对不同数据进行排序的。

这个函数可以直接使用。

这个函数可以用来排序任意类型的数据。

对数据进行排序方法很多:

冒泡排,序选择排序,插入排序,快速排序等等。 

关于qsort函数  

关于qsort函数的点--->qsort - C++ Reference (cplusplus.com)

需要包含头文件#include<stdlib.h>

  •  排序整型数组,两个整型可以直接使用>比较
  • 排序结构体数组,两个结构体的数据可能不能直接使用>比较

也就是不同类型的数据,比较大小的方法是有差异的

最后一个参数,排序不同数据的重要点,需要封装不同的函数去比较不同的数据的大小

void qsort(void* base, //指向了待排序数组第一个元素的首地址size_t num, //待排序数组的元素个数size_t size,//每个待排序数组元素的大小int (*compar)(const void* e1, const void* e2));
//函数指针,compar指向了一个函数,这个函数是用来比较两个元素的大小,
//e1和e2存放的是两个元素的地址
//在qsort内部调用这个函数,指向这个函数,这个函数就被称为回调函数
// 
//qsort内部怎么排序我们不需要过多去探讨
//const也暂不做讲解//因为不知道要比较的元素类型,所以我们使用void*指针的类型,来统一存放各种类型的指针

那怎样通过元素地址,去比较两个元素数据的大小呢? 

以int的数据为例:将void*类型的数据强制转化成(int*),再作差

当e1>e2,函数返回>0的值;

当e1<e2,函数返回<0的值;

当e1=e2,函数返回=0

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

那有人询问为什么不直接对元素地址const void* e1和 const void* e2解引用?

作为void*指针不能直接解引用。

void* 类型的指针—不能进行解引用操作符,也不能进行+-整数的操作
void* 类型的指针是用来存放任意类型数据的地址
void* 无具体类型的指针
void*和int*和char*一样都是指针类型

#include<stdio.h>
int main()
{char a = 'x';char* pa = &a;int b = 1;void* p = &b;//存放int*p = &a;//存放char*return 0;
}

演示qsort函数的使用

#include<stdio.h>
#include<stdlib.h>
void print(int arr[], int sz)
{int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}
}void qsort(void* base, size_t num,size_t size,int (*compar)(const void*, const void*));void compar_int(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;
}
void test1()
{int arr[] = { 10,9,8,7,6,5,4,3,2,1 };int sz = sizeof(arr) / sizeof(arr[0]);print(arr, sz);printf("\n");qsort(arr, sz, sizeof(arr[0]), compar_int);print(arr, sz);
}int main()
{test1();test2();return 0;
}

以上我只是以整型为例,结构体数据数组也是一样的逻辑,大家可以自行分析。

下面结构体:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>//?void qsort(void* base,size_t num,size_t size,int (*compar)(const void*, const void*));struct Stu
{char name[20];int age;
};
//结构体数据怎么比较呢?
//按照年龄比较
//按照名字比较//按照年龄
void compar_stu_by_age(const void* e1, const void* e2)
{return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;//return (*(struct Stu*)e1).age - (*(struct Stu*)e2).age;
}
void test2()
{struct Stu arr[] = { {"zhangsan",20},{"lisi",30},{"wangwu",12} };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), compar_stu_by_age);}
//按照名字
void compar_stu_by_name(const void* e1, const void* e2)
{return ((struct Stu*)e1)->name - ((struct Stu*)e2)->name;//return (*(struct Stu*)e1).name - (*(struct Stu*)e2).name;
}
void test2()
{struct Stu arr[] = { {"zhangsan",20},{"lisi",30},{"wangwu",12} };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), compar_stu_by_name);}int main()
{test2();return 0;
}

只要qsort函数使用得当,可以对任何数据进行排序!🆗🆗 

案例3—冒泡排序 

(使用回调函数,模拟实现qsort(采用冒泡的方式)

整型数据冒泡排序

(这种方式只能排列整数,存在局限性)

//冒泡排序
#include<stdio.h>
void bubble_sort(int arr[], int sz)
{int i = 0;for (i = 0; i < sz - 1; i++){int j = 0;for (j = 0; j < sz - 1 - i; j++){if (arr[j] > arr[j + 1]){int tmp = 0;tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}
}
void print_arr(int arr[], int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}
}
int main()
{int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz);print_arr(arr, sz);
}

回调函数搞定各类型冒泡排序

 经过分析冒泡排序,我们得到

void bubble_sort(void* base, size_t num, size_t size,

                            int (*cmp)(const void* e1, const void* e2))

cmp_int比较大小

以整型为例 

int (*cmp)(const void* e1, const void* e2)

e1是一个指针,存放了一个要比较的元素的地址。

e2是一个指针,存放了一个要比较的元素的地址。

e1指向的元素>e2指向的元素,返回>0的数字。

e1指向的元素<e2指向的元素,返回>0的数字。

e1指向的元素==e2指向的元素,返回>0的数字。

cmp是函数指针指向一个我们程序想要待排序的数组。

将比较函数cmp_int的地址传给cmp即可。

//比较大小
void cmp_int(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;
}
//这里就是将cmp_int的地址在调用函数bubble_sort时将其传过去即可。
 cmp传参数
NO1.

有同学提出直接对待排序的数组首元素地址解引用找到e1的地址,然后通过一个元素的大小或者+1可以找到e2的地址,可以吗?当然不可以

  • 作为void*指针不能直接解引用。

    void* 类型的指针—不能进行解引用操作符,也不能进行+-整数的操作
    void* 类型的指针是用来存放任意类型数据的地址
    void* 无具体类型的指针
    void*和int*和char*一样都是指针类型

NO2.

有同学又提出那将void*的指针强制转换成我们想要的int*或double*等,再+1可以吗?           不可以,理由就是,强制转换存在在于我们公共的bubble_sort排序函数中时不能随着待排序的数组数据类型不同而改变,我们只能改变不同数据类型的不同比较方法。

解决方案

 

			//if(arr[j]>arr[j+1])if (cmp( (char*)base+j*size,(char*)base+(j+1)*size )>0){int tmp = 0;tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}
交换swap

当我们只知道元素的起始地址,并不知道元素的类型所以我们并没有合适的中间值类型tmp创建。所以我们换一种方法。

我们已知元素e1和e2的起始地址每个元素的大小

那我们可以用一个一个char类型的数据交换用for循环

直到每个元素的大小size结束,也就是元素交换完成。

 

//交换数据
void change(char* buf1, char* buf2,size_t size)
{char i = 0;for (i = 0; i < size; i++){char tmp = 0;tmp = *buf1;*buf1=*buf2;*buf2 = tmp;buf1++;//*buf1++buf2++;//*buf2++}
}
总代码
//冒泡排序
#include<stdio.h>
void print_arr(int arr[], int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}
}void bubble_sort(void* base, size_t num, size_t size,int (*cmp)(const void* e1, const void* e2))
{int i = 0;for (i = 0; i < num - 1; i++){int j = 0;for (j = 0; j < num - 1 - i; j++){//if(arr[j]>arr[j+1])if (cmp( (char*)base+j*size,(char*)base+(j+1)*size )>0){change((char*)base + j * size, (char*)base + (j + 1) * size, size);}}}
}
//交换数据
void change(char* buf1, char* buf2,size_t size)
{char i = 0;for (i = 0; i < size; i++){char tmp = 0;tmp = *buf1;*buf1=*buf2;*buf2 = tmp;buf1++;//*e1++buf2++;//*e2++}
}
//比较大小
void cmp_int(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;//>0
}void test1()
{int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };int sz = sizeof(arr) / sizeof(arr[0]);print_arr(arr, sz);printf("\n");bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);print_arr(arr, sz);
}int main()
{test1();
}

当然我们也可以用结构体类型去测试一下! 🆗🆗试试

✔✔✔✔✔最后,感谢大家的阅读,若有错误和不足,欢迎指正!旗鼓相当

代码------→【gitee:唐棣棣 (TSQXG) - Gitee.com】

联系------→【邮箱:2784139418@qq.com】

http://www.yayakq.cn/news/15982/

相关文章:

  • 局域网内网站建设的步骤过程南宁手机企业网站定制
  • 网站建设放什么会计科目烟台怎么做网站
  • 设计的网站源代码怎么做免费网站建设策划
  • 做设计开店的网站建设美食网站
  • 高端网站建设 aspx东莞南城网站设计
  • 做网站能用ai做吗做熟食的网站美食网站
  • 网站建设ppt答辩h5响应式网站建设报价
  • discuz可以做商城网站吗页面推广策略有哪些
  • 电子元器件在哪个网站上做域名服务商怎么查询
  • 温州新公司做网站用html做卖珠宝的网站
  • 绍兴做外贸网站的公司企业网站源码交易
  • 安庆市城乡建设网站wordpress 不同页面
  • 成都网站建设开wordpress固定链
  • 管理系统网站加强机构编制网站建设力度
  • aspcms自适应网站今天的新闻联播内容摘抄
  • 郑州网站建设报价表跨境电商平台入驻条件及费用
  • asp网站后台安全退出wordpress 纯代码 雪花
  • 上海门户网站一网通办seo如何进行优化
  • 什么软件制作网站快石家庄网络营销网站推广
  • 做招聘网站的怎么让人注册简历做个企业网站 优帮云
  • 合肥网站建设5k5互联网营销师证书是国家认可的吗
  • 如何做起一个网站推广汉服网站设计目的
  • 个人网站免费做php做网站完整视频
  • 网站界面设计论文网站建站目标
  • 网页设计模板网站免费肃宁县网站建设价格
  • 求职网站开发多少钱百度电话怎么转人工
  • 长宁区网站建设网站制作网站权重怎么提高
  • 公司网站备案需要哪些资料网站的总体风格包括
  • 无忧企业网站系统怎么开一个做网站的工作室
  • 站长之家关键词挖掘温州门户网站