【问题标题】:Trouble using bsearch with an array of strings将 bsearch 与字符串数组一起使用时遇到问题
【发布时间】:2013-03-27 08:08:54
【问题描述】:

我在尝试对 C 中的字符串数组使用 c 内置 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

谢谢!

【问题讨论】:

    标签: c bsearch


    【解决方案1】:

    由于您使用的是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);
    }
    

    【讨论】:

    • 有趣:这行得通,我没想到会得到标准的保证。但是,阅读 ISO/IEC 9899:2011,'§7.22.5.1 bsearch 函数',它说: ¶3 compar 指向的比较函数被调用,两个参数指向关键对象并以该顺序传递给数组元素。 因此,行为是确定性的。但是,您不能将 myStrCmp() 函数与 qsort() 一起使用。
    • @JonathanLeffler:是的,API 的定义与qsort() 的定义略有不同,因此您可以为键传递一个字符串,但有一个结构数组可供搜索。
    【解决方案2】:

    您的状态名称(或密钥)需要是指向指针的指针。不必添加/删除constanywhere。 myStrCmp需要取消引用以比较字符串。下面的代码可以满足我的想法。如果没有请告诉我,谢谢。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-20
      • 2021-07-15
      • 2013-06-19
      • 2014-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多