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

c/c++使用void*实现类型通配

概述:

我们封装一个函数,比如是一个比较函数,用于比较两个数据的值, 如果我们将参数的类型写死,那么这个函数就只能去处理此种类型的数据,对于其它的类型我们还需要进行函数的重载。

在c++中,模板很好的解决了这个问题,但是C语言中是没有模板的,那我们怎样实现一个函数可以处理多类型的数据呢? 


就是使用void*,我们知道任何类型的指针都可以隐式的转换为void*类型的指针,所以,如果我们在参数中以void*类型的量作为参数的话,那么这个函数就可以接收任意类型的地址。进而实现一个函数处理多个类型。

但是,由于void*类型的数据我们不能直接访问或者操作其指向的空间,必须转换成具体的类型才可以。所以,如果我们只是将参数修改成void*类型,自然是不行的。因为你在函数内部,是不知道你要将void*指针转化为什么类型的,自然也没有办法处理其指向的数据。

那么怎么办呢?
我们可以使用函数指针来实现,就是我们在传递void*的时候,还需要根据函数所要实现的功能,提供一个处理void*数据的函数。函数指针指向的函数的参数也应该是void*。


这个函数是我们自己编写,然后传入到调用的函数中去的,所以其内部需要提供一些功能,就是帮助调用函数中需要访问或者操作void*数据的部分,我们可以调用这个函数来实现,因为这个函数使我们自己提供的,我们知道自己此时要处理的具体类型,所以可以根据需求在函数指针指向的函数内部将void*转化为具体的类型,然后进行操作。

下面的代码就使用了void*参数,以及相应的函数指针,来实现通配类型的二分查找。

#include <stdio.h>
#include <stdlib.h>
/*二分查找:  数据必须提前有序,才能使用二分查找,也就是现需要排序*/
/*C语言做到支持多类型,那就使用void*,因为任何类型的指针都可以隐式转换为void*
*/int INT_compare(const void* nub1, const void* nub2) {int* tmp1 = (int*)nub1;int* tmp2 = (int*)nub2;return *tmp1 - *tmp2;											 // 实现简写
}/*查找到元素返回数组的下标,没有找到返回-1*/
/*elemSize是比较元素类型所占用的字节数,用来获取地址偏移
*/
int BinarySearch(void* arr, int len, int elemSize,void* search,int (*Compare)(const void* , const void*)) {int left = 0, right = 0, middle = 0;/*初始化边界的值,圈定范围的值*/left  = 0;right = len - 1;/*没有找到的话,left会大于right*/while (left <= right) {middle  = (left + right) / 2;                                // 还可以使用left + (right - left) / 2 进行计算结果int ret = 0;ret = Compare((char*)arr + middle * elemSize, search);       if (!ret) {return middle;}else if(ret > 0){right = middle - 1;}else {left = middle + 1;}}return -1;
}int main(void) {int arr[] = { 1,3,7,9,11 };int search[] = {0,1,7,2,11,12,-1};                                  // 测试多个数据可以写一个数组,使用for循环测试一堆数据for (int i = 0; i < sizeof(search) / sizeof(search[0]); i++) {int index = BinarySearch(arr, sizeof(arr) / sizeof(arr[0]),sizeof(int) ,&search[i],INT_compare);if (index != -1) printf("%-3d 找到了\n",search[i]);else printf("%-3d 没有找到\n",search[i]);}getchar();return 0;
}

ret = Compare((char*)arr + middle * elemSize, search);    // 因为Compare函数指针函数实现了对数据的比较,但是我们在调用函数中传入的是void*类型的数组,每次调用Compare函数传入的是数组对应的某个元素,但是void*的数组我们无法直接访问其内部的元素。(下标访问和指针访问都不可以)。

所以,我们此处将arr转换成(char*),这样你对arr指针加一个数字,就表示其向后移动多少个字节。i表示我们当前遍历数组的第几个元素,arr+i这样指针会向后移动i个字节。

但是,我们传入的数组中的数据并不一定是1个字节的,所以我们需要调用函数的位置,传入一个需要处理的数据占用的字节数elemSize。然后arr+i*elemSize这样arr指针就会指向数组中第i个元素了。

相关文章:

  • 短视频都是怎么剪的:四川京之华锦信息技术公司
  • 景源畅信电商:抖店需要的成本高吗?
  • Python 魂斗罗的音效和动漫效果
  • Qt moc系统的黑魔法?
  • KMP算法【C++】
  • 【MySQL精通之路】InnoDB(6)-磁盘结构(6)-Undolog
  • 【C语言】程序员自我修养之文件操作
  • 初始化是什么
  • 技术人内卷下新的尝试
  • Windows下安装Hadoop(引导版)
  • python-鸡兔同笼问题:已知鸡和兔的总头数与总脚数。求笼中鸡和兔各几只?
  • CSP模板生成系统
  • 三维科技云展厅如何突破传统展览的局限,赋能企业高效展示
  • linux常用命令之大数据平台搭建版
  • [CocosCreator]Android的增加AndroidX的动态权限
  • -------------------- 第二讲-------- 第一节------在此给出链表的基本操作
  • [Vue CLI 3] 配置解析之 css.extract
  • canvas实际项目操作,包含:线条,圆形,扇形,图片绘制,图片圆角遮罩,矩形,弧形文字...
  • CODING 缺陷管理功能正式开始公测
  • CSS盒模型深入
  • es6(二):字符串的扩展
  • ES6系统学习----从Apollo Client看解构赋值
  • java8-模拟hadoop
  • PHP 程序员也能做的 Java 开发 30分钟使用 netty 轻松打造一个高性能 websocket 服务...
  • springMvc学习笔记(2)
  • Webpack4 学习笔记 - 01:webpack的安装和简单配置
  • 大数据与云计算学习:数据分析(二)
  • 前端面试之CSS3新特性
  • 区块链技术特点之去中心化特性
  • 通过几道题目学习二叉搜索树
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 小程序滚动组件,左边导航栏与右边内容联动效果实现
  • 云栖大讲堂Java基础入门(三)- 阿里巴巴Java开发手册介绍
  • 400多位云计算专家和开发者,加入了同一个组织 ...
  • 没有任何编程基础可以直接学习python语言吗?学会后能够做什么? ...
  • #Spring-boot高级
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (17)Hive ——MR任务的map与reduce个数由什么决定?
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (十二)python网络爬虫(理论+实战)——实战:使用BeautfulSoup解析baidu热搜新闻数据
  • (转) 深度模型优化性能 调参
  • *ST京蓝入股力合节能 着力绿色智慧城市服务
  • .mat 文件的加载与创建 矩阵变图像? ∈ Matlab 使用笔记
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .NET Windows:删除文件夹后立即判断,有可能依然存在
  • .NET 使用配置文件
  • .NET企业级应用架构设计系列之结尾篇
  • .Net实现SCrypt Hash加密
  • /bin、/sbin、/usr/bin、/usr/sbin
  • ?.的用法
  • @ConfigurationProperties注解对数据的自动封装
  • @for /l %i in (1,1,10) do md %i 批处理自动建立目录
  • [20150707]外部表与rowid.txt
  • [2021]Zookeeper getAcl命令未授权访问漏洞概述与解决