我正在尝试在预排序的数组中找到用户输入的字符串。如果我编写自己的二进制搜索功能,则可以正确找到输入。如果我使用C bsearch,我总是会得到一个NULL指针。
这是相关的代码段:
printf(bsearch(&input, *words, curr_idx + 1, max_len,
(int (*)(const void *, const void *))strcmp) ?
"YES" : "NO");
char input[max_len]
是scanf("%s", input); uppercase(input);
char **words
是预先排序的大写字符串数组
int curr_idx
是words
int max_len
是words
中的单词的最大长度(以字节为单位)(当前为18)
我尝试输入我知道在数组中的字符串以及我知道不在数组中的字符串,并且每种情况都返回NULL指针。
在gdb中设置断点并检查input
和words
的内容,似乎没有什么不正确的地方:
(gdb) print (char*)input
$5 = 0x7fffffffe610 "STONE"
(gdb) print words[150980]
$6 = 0x555555bf45a0 "STONE"
编辑以添加MCVE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char **words;
char *dictionary[5] = { "STOMPS", "STONABLE", "STONE", "STONEBOAT", "STONEBOATS" };
int curr_idx = 4;
int max_len = 18;
int compare(const void *a, const void *b)
{
return strcmp((const char *)a, (const char *)b);
}
void uppercase(char *input)
{
char *t = input;
while (*t) {
*t = toupper((unsigned char)*t);
t++;
}
}
int main()
{
words = malloc((curr_idx + 1) * sizeof(char *));
int i;
for (i = 0; i < 5; i++){
// words[i] = malloc(sizeof(char) * max_len);
words[i] = dictionary[i];
}
char input[max_len];
printf("Enter a word: ");
scanf("%s", input);
uppercase(input);
printf(bsearch(input, words, curr_idx + 1, sizeof(*words), compare) ?
"YES\n" :
"NO\n");
}
malloc()
位是不必要的,但是它意味着尽可能接近地复制原始程序。
答案 0 :(得分:2)
以下是代码的简化版本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int compare(const void *a, const void *b)
{
return strcmp(a, b);
}
int main(void)
{
const char *words[] = { "A" };
puts(bsearch("A", words, 1, sizeof *words, compare) ?
"YES" :
"NO");
}
问题是bsearch
使用指针调用您的compare
函数,以指向当前数组元素(作为第二个参数,即,第一个参数始终是赋予bsearch
作为第一个参数的关键指针)。
您的数组元素是指针(char *
),因此compare
收到一个指向char指针的指针。要使strcmp
工作,您需要取消引用该指针:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int compare(const void *a, const void *b)
{
const char *const *pstr = b;
return strcmp(a, *pstr);
}
int main(void)
{
const char *words[] = { "A" };
puts(bsearch("A", words, 1, sizeof *words, compare) ?
"YES" :
"NO");
}
答案 1 :(得分:0)
您的比较功能错误。您正在比较字符指针数组中的条目,因此比较函数将传递两个伪装为char **
的{{1}}值。您的比较代码需要做出相应的反应。
const void *
然后,也必须正确调用bsearch函数:
int compare(const void *v1, const void *v2)
{
const char *s1 = *(char **)v1;
const char *s2 = *(char **)v2;
// printf("[%s] <=> [%s] = %d\n", s1, s2, strcmp(s1, s2));
return strcmp(s1, s2);
}
此比较功能相对于其他功能的优点在于,同一比较器可以与char *key = input;
bsearch(&key, words, 5, sizeof(*words), compare);
一起使用,以对数组中的数据进行排序,从而确保比较是…err…是可比较的。您可以设计其他驱动qsort()
的方式(请参阅melpomene的answer),因为bsearch()
始终将键作为第一个参数传递给比较函数。但是在我看来,能够使用相同的比较器进行排序和搜索(而不是需要两个不同的功能)的能力似乎胜过不必总是取消引用键的好处。
工作代码:
bsearch()
样品运行(程序名称#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
static char **words;
static char *dictionary[] = { "STOMPS", "STONABLE", "STONE", "STONEBOAT", "STONEBOATS" };
static int curr_idx = 4;
static int max_len = 18;
#if 0
int compare(const void *a, const void *b)
{
return strcmp((const char *)a, (const char *)b);
}
#endif
static int compare(const void *v1, const void *v2)
{
const char *s1 = *(char **)v1;
const char *s2 = *(char **)v2;
printf("%s(): [%s] <=> [%s] = %d\n", __func__, s1, s2, strcmp(s1, s2));
return strcmp(s1, s2);
}
static void uppercase(char *input)
{
char *t = input;
while (*t)
{
*t = toupper((unsigned char)*t);
t++;
}
}
int main(void)
{
words = malloc((curr_idx + 1) * sizeof(char *));
int i;
for (i = 0; i < curr_idx + 1; i++)
{
// words[i] = malloc(sizeof(char) * max_len);
words[i] = dictionary[i];
}
char input[max_len];
char fmt[10];
snprintf(fmt, sizeof(fmt), "%%%ds", max_len - 1);
while (printf("Enter a word: ") > 0 && scanf(fmt, input) == 1)
{
uppercase(input);
char *key = input;
char **result = bsearch(&key, words, curr_idx + 1, sizeof(*words), compare);
if (result != 0)
printf("Key [%s] found at %p [%s]\n", input, result, *result);
else
printf("Key [%s] not found\n", input);
}
putchar('\n');
return 0;
}
):
bs11