1

Using bsearch in C failed to find a string 'Eva Lam' in an array of structure. This array is sorted in descending order of string members. I checked many times, still don't know where the bug is? BTW, I am using DEV C++ 5.9.4. Please help, many thanks.

#include <stdio.h>
#include <stdlib.h>     // for bsearch
#include <string.h>
#define SIZE 4   
#define NAME_SIZE 20

struct student {
  int id;
  char name[NAME_SIZE];
};

// Function prototypes
int comp_name(const void* a, const void* b);
void print_struct_array(struct student studs[], int size, int serial);

int main(){
  int i, option=0;
  struct student *stud, *target;

  // studs array already sort in descending order of name
  struct student studs[SIZE] = {{14123456, "Mary Chan"}
    , {11001234, "Eva Lam"}
    , {10123456, "David Wong"}
    , {12345678, "Chris So"}
  };

  printf("*** Before Searching ***\n");
  print_struct_array(studs, SIZE, 1);

  target = (struct student*) malloc(sizeof(struct student));
  if (target == NULL) {
    fprintf(stderr, "Out of memory!\n");
    return -1;
  }

  printf("Input student name to search: ");
  scanf("%[^\n]", target->name);
  fflush(stdin);
  printf("name=%s\n", target->name);


  stud = (struct student *)bsearch(target->name, studs, SIZE,  
    sizeof(struct student), comp_name);
  if (!stud)
     printf("name %s not found!\n", target->name);
  else
     printf("[id, name] found is [%d, %s]\n", stud->id, stud->name);


  return 0;
}

int comp_name(const void* a, const void* b) {
   printf("comp_name: a->name=%s, b->name=%s\n", 
     (*(struct student *)a).name, (*(struct student *)b).name);
   return strcmp((*(struct student *)b).name, 
     (*(struct student *)a).name);
}


void print_struct_array(struct student studs[], int size, int serial) {
  int i;

  printf("Student array #%d is {\n", serial);
  for (i=0; i<SIZE; i++) {
    if (i==0) 
      printf("  ");
    else if (i<=SIZE-1)
      printf(", ");
    printf("[%d, %s]\n", studs[i].id, studs[i].name);
  }
  printf("}\n");
}

But the output of the program when searching 'Eva Lam' is:

*** Before Searching ***
Student array #1 is {
  [14123456, Mary Chan]
, [11001234, Eva Lam]
, [10123456, David Wong]
, [12345678, Chris So]
}
Input student name to search: Eva Lam
name=Eva Lam
comp_name: a->name=Lam, b->name=Eva Lam
comp_name: a->name=Lam, b->name=Mary Chan
name Eva Lam not found!

--------------------------------
Process exited after 8.216 seconds with return value 0
alk
  • 69,737
  • 10
  • 105
  • 255
SJ0407
  • 11
  • 1

1 Answers1

1

Read the documentation for bsearch more carefully.

The compar routine is expected to have two arguments which point to the key object and to an array member, in that order.

This means that the first argument to your compare function will always be exactly what you gave as a first argument to bsearch. So either call it as: bsearch(target, studs, ...) or better yet, rewrite your compare function to:

int
comp_name(const void *av, const void *bv) {
    const char *a = av;
    const struct student *b = bv;
    printf("comp_name: a->name=%s, b->name=%s\n", a, b->name);
    return strcmp(b->name, a);
}

Also, please don't cast void * pointers in C, especially from malloc, but also the return value from bsearch in your code.

Art
  • 19,807
  • 1
  • 34
  • 60
  • Your explanation on bsearch compar parameter is very clear and useful. Now, I totally understood its usage. Your suggestion worked, many thanks Art. But why don't cast void * pointers in C, especially from malloc, but also the return value from bsearch? – SJ0407 Jul 22 '15 at 08:05
  • Because there's no reason to cast void pointers to other pointers. And it can hide errors in your code if you forgot the includes for correct function declarations. – Art Jul 22 '15 at 08:42