27

假设我在 C 中有一个指向 char 的指针数组:

char *data[5] = { "boda", "cydo", "washington", "dc", "obama" };

我希望使用 qsort 对这个数组进行排序:

qsort(data, 5, sizeof(char *), compare_function);

我无法提出比较功能。由于某种原因,这不起作用:

int compare_function(const void *name1, const void *name2)
{
    const char *name1_ = (const char *)name1;
    const char *name2_ = (const char *)name2;
    return strcmp(name1_, name2_);
}

我做了很多搜索,发现我必须**在 qsort 内部使用:

int compare_function(const void *name1, const void *name2)
{
    const char *name1_ = *(const char **)name1;
    const char *name2_ = *(const char **)name2;
    return strcmp(name1_, name2_);
}

这有效。

谁能解释一下*(const char **)name1这个函数的用法?我完全不明白。为什么是双指针?为什么我原来的功能不起作用?

谢谢,博达赛多。

4

8 回答 8

25

如果它有助于保持头脑清醒,那么您应该在比较器中将指针转换为的类型与您传入的数据指针的原始类型相同qsort(qsort 文档调用base)。但是为了qsort通用,它只是将所有内容处理为void*,而不管它“真正”是什么。

因此,如果您正在对一个整数数组进行排序,那么您将传入一个int*(转换为void*)。qsort 将返回两个void*指向比较器的指针,您将其转换为int*,并取消引用以获取int您实际比较的值。

现在替换intchar*

如果您正在对 的数组进行排序char*,那么您将传入一个char**(转换为void*)。qsort 将返回两个void*指向比较器的指针,您将其转换为char**,并取消引用以获取char*您实际比较的值。

在您的示例中,因为您使用的是数组,所以char**您传入的是数组char*“衰减”到指向其第一个元素的指针的结果。由于第一个元素是 a char*,指向它的指针是 a char**

于 2010-08-15T22:47:14.873 回答
3

想象一下您的数据是double data[5].

您的比较方法将接收指向元素(双精度)的指针(双精度*,作为 void* 传递)。
现在再次用 char* 替换 double 。

于 2010-08-15T20:45:22.933 回答
2

比较函数将指针指向要排序的数组中的对象类型。由于数组包含char *,因此您的比较函数将指针指向char *,也就是char **

于 2010-08-16T03:53:37.003 回答
2

qsort足以对由指针以外的其他内容组成的数组进行排序。这就是 size 参数存在的原因。它不能将数组元素直接传递给比较函数,因为它在编译时不知道它们有多大。因此它传递指针。在您的情况下,您会得到指向char *,的指针char **

于 2010-08-15T20:45:58.683 回答
0

来自man qsort

The  contents of the array are sorted in ascending 
order according to a comparison function pointed to by
compar, which is called with two arguments that **point**
to the objects being compared.

所以听起来比较函数获取指向数组元素的指针。现在指向 a 的指针char *是 a char ** (即指向字符指针的指针)。

于 2010-08-15T20:49:56.890 回答
0

char *data[5] = { "boda", "cydo", "washington", "dc", "obama" };

是一条语句,要求编译器提供一个大小为 5 的字符指针数组。您已经将这些指针初始化为字符串文字,但对于编译器来说,它仍然是一个由五个指针组成的数组。

根据 C 数组参数传递规则,当您将该数组传递给 时qsort,指针数组会衰减为指向第一个元素的指针。

因此,您必须先处理一级间接,然后才能访问包含常量的实际字符数组。

于 2010-08-15T20:50:43.837 回答
0

也许给你一个我的代码示例更容易。我正在尝试对 TreeNodes 数组进行排序,比较器的前几行如下所示:

int compareTreeNode(const void* tt1, const void* tt2) {
   const TreeNode *t1, *t2;
   t1=*(const TreeNode**)tt1;
   t2=*(const TreeNode**)tt2;

之后,您使用 t1 和 t2 进行比较。

于 2019-01-21T07:49:27.637 回答
0

@bodacydo 这里是一个程序,可以解释其他程序员试图传达的内容,但这将是在“整数”的上下文中

#include <stdio.h>


int main()
{
    int i , j;
    int *x[2] = {&i, &j};

    i = 10; j = 20;

    printf("in main() address of i = %p, address of j = %p \r\n", &i, &j);

    fun(x);
    fun(x + 1);

    return 0;
}


void fun(int **ptr)
{
    printf("value(it would be an address) of decayed element received = %p, double dereferenced value is %d \r\n",*ptr, **ptr);
    printf("the decayed value can also be printed as *(int **)ptr = %p \r\n", *(int **)ptr );
}
于 2017-01-06T04:13:11.247 回答