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

C语言第17讲

回调函数

回调函数就是⼀个通过函数指针调⽤的函数

                当我们想写一个简易的计算机系统的时,会和先前写 扫雷 猜数字游戏 一样的模版

第一版 代码如下:

#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h>void print()
{printf("########################\n");printf("###   1.Add  2.Sum   ###\n");printf("###   3.Mul  4.Div   ###\n");printf("###       0.Exit     ###\n");printf("########################\n");
}int Add(int x, int y)
{return x + y;
}int Sum(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;do{print();printf("请选择:");scanf("%d", &input);int x = 0;int y = 0;int ret = 0;switch (input){case 1:printf("请输入两数:");scanf("%d %d", &x, &y);ret = Add(x, y);printf("%d\n", ret);break;case 2:printf("请输入两数:");scanf("%d %d", &x, &y);ret = Sum(x, y);printf("%d\n", ret);break;case 3:printf("请输入两数:");scanf("%d %d", &x, &y);ret = Mul(x, y);printf("%d\n", ret);break;case 4:printf("请输入两数:");scanf("%d %d", &x, &y);ret = Div(x, y);printf("%d\n", ret);break;case 0:printf("退出成功\n");break;default:printf("选择错误,请从选择\n");break;}} while (input);return 0;
}

                我们会发现发现在whitch 语句中的选择会有太多重复我进行第二版修改

第二版 代码如下:

#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h>void print()
{printf("########################\n");printf("###   1.Add  2.Sum   ###\n");printf("###   3.Mul  4.Div   ###\n");printf("###       0.Exit     ###\n");printf("########################\n");
}int Add(int x, int y)
{return x + y;
}int Sum(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 clac(int (*p_fun)(int, int))
{int x = 0;int y = 0;int ret = 0;printf("请输入两数:");scanf("%d %d", &x, &y);ret = p_fun(x, y);printf("%d\n", ret);
}int main()
{int input = 0;do{print();printf("请选择:");scanf("%d", &input);switch (input){case 1:calc(Add);break;case 2:calc(Sum);break;case 3:calc(Mul);break;case 4:calc(Div);break;case 0:printf("退出成功\n");break;default:printf("选择错误,请从选择\n");break;}} while (input);return 0;
}

                对比第一版,第二版,将重复的内容分装成了个函数,重复内容中,不同的是每次函数的调用,我们便将所需的函数指针传过去。

在我们分装的函数中,调用其他函数的方式便是函数回调(利用函数的地址去调用它)

                我们也可以利用 函数指针数组 去修改第一版代码

第三版 代码如下:

#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h>void print()
{printf("########################\n");printf("###   1.Add  2.Sum   ###\n");printf("###   3.Mul  4.Div   ###\n");printf("########################\n");
}int Add(int x, int y)
{return x + y;
}int Sum(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(*arr_fun[])(int, int) = {0,Add, Sum, Mul, Div};int input = 0;do{print();printf("请选择:");scanf("%d", &input);int x = 0;int y = 0;int ret = 0;printf("请输入两数:");scanf("%d %d", &x, &y);ret = arr_fun[input](x,y);printf("%d\n", ret);} while (input);return 0;
}

                第二版 修改的为 switch语言 重复内容,与第一版的内容没变

                第三版 修改的 switch语句 ,导致内容会有缺少,缺少在选择退出 和选择错误的程序

qsort函数

                在 qsort 先拿出冒牌排序

冒泡排序 代码如下:

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

                由此提出个问题:怎样排序才能不受限于类型

qsort 就是个排序功能库函数,底层是快速排序逻辑,不受限排列类型

qsort 函数的使用

                qsort 函数声明:

void qsort(void *base, size_t num, size_t size, int (*compar)(const void *, const void *));

                base 为待排序数组的开始地址

                num 为待排序数组的所有元素总数

                size 为元素所占内存大小

                compar 为比较函数 要求传输比较函数的指针 类型为 int (const void*, const void*);

在qsort 函数中需要返回值,只有返回值大于0时,才会进行替换        

                例1:利用sqort 排序升序整形数组

代码如下:

#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h>
#include <stdlib.h>							     // qsort 头文件int cmp_int(const void* p1, const void* p2)      // 待比较的两指针
{// 由于void* 类型不能直接解引用,不能+ - 整数return (*(int *)p1) - (*(int *)p2);          // 可以将其装换为可以进行 运算类型		
}int main()
{int arr[] = { 9,8,7,6,5,4,3,2,1 };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]),cmp_int);		 // 填入函数指针for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}

对比函数 已在 要比较两元素的开始

                将 p1 装换为准确类型是为了知道一个元素的所占内存大小 

                例2:利用qsort 排序结构体

                2.1:按名字排列结构体

代码如下:

#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>struct stu
{char name[20];int age;
};int cmp_str(const void* p1, const void* p2)
{return strcmp(((struct stu*)p1)->name, ((struct stu*)p2)->name);
}int main()
{struct stu s[] = {{"zhangsan",20},{"lisi",35},{"wangwu",18}};int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), cmp_str);return 0;
}

