C使用qsort对二维整数数组进行排序

C sort 2D integer array with qsort

你有什么问题?

我正在尝试使用 C 中的 qsort 函数对二维整数数组进行排序,但我 出现分段错误。 当我使用以下命令编译它时:

gcc -g -lm -Werror -Wfatal-errors -Wall -Wextra -Wuninitialized -fsanitize=address -pedantic -Wshadow -std=c99 Test2.c

然后执行它,我收到此错误消息:

AddressSanitizer:DEADLYSIGNAL
=================================================================
==347270==ERROR: AddressSanitizer: SEGV on unknown address 0x00147fff8c06 (pc 0x556f9e44d2bb bp 0x7ffe9684a5f0 sp 0x7ffe9684a5d0 T0)
==347270==The signal is caused by a READ memory access.
    #0 0x556f9e44d2bb in compare /windows/Programming/C/Random_Stuff/Test2.c:8
    #1 0x7f17aa2718d7 in msort_with_tmp.part.0 (/usr/lib/libc.so.6+0x3e8d7)
    #2 0x7f17aa2716b4 in msort_with_tmp.part.0 (/usr/lib/libc.so.6+0x3e6b4)
    #3 0x7f17aa2716b4 in msort_with_tmp.part.0 (/usr/lib/libc.so.6+0x3e6b4)
    #4 0x7f17aa271a79 in __qsort_r (/usr/lib/libc.so.6+0x3ea79)
    #5 0x556f9e44d657 in main /windows/Programming/C/Random_Stuff/Test2.c:64
    #6 0x7f17aa25ab24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)
    #7 0x556f9e44d13d in _start (/windows/Programming/C/Random_Stuff/a.out+0x113d)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /windows/Programming/C/Random_Stuff/Test2.c:8 in compare
==347270==ABORTING

提示:请不要被目录名激怒windows,我在 linux.

代码

简化示例

在下面的代码中,我创建了一个 10x10 数组,如下所示:

[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9]
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
[30, 31, 32, 33, 34, 35, 36, 37, 38, 39]
[40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
[50, 51, 52, 53, 54, 55, 56, 57, 58, 59]
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69]
[70, 71, 72, 73, 74, 75, 76, 77, 78, 79]
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89]
[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]

现在我想根据每个子数组的特定索引,以与“第一个”数组相反的顺序对这些“行”进行排序。 所以它最终应该是这样的:

[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89]
[70, 71, 72, 73, 74, 75, 76, 77, 78, 79]
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69]
[50, 51, 52, 53, 54, 55, 56, 57, 58, 59]
[40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
[30, 31, 32, 33, 34, 35, 36, 37, 38, 39]
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9]

原案

在我原来的情况下,我有类似的东西:

[8,  18, 2, 20, 0]
[13, 18, 3, 15, 1]
[8,  18, 3, 30, 2]
[8,  13, 3, 15, 3]
[8,  13, 2, 10, 4]
[8,  15, 1, 7, 5]
[13, 18, 2, 10, 6]
[13, 17, 6, 24, 7]
[8,  13, 1, 5, 8]
[8,  13, 2, 10, 9]
[13, 18, 2, 10, 10]
[8,  13, 4, 20, 11]
[8,  12, 4, 16, 12]
[8,  13, 1, 5, 13]
[13, 15, 8, 16, 14]
[9,  14, 6, 30, 15]
[8,  14, 1, 6, 16]

现在我想根据每个的第四个值对这些“子数组”进行排序 子数组,所以它应该是这样的:

[8,  13, 1, 5, 8]
[8,  13, 1, 5, 13]
[8,  14, 1, 6, 16]
[8,  15, 1, 7, 5]
[8,  13, 2, 10, 4]
[13, 18, 2, 10, 6]
[8,  13, 2, 10, 9]
[13, 18, 2, 10, 10]
[13, 18, 3, 15, 1]
[8,  13, 3, 15, 3]
[8,  12, 4, 16, 12]
[13, 15, 8, 16, 14]
[8,  18, 2, 20, 0]
[8,  13, 4, 20, 11]
[13, 17, 6, 24, 7]
[8,  18, 3, 30, 2]
[9,  14, 6, 30, 15]

你试过什么?

我看到了这个 post: Sorting a 2D array with qsort 但是如果我将它与 post.

#include <stdio.h>
#include <stdlib.h>

int compare(const void * a, const void * b)
{
    // "const void * a" points to "&nums[x]", right?
    unsigned short val1 = (*(unsigned short **) a) [3];
    unsigned short val2 = (*(unsigned short **) b) [3];

    if (val1 < val2)
        return 1;

    else if (val1 == val2)
        return 0;

    return -1;
}

