对Qsort和Pointers感到困惑

时间:2013-10-29 22:24:08

标签: c pointers qsort

我是C的初学程序员,想要习惯术语和指针。 我在寻找一种对数值数组元素进行排序的方法时,找到了以下工作函数原型。函数是qsort,它使用指针。现在我所理解的是,“const”这个词确保了值a和b不变,但指针却没有。如果我在这里错了,请纠正我。我的问题是:

  1. 为什么我们使用void *函数我们不能使用int * 开始?
  2. 返回部分中的构造*(int*)a如何 工作?
  3. 为什么qsort算法需要这么多参数?

    int compare (const void *a, const void *b)
    {
         return ( *(int*)a - *(int*)b ); 
    }
    
  4. 非常感谢答案。 PS:对我来说,这是一项非常复杂的任务。

4 个答案:

答案 0 :(得分:2)

  1. qsort以这种方式制作,因此可以用作通用分类器。如果它从一开始就使用int,它只能用于比较整数。这样,您也可以通过将strcmp作为比较函数传递给qsort来对字符串进行排序。
  2. *(int*)aa转换为指向int的指针,然后取消引用它,以便获得存储在a的整数。请注意,这不会更改aa指向的值。
  3. qsort需要4个参数:要排序的数组,该数组中元素的数量以及元素的大小,最后是比较函数。它需要所有这些信息,因为它再次被认为是尽可能通用的。

    它需要元素的数量,因为在C指针中不包含有关它们之后的缓冲区大小的信息。并且它需要知道每个元素的大小,以便它可以正确地将元素传递给比较函数。例如,要比较int,您可以将sizeof(int)作为尺寸参数。要比较字符串,请使用sizeof(char *)

  4. 根据H2CO3的建议

    ADDIT 使用const void *的原因是指示比较函数可能不会更改ab指向的值。当然,这是为了确保对数组进行排序不会突然改变数组中的值。而且,正如H2CO3所说的那样,投射到(const int *)会更加清晰,这样你就不会在投射后不小心改变它:

    return *(const int *)a - *(const int *)b;
    

    你也可以通过以下方式摆脱演员阵容:

    int compare(const void * a, const void * b){
        const int * ia = a;
        const int * ib = b;
    
        return *ia - *ib;
    }
    

    取决于你对演员表的喜好。 (我更愿意避开它们)

    最后,澄清星号:

    *(int *)a
    ^     ^
    |     └ cast to integer pointer
    └ dereference (integer) pointer
    

答案 1 :(得分:2)

  

现在我所理解的是" const"确保值ab不变,但指针

你理解错了。

 const int *a;  

a声明为常量int类型的指针。这意味着单词const可确保您无法通过修改a来修改变量*a指向的值。

  

为什么我们使用void *函数我们从一开始就不能使用int *?

void *用于指出任何类型的变量。

  

返回部分的构造*(int*)a如何工作?

*(int *)用于将a转换为指向int的指针,然后取消引用它以获取存储在其指向的位置的值。

答案 2 :(得分:1)

其他答案非常好。我只想补充一点,如果你在回调函数中非常清楚,它会更容易阅读。

int compare (const void *a, const void *b)
{
     return ( *(int*)a - *(int*)b ); 
}

变为

int compare (const void *a, const void *b)
{
    int ia = *(int *)a;
    int ib = *(int *)b;
    return ia - ib;
}

在这种情况下,它并不太重要,但是当您的比较功能变得复杂时,您可能希望在进行比较之前将变量设置为“您的类型”。

由于您在下面的评论中提到过,这是一个非常循序渐进的版本:

int compare (const void *a, const void *b)
{
    int *pa = (int *)a;
    int *pb = (int *)b;
    int ia = *pa;
    int ib = *pb;
    return ia - ib;
}

答案 3 :(得分:0)

qsort()函数是泛型算法的一个示例,它是作为通用例程实现的。我们的想法是使其对排序任意对象很有用,而不仅仅是intfloat。因此(并且由于C语言设计),qsort()采用比较函数作为接受两个通用(在C意义上)指针的参数。该函数(由qsort()用户提供)可以将这些指针强制转换为正确的类型,执行正确的比较并返回排序指示。

同样,由于qsort()事先并不知道对象的大小,因此它将对象大小作为参数。就qsort()而言,对象是在内存中连续排列的大小相等的字节。

最后,由于qsort()执行的操作都不会导致错误,因此不会返回错误代码。实际上 qsort()可能失败的情况,这是传递给它的非法参数,但是在许多其他标准C库例程的传统中,它不保证对参数的任何错误检查在这种情况下承诺未定义的行为。