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个元素了。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值