2013-04-05 134 views
5

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

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

这里是当这个函数被调用来寻找阿拉巴马州时的一些输出。

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之前刚选中),但输出,如果你尝试打印字符*在那位置是垃圾。任何人都能看到我的错误?顺便说一句,我得到了相同的不良行为(但没有得到遵循它作为密切明显)当我打电话bsearch与最终的参数设置为:

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

谢谢!

回答

7

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

有趣的是,这工程,我没有想到会被标准保证。但是,阅读ISO/IEC 9899:2011,'§7.22.5.1'bsearch'函数',它会说:_¶3用'compar'指向的比较函数有两个参数指向 指向关键对象,而到数组元素,按照这个顺序。因此,行为是确定性的。尽管如此,你不能在'qsort()'中使用'myStrCmp()'函数。 – 2013-04-05 05:08:00

+0

@JonathanLeffler:是的,API的定义与'qsort()'有一点不同,这样你就可以传递一个字符串作为键,但有一个结构数组可以搜索。 – jxh 2013-04-05 05:49:55

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

}