C语言中使用函数指针进行字符串比较失效问题排查
C语言bsearch使用strcmp版比较函数匹配失败问题排查
问题原因
版本2的compare_first_characters使用strcmp比较整个字符串,这与你要查找「以指定字符开头的单词」的需求完全不符:
- 调用
qsort时,数组会按字符串的完整字典序排序,结果为blue, green, red, yellow - 调用
bsearch时,函数会尝试查找与key(字符串"g")完全相等的元素,但数组中不存在完全匹配"g"的字符串,因此返回未找到。
而版本1的比较函数仅比较字符串的第一个字符,qsort会按首字母排序数组,bsearch也仅匹配首字母与key的第一个字符相同的元素,刚好符合你的需求,因此能找到green。不过版本1存在未定义行为:bsearch传入的key是const char*类型,比较函数中把它强制转换为char**解引用,本质上是非法的内存访问,只是在多数平台上碰巧能得到正确结果。
解决方法
根据你的需求(查找首字母匹配的单词),提供两种规范的实现方式:
方式1:修正首字母比较逻辑,消除未定义行为
修改比较函数,确保类型转换合法,同时保持首字母比较的逻辑;调整key的类型,使其与数组元素类型一致(数组元素是char*,因此key应为指向char*的指针)。
完整代码:
#include <stdlib.h> #include <stdio.h> #include <string.h> int compare_first_characters(const void *p, const void *q) { // p、q均为指向char*的指针(数组元素地址或key地址) const char *str1 = *(const char **)p; const char *str2 = *(const char **)q; // 仅比较字符串的第一个字符 return *str1 - *str2; } int main(int argc, char *argv[]) { char *words[] = {"red", "blue", "green", "yellow"}; int n = sizeof(words) / sizeof(*words); const char *key_str = "g"; // key类型与数组元素类型一致:指向char*的指针 const char **key = &key_str; qsort(words, n, sizeof(words[0]), compare_first_characters); printf("Sorted by first letter: \n"); for (int i = 0; i < n; i++) { printf("%s ", words[i]); } printf("\n"); printf("Looking for a word that starts with '%s': ", *key); const void *found = bsearch(key, words, n, sizeof(words[0]), compare_first_characters); printf("found '%s'\n", found ? *(const char **)found : "none"); return 0; }
方式2:用strcmp实现首字母比较(可扩展为前缀匹配)
如果需要基于strcmp实现首字母比较(方便未来扩展为多字符前缀匹配),可以构造仅包含首字母的临时字符串进行比较,同时保持key类型与数组元素一致。
修改后的比较函数:
int compare_first_characters(const void *p, const void *q) { const char *str1 = *(const char **)p; const char *str2 = *(const char **)q; // 构造仅含首字母的临时字符串 char prefix1[2] = {*str1, '\0'}; char prefix2[2] = {*str2, '\0'}; return strcmp(prefix1, prefix2); }
main函数部分与方式1完全一致,运行结果也相同。
补充说明
如果你的实际需求是完全匹配字符串,那么版本2的代码逻辑是正确的,但由于数组中没有"g"这个元素,bsearch返回未找到是正常结果。
内容的提问来源于stack exchange,提问作者Hank Tang
相关产品推荐
相关产品推荐

