繁体   English   中英

比较Qsort使用的函数 - 比较(char **)

[英]Compare Function used by Qsort - Comparing (char **)

这是比较功能:

int compare(const void *a, const void *b) {
    char* *s = (char* *) a;
    char* *t = (char* *) b;
    return sort_order * strcmp(*s, *t); // sort_order is -1 or 1
}

现在我的问题是投射到特定类型的double pointer背后的原因是什么? 或者更确切地说, 为什么需要双指针转换以及如何在内部使用它

使用的其他变量: char **wordlist; int nbr_words; (数组元素是) char *word;

Ex qsort调用: qsort(wordlist, nbr_words, sizeof(char *), compare);

如果你展示wordlist的定义会有所帮助,但很可能它被定义为char ** compare()函数接收指向列表中每个元素的指针。 如果列表中的每个元素都是char *类型,那么compare()将接收两个指向char *指针,或者char **句话就是两个char **

转换为char ** (注意,实际将是多余的,在这种特殊情况下,如果你不从去const空指针,以非const char ** )本身是必要的,因为qsort()有处理任何类型的类型,因此参数在传递之前转换为void * 你无法尊重void *所以你必须先将它们转换回原来的类型,然后再对它们做任何事情。

例如:

#include <stdio.h>

int compare_int(void * a, void * b) {
    int * pa = a;
    int * pb = b;
    if ( *pa < *pb ) {
        return -1;
    } else if ( *pa > *pb ) {
        return 1;
    } else {
        return 0;
    }
}

int compare_double(void * a, void * b) {
    double * pa = a;
    double * pb = b;
    if ( *pa < *pb ) {
        return -1;
    } else if ( *pa > *pb ) {
        return 1;
    } else {
        return 0;
    }
}

int compare_any(void * a, void * b, int (*cfunc)(void *, void *)) {
    return cfunc(a, b);
}

int main(void) {
    int a = 1, b = 2;
    if ( compare_any(&a, &b, compare_int) ) {
        puts("a and b are not equal");
    } else {
        puts("a and b are equal");
    }

    double c = 3.0, d = 3.0;
    if ( compare_any(&c, &d, compare_double) ) {
        puts("c and d are not equal");
    } else {
        puts("c and d are equal");
    }

    return 0;
}

输出:

paul@local:~/src/c/scratch$ ./comp
a and b are not equal
c and d are equal
paul@local:~/src/c/scratch$

compare_any()函数将比较所支持的任何类型,在本例中为intdouble ,因为我们可以将函数指针传递给它。 但是,传递函数的签名必须相同,因此我们不能声明compare_int()接受两个int *参数,而compare_double()取两个double * 我们必须声明它们都是两个void *参数,当我们这样做时,我们必须将这些void *参数转换为这些函数中有用的东西,然后才能使用它们。

在你的情况下发生的事情是完全相同的,但数据本身是指针,所以我们传递指针指针,所以我们需要将void *转换为,在你的情况下, char **

编辑:为了解释有关qsort()如何工作的原始问题的评论中的一些混淆,这里是qsort()签名:

void qsort(void *base, size_t nmemb, size_t size,
           int(*compar)(const void*, const void*))

base是指向数组第一个元素的指针, nmemb是该数组的成员数, size是每个元素的大小。

qsort()调用compar on,比如数组的第一个和第二个元素时,它将发送第一个元素的地址(即base本身)和元素的地址(即base + size )。

如果base最初被声明为int数组,那么compare函数必须将它接收的那些指针解释为指向int指针,如int * 如果base最初被声明为字符串数组,作为char ** ,则compare函数必须将这些指针解释为char *指针,即char **

在所有情况下,compare函数都会获得指向元素的指针。 如果你有一个int数组,那么你必须在比较函数中将这些指针解释为int * 如果你有一个char *数组,那么你必须将它们解释为char ** ,依此类推。

在这种情况下,如果你只是将普通的char *参数传递给compare函数,你显然可以调用strcmp() 但是,因为qsort()是通用的,它只能传递指向compare函数的指针,它实际上不能传递元素的值 - 它是使用void *允许它是通用的,因为任何类型的对象指针都可以转换为void * ,但没有可以转换任何非指针值的等效数据类型。 因此,它必须以常规类型(如intdouble ,带指针和结构)以相同的方式工作,并且使其与所有可能类型正确工作的唯一方法是让它处理指向元素的指针,不是元素本身,即使元素本身也是指针。 出于这个原因,在这里看起来似乎得到了一个不必要的间接层,但实际上它必要的,以便qsort()能够以它的通用方式运行。

如果我修改上面的代码,你可以更清楚地看到这一点,这样compare_any()更类似于qsort() ,并且不需要两个指针,而是一个指向各种类型的双元素数组的单个指针(稍微做作的例子,但是我们保持简单):

#include <stdio.h>
#include <string.h>

int compare_int(void * a, void * b) {
    int * pa = a;
    int * pb = b;
    if ( *pa < *pb ) {
        return -1;
    } else if ( *pa > *pb ) {
        return 1;
    } else {
        return 0;
    }
}

int compare_double(void * a, void * b) {
    double * pa = a;
    double * pb = b;
    if ( *pa < *pb ) {
        return -1;
    } else if ( *pa > *pb ) {
        return 1;
    } else {
        return 0;
    }
}

int compare_string(void * a, void * b) {
    char ** pa = a;
    char ** pb = b;
    return strcmp(*pa, *pb);
}

int compare_any(void * arr, size_t size, int (*cfunc)(void *, void *)) {
    char * first = arr;
    char * second = first + size;
    return cfunc(first, second);
}

int main(void) {
    int n[2] = {1, 2};
    if ( compare_any(n, sizeof(*n), compare_int) ) {
        puts("a and b are not equal");
    } else {
        puts("a and b are equal");
    }

    double d[2] = {3.0, 3.0};
    if ( compare_any(d, sizeof(*d), compare_double) ) {
        puts("c and d are not equal");
    } else {
        puts("c and d are equal");
    }

    char * s[] = {"abcd", "bcde"};
    if ( compare_any(s, sizeof(*s), compare_string) ) {
        puts("'abcd' and 'bcde' are not equal");
    } else {
        puts("'abcd' and 'bcde' are equal");
    }

    return 0;
}

输出:

paul@local:~/src/c/scratch$ ./comp
a and b are not equal
c and d are equal
'abcd' and 'bcde' are not equal
paul@local:~/src/c/scratch$

正如您所看到的, compare_any()无法同时接受int数组和char *数组,而compare_string()函数不会获得需要将其视为char **的指针,因为指针算术它对数组元素执行。 没有这种额外的间接级别, compare_int()compare_double()都不起作用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM