通用二进制搜索函数实现问询:支持多类型数组
通用二分查找函数实现(支持多数据类型)
你原来的思路存在两个核心问题:一是void*指针无法直接获取元素大小(sizeof(array[0])属于非法操作),二是仅靠元素大小无法区分有符号/无符号类型的比较逻辑。下面是最优实现方案,通过传入元素大小、数组长度和自定义比较函数来实现通用型二分查找:
核心思路
- 用
void*接收任意类型的数组指针,打破单一类型限制; - 显式传入元素字节大小,用来计算数组中每个元素的内存偏移;
- 传入自定义比较函数,处理不同类型的大小比较逻辑(比如有符号和无符号的差异);
- 补充数组长度参数,二分查找必须依赖边界信息才能正确执行。
完整代码实现
通用二分查找函数
#include <stdint.h> #include <stddef.h> // 比较函数类型定义:返回值 <0 表示a < b,=0表示a==b,>0表示a>b typedef int (*CompareFunc)(const void* a, const void* b); // 查找成功返回目标元素的索引,失败返回SIZE_MAX size_t binary_search(const void* array, size_t length, size_t elem_size, const void* target, CompareFunc cmp) { size_t left = 0; size_t right = length - 1; while (left <= right) { // 计算中间元素的内存地址:用char*做偏移,确保字节级精确计算 size_t mid_idx = left + (right - left) / 2; const void* mid_elem = (const char*)array + mid_idx * elem_size; int cmp_result = cmp(mid_elem, target); if (cmp_result == 0) { return mid_idx; // 返回索引 } else if (cmp_result < 0) { left = mid_idx + 1; } else { right = mid_idx - 1; } } return SIZE_MAX; // 未找到目标元素 }
针对不同类型的比较函数
// uint8_t类型比较 int cmp_uint8(const void* a, const void* b) { const uint8_t* val_a = (const uint8_t*)a; const uint8_t* val_b = (const uint8_t*)b; return (*val_a > *val_b) - (*val_a < *val_b); } // int8_t类型比较 int cmp_int8(const void* a, const void* b) { const int8_t* val_a = (const int8_t*)a; const int8_t* val_b = (const int8_t*)b; return (*val_a > *val_b) - (*val_a < *val_b); } // uint16_t类型比较 int cmp_uint16(const void* a, const void* b) { const uint16_t* val_a = (const uint16_t*)a; const uint16_t* val_b = (const uint16_t*)b; return (*val_a > *val_b) - (*val_a < *val_b); }
调用示例
#include <stdio.h> int main() { // uint8_t数组查找 uint8_t u8_arr[] = {2, 4, 6, 8, 10}; size_t u8_len = sizeof(u8_arr) / sizeof(u8_arr[0]); uint8_t u8_target = 6; size_t u8_idx = binary_search(u8_arr, u8_len, sizeof(uint8_t), &u8_target, cmp_uint8); if (u8_idx != SIZE_MAX) { printf("uint8_t target found at index: %zu\n", u8_idx); } else { printf("uint8_t target not found\n"); } // int8_t数组查找 int8_t s8_arr[] = {-10, -5, 0, 5, 10}; size_t s8_len = sizeof(s8_arr) / sizeof(s8_arr[0]); int8_t s8_target = -5; size_t s8_idx = binary_search(s8_arr, s8_len, sizeof(int8_t), &s8_target, cmp_int8); if (s8_idx != SIZE_MAX) { printf("int8_t target found at index: %zu\n", s8_idx); } else { printf("int8_t target not found\n"); } return 0; }
关键细节说明
- 用char*计算偏移:char类型的大小固定为1字节,转换为char*后进行指针加减操作,可以精确计算任意类型元素的内存地址;
- 比较函数的必要性:即使元素字节大小相同(比如int8_t和uint8_t都是1字节),它们的比较逻辑完全不同,必须通过自定义比较函数区分;
- 返回值选择:用
size_t作为索引类型更符合C语言的规范,SIZE_MAX表示未找到,避免了符号类型转换的潜在问题。
内容的提问来源于stack exchange,提问作者nerd_god
相关产品推荐
相关产品推荐

