2013-10-29 152 views
0

我是一个初学C程序员,想习惯术语和指针。 我在搜索排序数值数组元素的方法时发现了以下工作函数原型。该函数是qsort,它使用指针。现在我所理解的是,“const”这个词确保了值a和b不变,但不是指针。如果我在这里错了,请纠正我。我的问题是:混淆Qsort和指针

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

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

非常感谢您的答案。 PS:这对我来说是一项相当复杂的任务。

回答

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

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

ADDIT通过H2CO3建议使用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 
+0

+1这真的很有帮助。虽然(也包括一个建议:转换为const const *会更合适),但值得澄清'const const限定符在'const void *'中的含义。 – 2013-10-29 22:36:33

+0

第二个星号是要尊重它,然后? – Vesnog

+1

@Vesnog *(int *)a'中的第二个星号是转换为'int *':(变量前面有一个括号中的类型指示符)将该变量转换为该类型,在本例中为指向int ')。然后,第一个星号将取消引用'int *'来获得'int'。 – Kninnug

0

qsort()函数是通用算法这是实现为通用程序的一个示例。这个想法是为排序任意对象,而不仅仅是intfloat。由于这个原因(并且因为C语言设计),qsort()会采取一种比较函数作为接受两个通用(C语义)指针的参数。它由该函数(由qsort()用户提供)将这些指针转换为正确的类型,执行正确的比较并返回排序指示。

同样,由于qsort()预先不知道对象有多大,它需要的对象的大小作为参数。就qsort()而言,这些对象是连续排列在内存中的相同大小的字节的斑点。

最后,因为无论是操作的qsort()执行可能会导致一个错误,它不会返回错误代码。其实有的情况下qsort()可能会失败,这是传递给它的参数不合法,但在许多其他标准C库函数的传统,它并不能保证在这样的情况下,有前途的不确定的行为参数的任何错误检查。

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

在这种情况下,这不是太重要,但作为比较funcion变得复杂,你可能希望得到您的变量做比较之前的“你的类型”。

既然你在下面的评论问,这里是一个非常一步一步版本:

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; 
} 
+0

因此,表达式*(int *)a中的第二个*是否获得了一个值的解除引用? – Vesnog

+0

(int *)部分将一个void从void *转换为int *。 (int *)的左边的*将int *解引用为int。 –

+0

好吧说得对。顺便说一句,计算机术语的含义是什么?谢谢 – Vesnog

2

现在,我的理解是,这个词“常量”保证价值ab不变但不是指针

你理解错了。

const int *a; 

声明a作为指针恒定int类型。这意味着字const确保您不能通过修改*a修改变量a指向的值。

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

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

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

*(int *)被用于铸造a为指针,以int,然后取消引用它来获取存储在位置值它指向。

+1

+1第一个误解在其他答案中没有解决。 – 2013-10-29 23:03:03