如何在C中对一个指针数组进行排序?

时间:2022-07-31 21:16:53

Suppose I have an array of pointers to char in C:

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

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

And I wish to sort this array using qsort:

我想用qsort对这个数组排序:

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

I am unable to come up with the compare function. For some reason this doesn't work:

我无法提出比较函数。由于某些原因,这行不通:

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

I did a lot of searching and found that I had to use ** inside of qsort:

我做了很多搜索,发现我必须在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_);
}

And this works.

这工作。

Can anyone explain the use of *(const char **)name1 in this function? I don't understand it at all. Why the double pointer? Why didn't my original function work?

谁能解释这个函数中*(const char **)name1的用法吗?我一点也不明白。为什么双指针?为什么我最初的功能不工作?

Thanks, Boda Cydo.

谢谢你,博达Cydo。

7 个解决方案

#1


17  

If it helps keep things straight in your head, the type that you should cast the pointers to in your comparator is the same as the original type of the data pointer you pass into qsort (that the qsort docs call base). But for qsort to be generic, it just handles everything as void*, regardless of what it "really" is.

如果它有助于保持您头脑中的东西,那么您应该在比较器中抛出指针的类型与您传入qsort的数据指针的原始类型相同(qsort docs调用base)。但是要让qsort是通用的,它只会把所有的东西都当作void*来处理,而不管它实际上是什么。

So, if you're sorting an array of ints, then you will pass in an int* (converted to void*). qsort will give you back two void* pointers to the comparator, which you convert to int*, and dereference to get the int values that you actually compare.

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

Now replace int with char*:

现在用char*替换int:

if you're sorting an array of char*, then you will pass in a char** (converted to void*). qsort will give you back two void* pointers to the comparator, which you convert to char**, and dereference to get the char* values you actually compare.

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

In your example, because you're using an array, the char** that you pass in is the result of the array of char* "decaying" to a pointer to its first element. Since the first element is a char*, a pointer to it is a char**.

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

#2


3  

Imagine your data was double data[5] .

假设您的数据是双数据[5]。

Your compare method would receive pointers (double*, passed as void*) to the elements (double).
Now replace double with char* again.

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

#3


2  

qsort is general enough to sort arrays consisting of other things than pointers. That's why the size parameter is there. It cannot pass the array elements to the comparison function directly, as it does not know at compile time how large they are. Therefore it passes pointers. In your case you get pointers to char *, char **.

qsort对数组进行排序的一般程度足以超过指针。这就是为什么这里有size参数。它不能直接将数组元素传递给比较函数,因为它在编译时不知道它们有多大。因此,通过指针。在您的例子中,您将获得指向char *、char **的指针。

#4


2  

The comparison function takes pointers to the type of object that's in the array you want to sort. Since the array contains char *, your comparison function takes pointers to char *, aka char **.

比较函数接受指向要排序的数组中的对象类型的指针。由于数组包含char *,所以比较函数接受指向char *的指针,即char **。

#5


0  

from man qsort:

从男人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.

So it sounds like the comparison function gets pointers to the array elements. Now a pointer to a char * is a char ** (i.e. a pointer to a pointer to a character).

听起来比较函数是指向数组元素的指针。现在指向char *的指针就是一个char **(也就是说指向一个字符的指针)。

#6


0  

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

char *数据[5]= {“博达”、“cydo”,“华盛顿”,“特区”,“奥巴马”};

is a statement asking the compiler for an array of size 5 of character pointers. You have initialized those pointers to string literals, but to the compiler, it's still an array of five pointers.

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

When you pass that array into qsort, the array of pointers decays into a pointer pointing to the first element, in accordance with C array parameter passing rules.

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

Therefore you must process one level of indirection before you can get to the actual character arrays containing the constants.

因此,在到达包含常量的实际字符数组之前,必须处理一个间接层。

#7


0  

@bodacydo here is a program that may explain what other programmers are trying to convey but this would be in context of "integers"

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

#1


17  

If it helps keep things straight in your head, the type that you should cast the pointers to in your comparator is the same as the original type of the data pointer you pass into qsort (that the qsort docs call base). But for qsort to be generic, it just handles everything as void*, regardless of what it "really" is.

如果它有助于保持您头脑中的东西,那么您应该在比较器中抛出指针的类型与您传入qsort的数据指针的原始类型相同(qsort docs调用base)。但是要让qsort是通用的,它只会把所有的东西都当作void*来处理,而不管它实际上是什么。

So, if you're sorting an array of ints, then you will pass in an int* (converted to void*). qsort will give you back two void* pointers to the comparator, which you convert to int*, and dereference to get the int values that you actually compare.

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

Now replace int with char*:

现在用char*替换int:

if you're sorting an array of char*, then you will pass in a char** (converted to void*). qsort will give you back two void* pointers to the comparator, which you convert to char**, and dereference to get the char* values you actually compare.

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

In your example, because you're using an array, the char** that you pass in is the result of the array of char* "decaying" to a pointer to its first element. Since the first element is a char*, a pointer to it is a char**.

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

#2


3  

Imagine your data was double data[5] .

假设您的数据是双数据[5]。

Your compare method would receive pointers (double*, passed as void*) to the elements (double).
Now replace double with char* again.

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

#3


2  

qsort is general enough to sort arrays consisting of other things than pointers. That's why the size parameter is there. It cannot pass the array elements to the comparison function directly, as it does not know at compile time how large they are. Therefore it passes pointers. In your case you get pointers to char *, char **.

qsort对数组进行排序的一般程度足以超过指针。这就是为什么这里有size参数。它不能直接将数组元素传递给比较函数,因为它在编译时不知道它们有多大。因此,通过指针。在您的例子中,您将获得指向char *、char **的指针。

#4


2  

The comparison function takes pointers to the type of object that's in the array you want to sort. Since the array contains char *, your comparison function takes pointers to char *, aka char **.

比较函数接受指向要排序的数组中的对象类型的指针。由于数组包含char *,所以比较函数接受指向char *的指针,即char **。

#5


0  

from man qsort:

从男人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.

So it sounds like the comparison function gets pointers to the array elements. Now a pointer to a char * is a char ** (i.e. a pointer to a pointer to a character).

听起来比较函数是指向数组元素的指针。现在指向char *的指针就是一个char **(也就是说指向一个字符的指针)。

#6


0  

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

char *数据[5]= {“博达”、“cydo”,“华盛顿”,“特区”,“奥巴马”};

is a statement asking the compiler for an array of size 5 of character pointers. You have initialized those pointers to string literals, but to the compiler, it's still an array of five pointers.

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

When you pass that array into qsort, the array of pointers decays into a pointer pointing to the first element, in accordance with C array parameter passing rules.

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

Therefore you must process one level of indirection before you can get to the actual character arrays containing the constants.

因此,在到达包含常量的实际字符数组之前,必须处理一个间接层。

#7


0  

@bodacydo here is a program that may explain what other programmers are trying to convey but this would be in context of "integers"

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