繁体   English   中英

如何使用本机 qsort 在 C 中对 `int **` 数组进行排序

[英]How to sort an `int **` array in C with native qsort

我一直找不到关于此的任何问题,我想我想弄清楚这一点有点疯狂。

我有以下代码:

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

这是超级基本的,对吧? 根据联机帮助页,第一个参数是指向基本元素的指针,第三个参数是大小。 但是,我无法将数组作为排序结果。 对于 qsort 的第一个和第三个参数应该是什么,我仍然很困惑,因为我怀疑这就是问题所在。

任何帮助表示赞赏。

谢谢。

编辑:我应该补充一点,这段代码显然没有进行错误检查,而且我试图用一个双指针整数数组来测试 qsort,所以虽然是的,我可以使用一个不是此代码预期目的的常规数组(它是实际上是单独程序中更大段的一部分)。

你的程序让我头疼。 您没有得到正确排序的原因是比较函数是错误的。 它需要return **(int **)a - **(int **)b; 以获得正确的结果。

但是,以这种方式解决问题是不值得的。 至少列出一些问题的清单:

  • 如果您不使用argcargv ,请不要声明它们。
  • srand调用中强制转换是不必要的。
  • 通过减法进行int比较是一个坏主意,因为它可能会溢出。
  • 应始终检查calloc返回的 null(内存不足)结果。
  • 根本不需要calloc 使用可变长度数组。
  • 无需分配指向 int 的指针数组。 只需分配一个整数数组。 然后您的比较按原样进行。
  • qsort调用使用硬常数 10 而不是n
  • 通过取消引用数组名称来给出元素大小不太容易出错。
  • 最后,您释放了“spine”数组,但永远不会释放整数元素。
  • 您应该分解出一个函数来打印数组。

这是一个解决这些问题的版本。

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

您遇到的问题是无法解释通过使用int **arr = calloc (n, sizeof *arr);分配一个指针块而创建的一个额外的间接级别int **arr = calloc (n, sizeof *arr); 然后使用arr[i] = calloc (1, sizeof *arr[i])为每个指针分配单个int存储空间。

由于qsortint compare (const void *a, const void *b)比较函数需要一个指向正在排序的数组元素的指针,因此上面的ab都是指向int的指针,需要 2在可以比较整数值之前取消引用间接级别。

而不是cmp_int ,您实际上需要一个cmp_int_ptr比较函数。 可以写成:

int cmp_int_ptr (const void *a, const void *b)
{
    int *ai = *(int * const *)a,
        *bi = *(int * const *)b;

    return (*ai > *bi) - (*ai < *bi);
}

注意: cast (int * const *) ... 中的两个间接级别也可以写成(int **) ,但要对应参数类型(const void *)(int * const *)是正确的)

把它放在适当的位置,为每个分配添加验证并通过使用取消引用的指针本身来设置类型大小来清理你的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 */
}

示例使用/输出

$ ./bin/qsortptrtoint
 654 99 402 264 680 534 155 533 397 678
 99 155 264 397 402 533 534 654 678 680

仔细检查一下,如果您有任何问题,请告诉我。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM