0

The prompt here was for us to use qsort() and bsearch() to find and return the element that the user specified. So if an array had elements [blue, red, green, orange, ...] and the user entered "red", I am to use bsearch() to traverse the list and return the element they selected.

To do so I have done this:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>



// ------------- Comparative Function ---------------

int compareSort(const void * First, const void * Next) {
    return (*(int*)First - *(int*)Next);
}



int main() {

    char sixteenColors[5][10] = { "black", "blue", "green", "cyan", "red" };

    char colorName[100];

    printf("\nEnter a desired color name:  ");          // prompt user for input
    gets(colorName);                                    // get input
    printf("\n\nYou chose the color:  %s", colorName);  // display choice


    char *item;                                         // create pointer to catch bsearch() result
    int n;

    printf("\nBefore sorting the list is: ");
    for (n = 0; n < 5; n++) {                          // traverse through list and print all elements
        printf("%s ", sixteenColors[n]);               // print all in list as is
    }

    qsort(sixteenColors, 5, sizeof(char), compareSort); // call qsort() and pass in all paramenters

    printf("\nAfter sorting the list is: \n");
    for (n = 0; n < 5; n++) {                          // 'for' loop for printing
        printf("%s ", sixteenColors[n]);               // print newly sorted array
    }


    /* using bsearch() to find the specified color in the array */
    item = (char*)bsearch(&colorName, sixteenColors, 5, sizeof(char), compareSort);

    if (item != NULL) {
        printf("\nFound item = %d\n", *item);               // if present print what was found
    }
    else {
        printf("Item = %d could not be found\n", *item);   // print error message of no element found
    }


    return(0);
}

which has worked for me in the past when trying this program out with integers; but now that I'm attempting to do this with char[] (or strings) I am running into more issues that I am unequipped to answer...

This is the output I get when I try to run this:

Enter a desired color name:  red
You chose the color:  red
Before sorting the list is: black blue green cyan red
After sorting the list is: backl blue green cyan red

And it gets this far before getting the error message of "Exception thrown: read access violation. item was nullptr" ......

so I tried to rearrange my list to see how the sorting went with a different order, and this is what I got:

Enter a desired color name:  red
You chose the color:  red
Before sorting the list is: red green blue cyan black
After sorting the list is:  green blue cyan black

