下面是比较函数:
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;
出口呼叫:
qsort(wordlist, nbr_words, sizeof(char *), compare);
最佳答案
如果您显示了wordlist
的定义,这会有所帮助,但很可能它被定义为char **
。compare()
函数接收指向列表中每个元素的指针。如果列表中的每个元素都是char *
类型,那么compare()
将接收到两个指向char *
的指针,换句话说就是两个char **
。
转换为char **
(注意,在这种特殊情况下,如果不从const
void指针转换到非-const
char **
)本身是多余的,因为qsort()
必须处理任何类型,因此参数在传递之前都转换为void *
。不能遵从avoid *
,因此在对它们执行任何操作之前,必须将它们转换回原始类型。
例如:
#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()
函数将比较支持的任何类型,在本例中是int
和double
,因为我们可以向它传递函数指针。但是,传递函数的签名必须相同,因此不能声明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
的数组,那么compare函数必须将接收到的指针解释为int
,即int
。如果int *
最初声明为字符串数组,则compare函数必须将这些指针解释为指向base
的指针,即char **
。在所有情况下,compare函数都会获取指向元素的指针。如果有一个
char *
数组,那么必须在compare函数中将这些指针解释为char **
。如果有int
数组,则必须将其解释为int *
,依此类推。在这种情况下,如果只向compare函数传递了普通的
char *
参数,显然可以调用char **
。但是,由于strcmp()
是泛型的,它只能将指针传递给compare函数,实际上它不能传递元素的值-这是使用char *
允许它是泛型的,因为任何类型的对象指针都可以转换为qsort()
,但是没有可转换任何非指针值的等效数据类型。因此,它必须与常规类型(如void *
和void *
)、指针和结构(structs)的工作方式相同,而让它正确处理所有可能类型的唯一方法是让它处理指向元素的指针,而不是元素本身,即使元素本身也是指针。出于这个原因,这里看起来您获得了一个不必要的间接级别,但实际上,为了使int
能够以其通用的方式工作,这是必要的。如果我修改上面的代码,使
double
更类似于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()
函数没有得到它需要视为qsort()
的指针,则compare_any()
无法同时接受int
数组和char *
数组,因为它对数组元素执行指针运算。如果没有这种额外的间接作用,无论是compare_string()
还是char **
都不能起作用。
关于c - Qsort使用的比较功能-比较(char **),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19527504/