cstringstructbsearch

bsearch() - Finding a string in an array of structs


I have a struct that looks like this:

typedef struct dictionary_t{
    char word[30];
    int foo;
    int bar;
} dictionary_t;

Which forms an ordered array:

dictionary_t dictionary[100];

I would like to search this array for a string using bsearch() and get a pointer to the struct. So far this has worked:

dictionary_t* result;
char target[30] = "target";
result = bsearch(&target, dictionary, dict_length, sizeof(dictionary_t), (int(*)(const void*,const void*)) strcmp);

However this is a bit of a hack and only works because the string happens to be the first member of the struct. What would be a better way to find a string within an array of structs and return a pointer to the struct?


Solution

  • You should implement your own comparator function and pass it in. The most important (non-trivial) thing to keep in mind here is that according to the standard,

    The implementation shall ensure that the first argument is always a pointer to the key.

    This means that you can write a comparator that compares a string such as target and a dictionary_t object. Here is a simple function that compares your stucts to a string:

    int compare_string_to_dict(const void *s, const void *d) {
        return strncmp(s, ((const dictionary_t *)d)->word, sizeof(((dictionary_t *)0)->word));
    }
    

    You would then pass it by name as a normal function pointer to bsearch:

    result = bsearch(target, dictionary, dict_length, sizeof(dictionary_t), compare_string_to_dict);
    

    Note that target does not need to have its address passed in since it is no longer mocking a struct.

    In case you are wondering, sizeof(((dictionary_t *)0)->word) is an idiomatic way of getting the size of word in dictionary_t. You could also do sizeof(dictionary[0].word) or define a constant equal to 30. It comes from here.