views:

85

answers:

2

Hi,

I have an unsorted dictionary file named "dict.txt". I have managed to put the words of the file in an array and the qsort() I use also seems to be working just fine (That is, the array is sorted).

The problem arises when I call bsearch(), the program crashes and my question is:

Why is this happening?

I use gcc to compile and don't use an IDE of any sort so I don't have any debugger nor do I know how to use one (yet).

I am quite aware that the code presented here might contain several problems.

That is because I am quite new to c and my background is mainly Java (which despite the similarities seems to be a drawback, because I am so used to OO and c is obviously not OO).

Any advice would be greatly appreciated.

int strcmp_mod(const void *p1, const void *p2) {
   return strcmp(* (char * const *) p1, * (char * const *) p2);
}

int main(void) {

int size, i;
char **words;

char *pItem;
char *key = "fight";

char* buf = load_file("dict.txt"); if (buf == NULL) return 1;

size = count_words(buf);

words = (char**)malloc((size+1) * sizeof(char*));

for (i=0; i<size; i++) {
 words[i] = (char*)malloc(80 * sizeof(char));
} 

copy_words_to_lower(buf, words, size);
    words[size] = '\0';

    qsort(words, size, sizeof(char*), strcmp_mod);

for (i=0; i<size; i++) {
 printf("%s\n", words[i]);
}  

pItem = (char *) bsearch(key, words, size, sizeof(char*), strcmp_mod);

if (pItem!=NULL)
 printf ("%s is in the array.\n", pItem);
else
 printf ("%s is not in the array.\n", key); 

return 0;
}
+2  A: 

Try giving bsearch the address of key.

Amnon
+1 beat me to it.
Steve Jessop
Thank you very much.
dankilman
+2  A: 

Why is this happening?

You're passing a char* as the key parameter to bsearch, but your comparator expects the result of casting a char** to void*.

Once you've fixed that, the next problem is that the return value from bsearch is a pointer to the matching item in the array. So again a char** not a char*.

Any advice would be greatly appreciated.

Either get a debugger, or else get ready to add lots of logging to your code.

Also the construction of your words array is slightly off. As it is it gets the job done, but it might be an idea to allocate the buffer for each word as you go, rather than all the same size at the start. Who knows if somebody will send you a file with a word in it more than 80 chars long? You terminate the list of words with a nul character, '\0', when you probably mean to terminate it with a null pointer, NULL. '\0' actually works, because it's another way of saying 0, and 0 converts to a null pointer. But it's not what you mean. And the array doesn't need to be null-terminated at all right now, because every time you use it after that you specify its length, size.

Steve Jessop
Excellent reply.I have a question about allocating the buffer as I go.when I try using the same syntax inside the copy_words_to_lower()after checking the current word's length I also get thrown out when using malloc() and I get an error about something that has to do with an access to some memory address which is not allowed. This is why I originally put it outside as it seemed to be working this way.Any great advice on this matter?
dankilman
found it... thank you anyway.
dankilman
Another option would be not to allocate buffers for each word at all. You don't use it for anything else, so you could perhaps modify the data in `buf`. Write a NUL byte at the end of each word (I'm guessing currently there are spaces or linebreaks between the words?), replace any capital letters with lowercase, and write a pointer to the start of each word in to the `words` array. Coming from Java this probably seems a bit hacky, just turning one big string into lots of little ones, but avoiding too much memory allocation is often a concern in practical C code.
Steve Jessop
I'll give it a try. I actually like the hacky part about this. One of the things I dislike about Java is that it's a little heavy and there is not much thought about optimization in general.
dankilman