I am attempting to find a user input string in a pre-sorted array. If I write my own binary search function, the input is found correctly. If I use the C bsearch, I always get a NULL pointer.
This is the relevant code snippet:
printf(bsearch(&input, *words, curr_idx + 1, max_len,
(int (*)(const void *, const void *))strcmp) ?
"YES" : "NO");
char input[max_len]
is the result of scanf("%s", input); uppercase(input);
char **words
is a pre-sorted array of uppercase strings
int curr_idx
is the max index of words
int max_len
is the max length, in bytes, of the words in words
(currently 18)
I've tried inputting strings I know are in the array, as well as strings I know are NOT in the array, and every case returns a NULL pointer.
Setting a breakpoint in gdb and examining the contents of input
and words
, it doesn't appear that anything is incorrect:
(gdb) print (char*)input
$5 = 0x7fffffffe610 "STONE"
(gdb) print words[150980]
$6 = 0x555555bf45a0 "STONE"
EDIT TO ADD 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");
}
The malloc()
bit is unnecessary, but meant to replicate the original program as closely as possible.
Here's a reduced version of your code:
#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");
}
The problem is that bsearch
calls your compare
function with a pointer to the current array element (as the second argument, that is; the first argument is always the key pointer given to bsearch
as its first argument).
Your array elements are pointers (char *
), so compare
receives a pointer to pointer to char. To make strcmp
work, you need to dereference that pointer:
#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");
}