Trouble using bsearch with an array of strings

喜夏-厌秋 提交于 2019-12-21 17:01:37

问题


I am getting some confusing behaviour trying to use the c builtin bsearch on an array of strings in C. Here is the code. I know you can use the builtin strcmp for searching arrays of strings, but I included myStrCmp for debugging purposes because I didn't know why it wasn't working.

const char *stateNames[] = {"Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "Washington DC", "West Virginia", "Wisconsin", "Wyoming"};

int myStrCmp(const void *s1, const void *s2) {
  printf("myStrCmp: s1(%p): %s, s2(%p): %s\n", s1, (char *)s1, s2, (char *)s2);
  return strcmp(s1, s2);
}

int determineState(char *state) {
  printf("state: %s\n", state);
  for(int i = 0; i < 51; i++) 
    printf("stateNames[%i](%p): %s\n", i, &(stateNames[i]), stateNames[i]);

  char *found = (char *) bsearch(state, stateNames, 51, sizeof(char *), myStrCmp );

  if(found == NULL)
    return -1;

  return 0;
}

and here is some of the output when this function is called to look for Alabama.

stateNames[0](0x618440): Alabama
stateNames[1](0x618448): Alaska
stateNames[2](0x618450): Arizona
...
stateNames[24](0x618500): Missouri
stateNames[25](0x618508): Montana
stateNames[26](0x618510): Nebraska
stateNames[27](0x618518): Nevada
stateNames[28](0x618520): New Hampshire
stateNames[29](0x618528): New Jersey
stateNames[30](0x618530): New Mexico
stateNames[31](0x618538): New York
stateNames[32](0x618540): North Carolina
stateNames[33](0x618548): North Dakota
stateNames[34](0x618550): Ohio
stateNames[35](0x618558): Oklahoma
stateNames[36](0x618560): Oregon
stateNames[37](0x618568): Pennsylvania
stateNames[38](0x618570): Rhode Island
stateNames[39](0x618578): South Carolina
stateNames[40](0x618580): South Dakota
stateNames[41](0x618588): Tennessee
stateNames[42](0x618590): Texas
stateNames[43](0x618598): Utah
stateNames[44](0x6185a0): Vermont
stateNames[45](0x6185a8): Virginia
stateNames[46](0x6185b0): Washington
stateNames[47](0x6185b8): Washington DC
stateNames[48](0x6185c0): West Virginia
stateNames[49](0x6185c8): Wisconsin
stateNames[50](0x6185d0): Wyoming
myStrCmp: s1(0x415430): Alabama, s2(0x618508): 
                                               UA
myStrCmp: s1(0x415430): Alabama, s2(0x618570): A
myStrCmp: s1(0x415430): Alabama, s2(0x618540): PUA
myStrCmp: s1(0x415430): Alabama, s2(0x618528): 1UA
myStrCmp: s1(0x415430): Alabama, s2(0x618538): GUA
myStrCmp: s1(0x415430): Alabama, s2(0x618530): <UA

As you can see, the locations visited by bsearch in the course of its search should have valid strings (as was just checked before calling bsearch), but the output if you try to print the char * at that location is garbage. Can anyone see my mistake? Incidentally I get the same bad behaviour (but don't get to follow it as closely obviously) when I call bsearch with the final parameter set to:

(int(*)(const void*, const void*))strcmp

Thanks!


回答1:


Since you are using an array of const char *, bsearch() will pass to the comparison function a pointer to those elements. In other words, it will receive const char * const * in its second argument.

int myStrCmp(const void *s1, const void *s2) {
  const char *key = s1;
  const char * const *arg = s2;
  printf("myStrCmp: s1(%p): %s, s2(%p): %s\n", s1, key, s2, *arg);
  return strcmp(key, *arg);
}



回答2:


Your state name (or key) needs to be a pointer to a pointer. Didn't have to add/remove constanywhere. myStrCmpneeds to dereference by one to compare the strings. The code below does what you want I think. Please let me know if not, thanks.

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


const char *stateNames[] = {"Alabama", "Alaska", "Arizona", "Arkansas","California", "Colorado", "Connecticut", "Delaware", "Florida","Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "Washington DC", "West Virginia", "Wisconsin", "Wyoming"};

int myStrCmp(const void *s1, const void *s2) {
    printf("myStrCmp: s1(%p): %s, s2(%p): %s\n", s1, *(char **)s1, s2, *(char**)s2);
    return strcmp(*(char **) s1, *(char **) s2);
}

int determineState(char *state) {
    printf("state: %s\n", state);

    for(int i = 0; i < 51; i++)
        printf("stateNames[%i](%p): %s\n", i, &(stateNames[i]), stateNames[i]);

    char **found = (char **) bsearch(&state, stateNames, 51, sizeof(char *), myStrCmp );

    if(found == NULL){
        return -1;
    } else {
        printf("Found it!: %s\n", *found);

    }

    return 0;
}

int main(int argc, const char * argv[]) {
    determineState("Alabama");

}


来源:https://stackoverflow.com/questions/15824966/trouble-using-bsearch-with-an-array-of-strings

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!