bsearch() 总是返回空指针
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);
的结果
char **words
是预排序的大写字符串数组
int curr_idx
是 words
的最大索引
int max_len
是 words
中单词的最大长度(以字节为单位)(当前为 18)
我已经尝试输入我知道在数组中的字符串,以及我知道不在数组中的字符串,并且每种情况 returns 一个 NULL 指针。
在gdb中设置断点并检查input
和words
的内容,似乎没有任何错误:
(gdb) print (char*)input
= 0x7fffffffe610 "STONE"
(gdb) print words[150980]
= 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
使用 指向 当前数组元素的指针调用您的 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");
}
你的比较函数有误。您正在比较字符指针数组中的条目,因此向比较函数传递了两个伪装成 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()
一起使用来对数组中的数据进行排序,从而确保比较是……错误的……可比的。您可以设计其他驱动 bsearch()
的方法(参见 melpomene's ),因为 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
$
我正在尝试在预先排序的数组中查找用户输入的字符串。如果我编写自己的二分查找函数,输入就会被正确找到。如果我使用 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)
我已经尝试输入我知道在数组中的字符串,以及我知道不在数组中的字符串,并且每种情况 returns 一个 NULL 指针。
在gdb中设置断点并检查input
和words
的内容,似乎没有任何错误:
(gdb) print (char*)input
= 0x7fffffffe610 "STONE"
(gdb) print words[150980]
= 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
使用 指向 当前数组元素的指针调用您的 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");
}
你的比较函数有误。您正在比较字符指针数组中的条目,因此向比较函数传递了两个伪装成 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()
一起使用来对数组中的数据进行排序,从而确保比较是……错误的……可比的。您可以设计其他驱动 bsearch()
的方法(参见 melpomene's 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
$