2013-04-05 15 views
5

Otrzymuję pewne mylące zachowanie próbujące użyć wbudowanego c wyszukiwania w tablicy łańcuchów w C. Oto kod. Wiem, że możesz użyć wbudowanego strcmp do wyszukiwania tablic ciągów, ale włączyłem myStrCmp do celów debugowania, ponieważ nie wiedziałem, dlaczego to nie działa.Problemy z używaniem bsearch z tablicą łańcuchów znaków

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

i tutaj jest część wyników, gdy ta funkcja jest wywoływana w poszukiwaniu Alabamy.

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 

Jak widać, lokalizacje odwiedzane przez bsearch w trakcie jego poszukiwań powinien posiadać ważne ciągi (jak właśnie sprawdzana przed wywołaniem bsearch), ale wyjście jeśli próbujesz wydrukować char * na które lokalizacja to śmieci. Czy ktoś może zobaczyć mój błąd? Nawiasem mówiąc mam taką samą złe zachowanie (ale nie dostać do naśladowania go jako ściśle oczywiście) gdy zgłoszę bsearch z końcowym zestawu parametrów do:

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

Dzięki!

Odpowiedz

7

Ponieważ używasz tablicy const char *, bsearch() przejdzie do funkcji porównania wskaźnik do tych elementów. Innymi słowy, otrzyma const char * const * w swoim drugim argumencie.

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

Interesujące: to działa, czego nie oczekiwałem, że będzie gwarantowane przez standard. Jednakże, czytając ISO/IEC 9899: 2011, "§7.22.5.1 Funkcja" bsearch ", mówi: _¶3 Funkcja porównania wskazana przez" compar "jest wywoływana z dwoma argumentami, które wskazują na klucz obiektu i do elementu tablicy, w tej kolejności. Tak więc zachowanie jest deterministyczne. Nie można jednak użyć funkcji 'myStrCmp()' z 'qsort()'. –

+0

@ JonathanLeffler: Tak, API jest zdefiniowane trochę inaczej niż dla 'qsort()', więc możesz podać ciąg znaków dla klucza, ale masz tablicę struktur do przeszukania. – jxh

1

Twoja nazwa stanu (lub klucz) musi być wskaźnikiem do wskaźnika. Nie trzeba było dodawać/usuwać w dowolnym miejscu. myStrCmp potrzebuje dereferencji przez jeden, aby porównać ciągi. Poniższy kod robi to, co chcesz, myślę. Daj mi znać, jeśli nie, dzięki.

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

} 
Powiązane problemy