strcmp函数排序方式:(这个函数只会 两两比较,下面是这种方式操作下的举例)

                abc ,cde ,acd 先拿出第一个字符进行比较(底层是利用ASCII表)

                a 为 0x97 c为0x99

                c比a大 c最后

                两个未出先后的取出第二个字符

                b和c   c大于b

最后排序:

                abc     acd     cde         

              

对比函数 两指针指向的整个结构体,需要细化至结构体中的name

                使用((struct stu*)p1)后加   ->name

                在使用->时格式:指针 -> 成员名

                在使用 . 时格式:结构体变量名称 . 成员名

运行前:

运行后:

                2.1:结构体按年龄的比较

代码如下:

#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>struct stu
{char name[20];int age;
};int cmp_str(const void* p1, const void* p2)
{return (((struct stu*)p1)->age) - (((struct stu*)p2)->age);
}int main()
{struct stu s[] = {{"zhangsan",20},{"lisi",35},{"wangwu",18}};int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), cmp_str);return 0;
}

运行前:

运行后:

模仿qsort来实现一个冒泡排序函数

                对比 qsort 函数 冒泡排序,需修改的地方在

                        1.函数参数不能被类型固定 

                        2.交换程序不能被类型固定

                        3.比较因为个性化太强,利用回调函数,让其他人自己写

                总结,模型qsort函数写的功能是,基于冒泡排序的交换模块

由原代码的替换模块入手,1 字节 1字节的替换能覆盖所有内存,其余 大小总会有遗留的整数所以确认为(char)

                                  

确认元素类型后,需要确认  指针指向位置的准确。

                因为需要修改为无固定类型排序,声明已经改为void *p

                且确定由1 字节 1字节方式替换        

                所以我们需要一个元素的内存大小

                才能知道两个交换元素的地址

函数声明参数修改如下:

(void* p_arr, size_t num, size_t size)

                p_arr 待排序数组开始地址

                nim    待排序的所有元素个数

                size    待排序元素的大小

冒泡排序 替换模块如下:

for (int i = 0; i < num - 1; i++)
{for (int j = 0; j < num - 1; j++){if (>0){for (int m = 0; m < size; m++){char tmp = *((char*)p_arr + j * size+m);*((char*)p_arr + j * size+m) = *((char*)p_arr + (j + 1) * size+m);*((char*)p_arr + (j + 1) * size+m) = tmp;}}}
}

                if 语句为判断模块,判断为>0进行替换操作

                比较模块  由于个性化太强,利用回调函数

                我们已知进行比较两个元素的地址

由上我们可以知道判断模块的类型:

                1.返回值为 int

                2.传参两个指针

比较函数声明:

int bubsort_cmp(const void*p1, const void*p2);

函数代码如下:

int bubsort_cmp(const void*p1, const void*p2)
{return (*(int*)p1) - (*(int*)p2);
}void bubble_sort(void* p_arr, size_t num, size_t size, int(*cmp)(const void*, const void*)) 
{for (int i = 0; i < num - 1; i++){for (int j = 0; j < num - 1; j++){if (cmp((char*)p_arr +j*size, (char*)p_arr +(j+1)*size) > 0){for (int m = 0; m < size; m++){char tmp = *((char*)p_arr + j * size+m);*((char*)p_arr + j * size+m) = *((char*)p_arr + (j + 1) * size+m);*((char*)p_arr + (j + 1) * size+m) = tmp;}}}}
}

                

                

http://www.dtcms.com/a/393396.html

相关文章:

  • 人机协同开发中的“深水炸弹”——指令上下文混淆
  • 朴素贝叶斯算法详解:原理、应用与实践
  • 强化学习的数学原理-02章 贝尔曼公式
  • C++:入门基础(2)
  • 数据架构章节考试考点及关系梳理
  • 用TRAE编程助手编写一个浏览器插件
  • 赋能工业未来:向成电子XC3576H工控主板多领域应用前景
  • Multi-Agent多智能体系统(三)
  • 【语法进阶】高级用法、贪婪与非贪婪
  • 15天见效的SEO优化方案
  • C语言基础【20】:指针7
  • IC 数字逻辑设计中的硬件算法 01 记
  • 《棒球运动联盟》国家级运动健将标准·棒球1号位
  • AAC 详解
  • 蚂蚁集团DIVER登顶BRIGHT榜首,开源多阶段推理检索范式
  • 2013/12 JLPT听力原文 问题四
  • 挑战与应对:轻量化 AI 算法的成长烦恼
  • FPGA基础 -- CDC(Clock Domain Crossing)实战教程
  • 低碳经济:碳汇——从生态固碳到金融资产的价值转化
  • QGC 通信模块架构梳理
  • Application接口拓展功能(三)
  • 【Python】错误和异常
  • 【状态机实现】初识——基于状态机实现的流程编排和Activiti、Camunda、Flowable等工作流的区别
  • SpringBoot自动配置核心原理
  • Python 中的 Builder 模式实践 —— 以 UserProfileBuilder 为例
  • 探秘陌讯AIGC检测算法优化:详解MPS加速与模型热重载的实现原理
  • 1.3 管道(Pipe)核心知识点总结
  • GLUE:自然语言理解评估的黄金基准
  • 第13章 智能监测-设备数据处理
  • GEO技术科普