[英]How to sort an `int **` array in C with native qsort
I've been unable to find any question regarding this, and I think I'm going a bit crazy trying to figure this out.我一直找不到关于此的任何问题,我想我想弄清楚这一点有点疯狂。
I have the following code:我有以下代码:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
int cmp_int(const void *a, const void *b)
{
return * (int *)a - * (int *)b;
}
int main(int argc, char *argv[])
{
int n = 10;
int **arr = calloc(n, sizeof(int *));
srand((unsigned int) time(NULL));
for (int i = n-1; i >= 0; i--) {
arr[i] = calloc(1, sizeof(int));
*(arr[i]) = rand() % 1000;
}
for (int i = 0; i < n; i++)
printf("%d ", *(arr[i]));
printf("\n");
qsort(arr, 10, sizeof(void *), cmp_int);
for (int i = 0; i < n; i++)
printf("%d ", *(arr[i]));
printf("\n");
free(arr);
return 0;
}
It's super basic, right?这是超级基本的,对吧? According to the manpage, the first argument is the pointer to the base element and the third argument is the size.根据联机帮助页,第一个参数是指向基本元素的指针,第三个参数是大小。 However, I fail to get the array as a sorted result.但是,我无法将数组作为排序结果。 I'm still really confused as to what the first and third argument to qsort should be since I suspect that that's where the fault is.对于 qsort 的第一个和第三个参数应该是什么,我仍然很困惑,因为我怀疑这就是问题所在。
Any help is appreciated.任何帮助表示赞赏。
Thanks.谢谢。
Edit: I should add that this code obviously does no error checking and that I was trying to test qsort with a double-pointer array of integers, so while yes I could use a regular array that was not the intended purpose of this code (it's actually part of a bigger segment in a separate program).编辑:我应该补充一点,这段代码显然没有进行错误检查,而且我试图用一个双指针整数数组来测试 qsort,所以虽然是的,我可以使用一个不是此代码预期目的的常规数组(它是实际上是单独程序中更大段的一部分)。
Your program makes my head hurt.你的程序让我头疼。 The reason you're not getting a correct sort is that the comparison function is wrong.您没有得到正确排序的原因是比较函数是错误的。 It would need to be return **(int **)a - **(int **)b;
它需要return **(int **)a - **(int **)b;
to get a correct result.以获得正确的结果。
However it's not worth fixing the problem that way.但是,以这种方式解决问题是不值得的。 A list of at least some of the issues:至少列出一些问题的清单:
argc
and argv
, don't declare them.如果您不使用argc
和argv
,请不要声明它们。srand
call is unnecessary.在srand
调用中强制转换是不必要的。int
comparison by subtraction is a bad idea because it can overflow.通过减法进行int
比较是一个坏主意,因为它可能会溢出。calloc
returns should always be checked for null (out of memory) results.应始终检查calloc
返回的 null(内存不足)结果。calloc
isn't needed at all.根本不需要calloc
。 Use a variable length array.使用可变长度数组。qsort
call uses a hard constant 10 rather than n
. qsort
调用使用硬常数 10 而不是n
。Here's a version that addresses these.这是一个解决这些问题的版本。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int cmp_int(const void *va, const void *vb)
{
int a = *(int *)va, b = *(int *) vb;
return a < b ? -1 : a > b ? +1 : 0;
}
void print(int *a, int n) {
for (int i = 0; i < n; ++i) printf("%d ", a[i]);
printf("\n");
}
int main(void)
{
int n = 10, a[n];
srand(time(0));
for (int i = 0; i < n; ++i) a[i] = rand() % 1000;
print(a, n);
qsort(a, n, sizeof a[0], cmp_int);
print(a, n);
return 0;
}
The problem you are having is failing to account for one additional level of indirection created by allocating for a block of pointers with int **arr = calloc (n, sizeof *arr);
您遇到的问题是无法解释通过使用int **arr = calloc (n, sizeof *arr);
分配一个指针块而创建的一个额外的间接级别int **arr = calloc (n, sizeof *arr);
and then allocating storage for a single int
to each pointer with arr[i] = calloc (1, sizeof *arr[i])
.然后使用arr[i] = calloc (1, sizeof *arr[i])
为每个指针分配单个int
存储空间。
Since the int compare (const void *a, const void *b)
compare function for qsort
expects a pointer to the elements of the array being sorted, both a
and b
above will be pointer-to-pointer to int
in your case requiring 2 levels of indirection be dereferenced before the integer values can be compared.由于qsort
的int compare (const void *a, const void *b)
比较函数需要一个指向正在排序的数组元素的指针,因此上面的a
和b
都是指向int
的指针,需要 2在可以比较整数值之前取消引用间接级别。
Rather than cmp_int
, you actually need a cmp_int_ptr
compare function.而不是cmp_int
,您实际上需要一个cmp_int_ptr
比较函数。 It can be written as:可以写成:
int cmp_int_ptr (const void *a, const void *b)
{
int *ai = *(int * const *)a,
*bi = *(int * const *)b;
return (*ai > *bi) - (*ai < *bi);
}
( note: the two levels of indirection in the cast (int * const *)
... which can also be written as (int **)
, but to correspond to the parameter type (const void *)
the (int * const *)
is proper) (注意: cast (int * const *)
... 中的两个间接级别也可以写成(int **)
,但要对应参数类型(const void *)
的(int * const *)
是正确的)
Putting that in place, adding validations for each allocation and cleaning up your calloc
type-size specification by using the dereferenced pointer itself to set type-size, you can do:把它放在适当的位置,为每个分配添加验证并通过使用取消引用的指针本身来设置类型大小来清理你的calloc
类型大小规范,你可以这样做:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
int cmp_int_ptr (const void *a, const void *b)
{
int *ai = *(int * const *)a,
*bi = *(int * const *)b;
return (*ai > *bi) - (*ai < *bi);
}
int main (void) {
int n = 10;
int **arr = calloc (n, sizeof *arr);
if (!arr) {
perror ("calloc-arr");
return 1;
}
srand((unsigned int) time(NULL));
for (int i = 0; i < n; i++) {
if (!(arr[i] = calloc (1, sizeof *arr[i]))) {
perror ("calloc-arr[i]");
return 1;
}
*(arr[i]) = rand() % 1000;
}
for (int i = 0; i < n; i++)
printf (" %d", *(arr[i]));
putchar ('\n');
qsort (arr, 10, sizeof *arr, cmp_int_ptr);
for (int i = 0; i < n; i++) {
printf (" %d", *(arr[i]));
free (arr[i]); /* don't forget to free your int allocated */
}
putchar ('\n');
free(arr); /* now free pointers */
}
Example Use/Output示例使用/输出
$ ./bin/qsortptrtoint
654 99 402 264 680 534 155 533 397 678
99 155 264 397 402 533 534 654 678 680
Look things over and let me know if you have questions.仔细检查一下,如果您有任何问题,请告诉我。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.