麻烦使用bsearch与字符串数组

时间:2013-04-05 02:34:50

标签: c bsearch

我在尝试在C中的字符串数组上使用c builtin bsearch时遇到了一些令人困惑的行为。这是代码。我知道你可以使用内置的strcmp来搜索字符串数组,但我包含了myStrCmp用于调试目的,因为我不知道为什么它不起作用。

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;
}

以下是调用此函数寻找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

正如您所看到的,bsearch在搜索过程中访问的位置应该具有有效的字符串(如在调用bsearch之前刚刚检查过的那样),但是如果您尝试在该位置打印char *则输出是垃圾。谁能看到我的错误?顺便说一下,当我调用bsearch并将最终参数设置为:

时,我会得到相同的不良行为(但不要明显地遵循它)
(int(*)(const void*, const void*))strcmp

谢谢!

2 个答案:

答案 0 :(得分:8)

由于您使用的是const char *数组,bsearch()会将指向这些元素的指针传递给比较函数。换句话说,它将在第二个参数中收到const char * const *

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);
}

答案 1 :(得分:1)

您的州名(或键)需要是指向指针的指针。没有必要在任何地方添加/删除constmyStrCmp需要通过一个解除引用来比较字符串。下面的代码可以实现您的想法。如果没有,请告诉我,谢谢。

#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");

}