无法使用 C 中的函数指针进行字符串比较

Failure to work on string comparison using function pointer in C

提问人:Hank Tang 提问时间:8/2/2023 最后编辑:Vlad from MoscowHank Tang 更新时间:8/2/2023 访问量:72

问:

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;
}
函数 比较 C-Strings bsearch

评论

1赞 Weather Vane 8/2/2023
欢迎您,但源代码的图片不是。请将所有代码发布为文本。更好的是,请发布两个代码的简单最小可重现示例,读者可以查看。完成与等。#includemain()
3赞 Hank Tang 8/2/2023
明白了。我已进行更改。谢谢你的指出。
0赞 chux - Reinstate Monica 8/2/2023
@HankTang 您是否希望返回相同或不同的值?strcmp("green", "g")
0赞 Hank Tang 8/2/2023
嗨,我希望它们会有所不同。

答:

1赞 0___________ 8/2/2023 #1
int compare_first_characters(const void *p, const void *q) {
    return strcmp(*(char **)p, *(char **)q);
}
  1. 这完全是无稽之谈,并调用未定义的行为。 不等同于*(char **)p(char *)p
  2. 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;
}

对应于根据其声明实际具有类型的参数的指针keyconst 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 可以正确地应用于数组。