簡體   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