当我学习使用qsort对字符串数组进行排序时,有一个问题困惑我。
例如,要对以下s
char *s[] = {
"Amit",
"Garima",
"Gaurav",
"Vaibhav"
};
要使用qsort,您必须提供类似的比较功能
跟随函数cstring_cmp
我想在qsort函数中,要传递给函数cstring_cmp
的参数类型是char**
。如何将char**
转换为void*
?为什么我们可以将char**
转换为void*
?
int cstring_cmp(const void *a, const void *b)
{
const char **ia = (const char **)a;
const char **ib = (const char **)b;
return -strcasecmp(*ia, *ib);
/* return the negative of the normal comparison */
}
答案 0 :(得分:2)
你的问题看起来有点模糊,但无论如何我都会试一试。要回答如何,您可以通过简单转换将任何指针类型转换为C中的任何其他指针类型。要回答为什么,那就是C的定义方式。
qsort()
函数需要具有给定原型(带有const void *
)参数的函数。这是因为qsort()
不知道您正在排序的实际数据类型,并且必须使用一致的函数原型进行比较回调。您的比较回调负责将const void *
参数转换为指向数组中实际类型的指针,例如const char **
。
答案 1 :(得分:2)
您提供的示例正在设置为要求qsort()
对char指针数组(char *)进行排序。您提供的这个比较器会给出算法所需的每对“项目”,按地址。两个char指针。地址qsort()
使用的地址基于您提供的根地址,每个“项目”添加大小字节数。由于每个“item”都是char *,因此每个项目的大小实际上是指针的大小。
我已经修改了比较器以演示正在比较的内容,以及传入的地址是什么。您将看到它们都是包含所有char * s的数组基址的增量。
char *mystrings[] =
{
"This",
"is",
"a",
"test",
"of",
"pointers",
"to",
"strings"
};
int cstring_cmp(const void *a, const void *b)
{
const char **ia = (const char **)a;
const char **ib = (const char **)b;
printf("%p:%s - %p:%s\n", a, *ia, b, *ib);
return -strcasecmp(*ia, *ib);
}
int main(int argc, char *argv[])
{
printf("Base address of our pointer array: %p\n\n", mystrings);
qsort(mystrings, sizeof(mystrings)/sizeof(mystrings[0]), sizeof(char*), cstring_cmp);
for (size_t i=0; i<sizeof(mystrings)/sizeof(mystrings[0]);i++)
printf("%s\n", mystrings[i]);
return 0;
}
产生以下输出:
Base address of our pointer array: 0x100006240
0x100006240:This - 0x100006260:of
0x100006260:of - 0x100006278:strings
0x100006240:This - 0x100006278:strings
0x100006248:is - 0x100006240:strings
0x100006278:This - 0x100006240:strings
0x100006250:a - 0x100006240:strings
0x100006270:to - 0x100006240:strings
0x100006258:test - 0x100006240:strings
0x100006260:of - 0x100006240:strings
0x100006268:pointers - 0x100006240:strings
0x100006260:of - 0x100006240:strings
0x100006240:test - 0x100006248:This
0x100006248:test - 0x100006250:to
0x100006240:This - 0x100006248:to
0x100006260:of - 0x100006268:pointers
0x100006268:of - 0x100006270:a
0x100006270:a - 0x100006278:is
0x100006268:of - 0x100006270:is
to
This
test
strings
pointers
of
is
a
答案 2 :(得分:0)
更不可视化的一个:
int cstring_cmp(const void *a, const void *b){
return -strcasecmp((char *)(*((char **)a)), (char *)(*((char **)b)));
}
但是你可以看到,a
和b
是char **
,他们被解除引用并成为char *
并传递给strcasecmp
。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int cstring_cmp(const void *a, const void *b){
return -strcasecmp((char *)(*((char **)a)), (char *)(*((char **)b)));
}
int main(){
char *s[] = { "Amit",
"Garima",
"Vaibhav",
"Gaurav"};
qsort(s, 4, sizeof(char *), cstring_cmp);
printf("%s\n%s\n%s\n%s\n", s[0], s[1], s[2], s[3]);
return 0;
}
输出:
Vaibhav
Gaurav
Garima
Amit
将任何指针强制转换为char *
或void *
是合法的,因为void *
表示指向内存(RAM或虚拟)字节的指针。