[英]bsearch() always returning null pointer
我试图在预排序的数组中找到用户输入的字符串。 如果我编写自己的二进制搜索功能,则可以正确找到输入。 如果我使用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);
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()
位是不必要的,但是它意味着尽可能接近地复制原始程序。
这是代码的简化版本:
#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
使用指向当前数组元素的指针 (作为第二个参数,即,第一个参数始终是作为其第一个参数提供给bsearch
的键指针)来调用compare
函数。
您的数组元素是指针( 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");
}
您的比较功能是错误的。 您正在比较字符指针数组中的条目,因此比较函数将传递给两个伪装为const void *
char **
值。 您的比较代码需要做出相应的反应。
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);
}
然后,也必须正确调用bsearch函数:
char *key = input;
bsearch(&key, words, 5, sizeof(*words), compare);
此比较功能相对于其他功能的优点在于,可以将同一个比较器与qsort()
一起使用,以对数组中的数据进行排序,从而确保比较是…err…可比较的。 您可以设计其他方法来驱动bsearch()
(请参阅melpomene的答案 ),因为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
):
$ ./bs11
Enter a word: abracadabra
compare(): [ABRACADABRA] <=> [STONE] = -18
compare(): [ABRACADABRA] <=> [STONABLE] = -18
compare(): [ABRACADABRA] <=> [STOMPS] = -18
Key [ABRACADABRA] not found
Enter a word: STOMPS
compare(): [STOMPS] <=> [STONE] = -1
compare(): [STOMPS] <=> [STONABLE] = -1
compare(): [STOMPS] <=> [STOMPS] = 0
Key [STOMPS] found at 0x7fa1e4402a70 [STOMPS]
Enter a word: stona
compare(): [STONA] <=> [STONE] = -4
compare(): [STONA] <=> [STONABLE] = -66
compare(): [STONA] <=> [STOMPS] = 1
Key [STONA] not found
Enter a word: STONABLE
compare(): [STONABLE] <=> [STONE] = -4
compare(): [STONABLE] <=> [STONABLE] = 0
Key [STONABLE] found at 0x7fa1e4402a78 [STONABLE]
Enter a word: stonable
compare(): [STONABLE] <=> [STONE] = -4
compare(): [STONABLE] <=> [STONABLE] = 0
Key [STONABLE] found at 0x7fa1e4402a78 [STONABLE]
Enter a word: stonc
compare(): [STONC] <=> [STONE] = -2
compare(): [STONC] <=> [STONABLE] = 2
Key [STONC] not found
Enter a word: STONE
compare(): [STONE] <=> [STONE] = 0
Key [STONE] found at 0x7fa1e4402a80 [STONE]
Enter a word: stobneage
compare(): [STOBNEAGE] <=> [STONE] = -12
compare(): [STOBNEAGE] <=> [STONABLE] = -12
compare(): [STOBNEAGE] <=> [STOMPS] = -11
Key [STOBNEAGE] not found
Enter a word: STONEBOAT
compare(): [STONEBOAT] <=> [STONE] = 66
compare(): [STONEBOAT] <=> [STONEBOATS] = -83
compare(): [STONEBOAT] <=> [STONEBOAT] = 0
Key [STONEBOAT] found at 0x7fa1e4402a88 [STONEBOAT]
Enter a word: stoneboatatdawn
compare(): [STONEBOATATDAWN] <=> [STONE] = 66
compare(): [STONEBOATATDAWN] <=> [STONEBOATS] = -18
compare(): [STONEBOATATDAWN] <=> [STONEBOAT] = 65
Key [STONEBOATATDAWN] not found
Enter a word: STONEBOATS
compare(): [STONEBOATS] <=> [STONE] = 66
compare(): [STONEBOATS] <=> [STONEBOATS] = 0
Key [STONEBOATS] found at 0x7fa1e4402a90 [STONEBOATS]
Enter a word: zoo
compare(): [ZOO] <=> [STONE] = 7
compare(): [ZOO] <=> [STONEBOATS] = 7
Key [ZOO] not found
Enter a word: ^D
$
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.