Please let me know if you can solve this or help me do so.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Reexamine your documentation for the `qsort` function and the parameters it needs. – 1201ProgramAlarm Nov 25 '19 at 05:16
  • **THANK YOU !!!!** i got a little bit farther by changing the number of elements parameter being passed in ; so now it reprints the "sorted" array, but still fails on the **bsearch()** .... – user1618033988749895 Nov 25 '19 at 05:23
  • `backl` or `black` in the output? – Jonathan Leffler Nov 25 '19 at 05:26
  • NB: [It is never safe to use `gets()`](https://stackoverflow.com/questions/1694036/why-is-the-gets-function-dangerous-why-should-it-not-be-used). Do NOT use it, even in test programs. It's a very bad habit. – Jonathan Leffler Nov 25 '19 at 05:28
  • the output prints as 'backl' for some reason... might be a problem with the comparative function i wrote... – user1618033988749895 Nov 25 '19 at 05:29
  • I just worked out that `backl` is the sorted order for `black`. You're sorting an array of characters, not an array of strings. Your comparator isn't appropriate for strings. Your call to `qsort` isn't correct, either; the entries are `sizeof(sizteenColors[0])` or `10`, not `sizeof(char)` or 1. You appear to have lost `red` altogether, but that may not be altogether surprising. The name `sixteenColors` for an array of 5 colours is odd, too. – Jonathan Leffler Nov 25 '19 at 05:32
  • you are dereferencing null pointer `item` in else block. `else { printf("Item = %d could not be found\n", *item); }` – NishanthSpShetty Nov 25 '19 at 05:44
  • @NishanthSpShetty Indeed! So focused on qsort and bsearch, didn't even notice that! – Willis Blackburn Nov 25 '19 at 06:10
  • @JonathanLeffler oh shit! i didn't even think of it that way! thank you! (p.s. i have to do it for 16, but trying to figure it out for 5 first lol) – user1618033988749895 Nov 25 '19 at 06:46
  • @NishanthSpShetty thanks for catching that! i originally thought that by pointing the star there that it would grab the data being pointed to lol – user1618033988749895 Nov 25 '19 at 06:49
  • @AJtheKidd be careful while dealing with pointer, the beauty is the beast!. – NishanthSpShetty Nov 25 '19 at 11:22

2 Answers2

2

Here is working code. The primary problems are identified somewhat cryptically in my comment and rather less cryptically in Willis Blackburn's answer.

The call to qsort() needs to identify the data correctly. You're not passing single characters but arrays of size 10. Your comparator needs to work with pointers to arrays of 10 characters. The revised code also avoids gets() like the plague it is. The use of strcspn() to zap the newline is the most succinct convention for zapping the newline; it works correctly even if there is no newline in the string.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static int compareSort(const void *First, const void *Next)
{
    const char *v1 = *(char (*)[10])First;
    const char *v2 = *(char (*)[10])Next;
    return strcmp(v1, v2);
}

int main(void)
{
    char colors[5][10] = { "black", "blue", "green", "cyan", "red" };
    char colorName[10];

    printf("\nEnter a desired color name:  ");
    if (fgets(colorName, sizeof(colorName), stdin) == NULL)
        exit(1);
    colorName[strcspn(colorName, "\n")] = '\0';
    printf("\n\nYou chose the color: [%s]\n", colorName);

    printf("Before sorting the list is: ");
    for (int n = 0; n < 5; n++)
    {
        printf("[%s] ", colors[n]);
    }
    putchar('\n');

    qsort(colors, 5, sizeof(colors[0]), compareSort);

    printf("After sorting the list is: ");
    for (int n = 0; n < 5; n++)
    {
        printf("[%s] ", colors[n]);
    }
    putchar('\n');

    char *item = (char *)bsearch(colorName, colors, 5, sizeof(colors[0]), compareSort);

    if (item != NULL)
    {
        printf("Found item = [%s]\n", item);
    }
    else
    {
        printf("Item = [%s] could not be found\n", colorName);
    }

    return(0);
}

My program was called qsbs89, compiled from qsbs89.c:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
      qsbs89.c -o qsbs89  
$ qsbs89

Enter a desired color name:  red


You chose the color: [red]
Before sorting the list is: [black] [blue] [green] [cyan] [red] 
After sorting the list is: [black] [blue] [cyan] [green] [red] 
Found item = [red]
$ qsbs89

Enter a desired color name:  magenta


You chose the color: [magenta]
Before sorting the list is: [black] [blue] [green] [cyan] [red] 
After sorting the list is: [black] [blue] [cyan] [green] [red] 
Item = [magenta] could not be found
$

(OK: I cheated slightly — I used a makefile that ran the gcc command shown.)

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 1
    Those casts in `compareSort` are why I said that multi-dimensional arrays in C are tricky. :-) – Willis Blackburn Nov 25 '19 at 06:02
  • I'd not disagree with you. It took me two goes to get it right (mainly due to not thinking hard enough on the first pass). – Jonathan Leffler Nov 25 '19 at 06:04
  • Thanks man! your comments along with your code have changed/showed a lot of the mistakes I've been making without even realzing it was bad lol to you and to @WillisBlackburn i've learned more about pointers/casting/parameters from you guys than i have from my lectures, so i appreciate it lots! – user1618033988749895 Nov 25 '19 at 07:20
1

You're having trouble with this because multi-dimensional arrays in C are tricky.

This is your data:

char sixteenColors[5][10] = { "black", "blue", "green", "cyan", "red" };

You're telling qsort that:

  • There are 5 elements in the array
  • The size of each element is sizeof(char)

In other words, you're asking it to quicksort an array of 5 chars. Is that what you have? No. But it explains why the characters of the word "black" are sorted.

Here are some useful metrics to use with a two-dimensional character array. Let's say you have char cs[X][Y] (where X and Y are constants).

  • sizeof cs is the size of the entire array.
  • sizeof *cs is the size of the second dimension, in other words, Y.
  • sizeof cs / sizeof *cs is X. (That works for any array; the number of elements in the array is the size of the array divided by the size of one element.)

Another issue is that it looks like your sorting function is sorting ints, not strings.

Willis Blackburn
  • 8,068
  • 19
  • 36
  • THANK YOU good sir! this cleared up a whole lot for me! and thanks for catching that!! i missed that 'int' portion of the sorting function because I originally was testing it with numbers before trying it with words lol the same way it says sixteenColors when there's only five, im trying to figure it out with only five colors before trying it with 16 – user1618033988749895 Nov 25 '19 at 06:56