4

这是比较功能:

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);

4

1 回答 1

6

如果您显示 的定义会有所帮助wordlist,但很可能它被定义为char **. 该compare()函数接收指向列表中每个元素的指针。如果列表中的每个元素都是 type char *,那么compare()将收到两个指向 的指针char *,或者char **换句话说,是两个。

转换为char **(请注意,在这种特殊情况下,如果您不从void 指针转到非指针,则实际转换将是多余的)本身是必要的,因为必须处理任何类型的类型,因此参数在通过之前转换为。你不能尊重 a所以你必须在对它们做任何事情之前将它们转换回它们的原始类型。constconst 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数组的第一个和第二个元素时,它将发送第一个元素的地址(即base自身)和元素的地址(即base + size)。

如果base最初声明为 的数组int,则比较函数必须将其接收的那些指针解释为指向 的指针int,为int *。如果base最初声明为字符串数组,则为 a char **,则比较函数必须将这些指针解释为指向 的指针char *,即 as char **

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

在这种情况下,如果您只是将普通参数传递给比较函数,您显然可以调用。但是,因为是泛型的,它只能将指针传递给比较函数,它实际上不能传递元素的值——它的使用允许它是泛型的,因为任何类型的对象指针都可以转换为,但是没有可以将任何非指针值转换为的等效数据类型。因此,它必须以与常规类型相同的方式工作,例如和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;
}

输出:

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$

如您所见,由于函数在数组元素上执行的指针运算,如果函数没有获得需要将其视为 a 的指针,compare_any()就无法同时接受 的数组int和 的数组。如果没有这种额外的间接级别,既不也不能发挥作用。char *compare_string()char **compare_int()compare_double()

于 2013-10-22T20:26:19.550 回答