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

Chr*_*ice 4 c sorting

这是比较功能:

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
}
Run Code Online (Sandbox Code Playgroud)

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

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

前qsort电话: qsort(wordlist, nbr_words, sizeof(char *), compare);

Cro*_*man 6

如果你展示了wordlist它的定义会有所帮助,但很可能它被定义为a char **.该compare()函数接收指向列表中每个元素的指针.如果列表中的每个元素都是类型char *,那么compare()将接收两个指针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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

paul@local:~/src/c/scratch$ ./comp
a and b are not equal
c and d are equal
paul@local:~/src/c/scratch$
Run Code Online (Sandbox Code Playgroud)

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*))
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

在这种情况下,如果你只是将普通参数传递给compare函数,你显然可以调用.但是,因为它是泛型的,它只能传递指向compare函数的指针,它实际上无法传递元素的值 - 它的使用允许它是通用的,因为任何类型的对象指针都可以转换为,但是没有可以转换任何非指针值的等效数据类型.出于这个原因,它必须以常规类型的方式工作strcmp()char *qsort()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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

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$
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,没有办法compare_any()可以同时接受一个数组int和一个数组char *,而没有compare_string()函数得到它需要作为a处理char **的指针,因为它在数组元素上执行指针算法.没有那种额外的间接水平,既不能compare_int()compare_double()不能发挥作用.