int main()
{
    unsigned short **    nums;
    unsigned short       num;
    unsigned short       index;
    unsigned short       index2;
    const unsigned short length     = 10;
    const unsigned short sub_length = 10;

    /* -----------------
     * Preparations
     * ----------------- */
    nums = malloc(sizeof(unsigned short *) * length);
    num  = 0;

    if (nums == NULL)
        return EXIT_FAILURE;

    /* ------------
     * Filling
     * ------------ */
    for (index = 0; index < length; index++)
    {
        nums [index] = malloc(sizeof(unsigned short) * sub_length);

        if (nums [index] == NULL)
            return EXIT_FAILURE;

        // Fill each subarray with random nums
        for (index2 = 0; index2 < sub_length; index2++)
            nums [index][index2] = num++;
    }

    // "Before" output
    printf("Before:\n");
    for (index = 0; index < length; index++)
    {
        printf("[");
        for (index2 = 0; index2 < sub_length - 1; index2++)
            printf("%2hu, ", nums [index][index2]);
        printf("%2hu]\n", nums [index][sub_length - 1]);
    }

    // ================
    // What am I doing wrong?
    qsort(nums, length, sizeof(unsigned short) * sub_length, compare);
    // ================

    // "After" output
    printf("After:\n");
    for (index = 0; index < length; index++)
    {
        printf("[");
        for (index2 = 0; index2 < sub_length - 1; index2++)
            printf("%2hu, ", nums [index][index2]);
        printf("%2hu]\n", nums [index][sub_length - 1]);
    }

    /* ------------
     * Cleanup
     * ------------ */
    for (index = 0; index < length; index++)
        free(nums [index]);
    free(nums);

    return EXIT_SUCCESS;
}

为了对行进行排序,您必须了解 qsort 的相邻元素将 指向 unsigned short。由于 qsort compare 采用 指向相邻元素的指针 ,这将是指向 unsigned short 指针。所以你在比较中有两级间接处理,例如

/* compare for adjacent ROW pointers - descending order */
int compare_desc (const void *a, const void *b)
{
    unsigned short *pa = *(unsigned short * const *)a,
                   *pb = *(unsigned short * const *)b;
    
    return (*pa < *pb) - (*pa > *pb);
}

现在一个简短的例子是:

#include <stdio.h>
#include <stdlib.h>

#define ROWS 10
#define COLS ROWS

/* compare for adjacent ROW pointers - descending order */
int compare_desc (const void *a, const void *b)
{
    unsigned short *pa = *(unsigned short * const *)a,
                   *pb = *(unsigned short * const *)b;
    
    return (*pa < *pb) - (*pa > *pb);
}

int main (void) {
    
    unsigned short **nums = NULL;
    
    nums = malloc (ROWS * sizeof *nums);
    if (!nums) {
        perror ("malloc-nums");
        exit (EXIT_FAILURE);
    }
    
    for (int i = 0; i < ROWS; i++) {
        nums[i] = malloc (COLS * sizeof *nums[i]);
        if (!nums[i]) {
            perror ("malloc-nums[i]");
            exit (EXIT_FAILURE);
        }
        for (int j = 0; j < COLS; j++) {
            nums[i][j] = i * COLS + j;
            printf (j ? " %3hu" : "%3hu", nums[i][j]);
        }
        putchar ('\n');
    }
    
    qsort (nums, ROWS, sizeof *nums, compare_desc);
    
    puts ("\nrows sorted descending, columns sorted ascending\n");
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++)
            printf (j ? " %3hu" : "%3hu", nums[i][j]);
        putchar ('\n');
        free (nums[i]);
    }
    free (nums);
}

示例Use/Output

$ ./bin/qsort_ptr2ptr
  0   1   2   3   4   5   6   7   8   9
 10  11  12  13  14  15  16  17  18  19
 20  21  22  23  24  25  26  27  28  29
 30  31  32  33  34  35  36  37  38  39
 40  41  42  43  44  45  46  47  48  49
 50  51  52  53  54  55  56  57  58  59
 60  61  62  63  64  65  66  67  68  69
 70  71  72  73  74  75  76  77  78  79
 80  81  82  83  84  85  86  87  88  89
 90  91  92  93  94  95  96  97  98  99

rows sorted descending, columns sorted ascending

 90  91  92  93  94  95  96  97  98  99
 80  81  82  83  84  85  86  87  88  89
 70  71  72  73  74  75  76  77  78  79
 60  61  62  63  64  65  66  67  68  69
 50  51  52  53  54  55  56  57  58  59
 40  41  42  43  44  45  46  47  48  49
 30  31  32  33  34  35  36  37  38  39
 20  21  22  23  24  25  26  27  28  29
 10  11  12  13  14  15  16  17  18  19
  0   1   2   3   4   5   6   7   8   9

让我知道这是否是您想要的,如果您还有其他问题。