cbsearch

bsearch() always returning null pointer


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.


Solution

  • 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");
    }