提问人:Hank Tang 提问时间:8/2/2023 最后编辑:Vlad from MoscowHank Tang 更新时间:8/2/2023 访问量:72
无法使用 C 中的函数指针进行字符串比较
Failure to work on string comparison using function pointer in C
问:
compare_first_character函数有两个版本,它们都传递到另一个函数中。但是,第一个将产生正确的单词匹配,而第二个将返回任何内容,尽管有一个。
版本1: [字符串比较版本 1]
int compare_first_characters(const void *p, const void *q) {
return **(char **)p - **(char **)q;
}
版本 2(失败): [字符串比较版本 2]
int compare_first_characters(const void *p, const void *q) {
return strcmp(*(char **)p, *(char **)q);
}
出现问题的可疑功能:
const void *found = bsearch(key, words, n, sizeof(words[0]), compare_first_characters);
完整程序:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int compare_first_characters(const void *p, const void *q) {
return strcmp(*(char **)p, *(char **)q);
}
int main(int argc, char *argv[]) {
char *words[] = {"red", "blue", "green", "yellow"};
int n = sizeof(words) / sizeof(*words);
const char *key = "g";
qsort(words, n, sizeof(words[0]), compare_first_characters);
printf("Sorted by first letter: \n");
for (int i = 0; i < n; i++) {
printf("%s ", words[i]);
}
printf("\n");
printf("Looking for a word that starts with '%s': ", key);
const void *found = bsearch(key, words, n, sizeof(words[0]), compare_first_characters);
printf("found '%s'\n", found ? *(const char **)found : "none");
return 0;
}
答:
1赞
0___________
8/2/2023
#1
int compare_first_characters(const void *p, const void *q) {
return strcmp(*(char **)p, *(char **)q);
}
- 这完全是无稽之谈,并调用未定义的行为。 不等同于
*(char **)p
(char *)p
strcmp
比较整个字符串,而不是第一个字符。
如果要比较字符串
int compare_first_characters(const void *p, const void *q) {
return !strcmp(p, q);
}
如果只有第一个字符
int compare_first_characters(const void *p, const void *q) {
const char *a = p, *b = q;
return *a == *b;
}
https://godbolt.org/z/MMEra35vY
评论
0赞
Hank Tang
8/2/2023
谢谢。但是在进行更改后,我仍然找不到匹配项。
0赞
Hank Tang
8/2/2023
知道了,谢谢!
1赞
Vlad from Moscow
8/2/2023
#2
调用的两个比较函数均无效。bsearch
该函数按如下方式声明bsearch
void *bsearch(const void *key, const void *base,
size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
这必须通过指向它的指针通过引用传递。key
但是,您调用的函数如下
const void *found = bsearch(key, words, n, sizeof(words[0]), compare_first_characters);
^^^
因此,在第一个比较函数中,这种双重取消引用
int compare_first_characters(const void *p, const void *q) {
return **(char **)p - **(char **)q;
}
对应于根据其声明实际具有类型的参数的指针key
const char *
const char *key = "g";
调用未定义的行为。你错了,使用第一个比较功能,程序可以正常工作。例如,尝试使用另一个字符串作为键,例如 ."y"
您必须编写函数调用,例如
const void *found = bsearch( &key, words, n, sizeof( words[0] ), compare_first_characters );
^^^^
请注意,该函数比较整个字符串。因此,要使用第二个比较函数,您需要指定一个字符串文本,该文本等于数组的字符串之一:在这种情况下,两个比较函数都可以正常工作。strcmp
相对于第一个比较函数,您应该将 void 指针转换为无符号字符类型。const unsigned char **
这是您更新的程序。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int compare_first_characters1( const void *p, const void *q ) {
return **( const unsigned char ** )p - **( const unsigned char ** )q;
}
int compare_first_characters2( const void *p, const void *q ) {
return strcmp( *( char ** )p, *( char ** )q );
}
int main( void )
{
const char *words[] = { "red", "blue", "green", "yellow" };
int n = sizeof( words ) / sizeof( *words );
const char *key1 = "y";
qsort( words, n, sizeof( words[0] ), compare_first_characters1 );
printf( "Sorted by first letter: \n" );
for (int i = 0; i < n; i++)
{
printf( "%s ", words[i] );
}
printf( "\n" );
printf( "Looking for a word that starts with '%s': ", key1 );
const void *found = bsearch( &key1, words, n, sizeof( words[0] ), compare_first_characters1 );
printf( "found '%s'\n", found ? *( const char ** )found : "none" );
putchar( '\n' );
const char *key2 = "yellow";
qsort( words, n, sizeof( words[0] ), compare_first_characters2 );
printf( "Sorted by first letter: \n" );
for (int i = 0; i < n; i++)
{
printf( "%s ", words[i] );
}
printf( "\n" );
printf( "Looking for a word that starts with '%s': ", key2 );
found = bsearch( &key2, words, n, sizeof( words[0] ), compare_first_characters2 );
printf( "found '%s'\n", found ? *( const char ** )found : "none" );
}
程序输出为
Sorted by first letter:
blue green red yellow
Looking for a word that starts with 'y': found 'yellow'
Sorted by first letter:
blue green red yellow
Looking for a word that starts with 'yellow': found 'yellow'
顺便说一句,由于数组中的所有字符串都与第一个字符不同,因此您可以使用第一个比较函数对数组进行排序,然后搜索目标字符串,例如,或者在调用中使用第二个比较函数。"yellow"
"green"
bsearch
这是更新以前的程序。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int compare_first_characters1( const void *p, const void *q ) {
return **( const unsigned char ** )p - **( const unsigned char ** )q;
}
int compare_first_characters2( const void *p, const void *q ) {
return strcmp( *( char ** )p, *( char ** )q );
}
int main( void )
{
const char *words[] = { "red", "blue", "green", "yellow" };
int n = sizeof( words ) / sizeof( *words );
const char *key = "green";
qsort( words, n, sizeof( words[0] ), compare_first_characters1 );
printf( "Sorted by first letter: \n" );
for (int i = 0; i < n; i++)
{
printf( "%s ", words[i] );
}
printf( "\n" );
printf( "Looking for a word that starts with '%s': ", key );
const void *found = bsearch( &key, words, n, sizeof( words[0] ), compare_first_characters1 );
printf( "found '%s'\n", found ? *( const char ** )found : "none" );
}
它的输出是
Sorted by first letter:
blue green red yellow
Looking for a word that starts with 'green': found 'green'
评论
0赞
Hank Tang
8/3/2023
知道了,谢谢!只是一个细节,bsearch 必须使用与 qsort 相同的比较功能,对吗?我认为这是写在bsearch手册中的。
1赞
Vlad from Moscow
8/3/2023
@HankTang bsearch 应用于有序数组。因此,应该对数组进行排序,以便 bsearch 可以正确地应用于数组。
评论
#include
main()
strcmp("green", "g")