Проблема с использованием bsearch с массивом строк
Я получаю некоторую путаницу, пытаясь использовать встроенный bsearch c для массива строк в C. Вот код. Я знаю, что вы можете использовать встроенный 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;
}
и вот некоторые из результатов, когда эта функция вызывается для поиска Алабамы.
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 ответа
Поскольку вы используете массив 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);
}
Ваше имя состояния (или ключ) должно быть указателем на указатель. Не нужно было добавлять / удалять const
в любом месте. 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");
}