C qsort() with dynamic n by 2 multi-dimensional array

谁说我不能喝 提交于 2019-11-27 14:13:48

问题


First, I defined a dynamic array with 2 columns and 10 row. The integer number is set to 10 here just for example.

int** array;
int number = 10;

array = malloc(number * sizeof(int*));

for (i = 0; i < number; i++)
    array[i] = malloc(2 * sizeof(int));

Then I try to use qsort() on it.

qsort( array, number, sizeof array[0], compare );

This is my compare function. It sorts by the integer values in the first column, then sorts by the second column while preserving the order in the first column. E.g. "0 2, 1 7, 0 1" will become "0 1, 0 2, 1 7".

int compare ( const void *pa, const void *pb ) {
    int (*a)[1] = pa;
    int (*b)[1] = pb;
    if ( (a[0][0] < b[0][0]) || (a[0][0] == b[0][0])&&(a[1][0] < b[1][0]) ) return -1;
    if ( (a[0][0] > b[0][0]) || (a[0][0] == b[0][0])&&(a[1][0] > b[1][0]) ) return +1;
    return 0;
}

Question

This worked with a static array. I know it doesn't work now because I have a dynamic array, which is an array of pointers.

How can I adapt this code to work with the dynamically created multi-dimensional array?


回答1:


sample code

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

int compare ( const void *pa, const void *pb ) {
    const int *a = *(const int **)pa;
    const int *b = *(const int **)pb;
    if(a[0] == b[0])
        return a[1] - b[1];
    else
        return a[0] - b[0];
}
/*
#define NUMCMP(x,y) (((x) < (y)) ? -1 : ((x) > (y)) ? 1 : 0)

int compare ( const void *pa, const void *pb ) {
    const int (*a)[2] = *(const int (**)[2])pa;
    const int (*b)[2] = *(const int (**)[2])pb;
    int tmp;
    if((tmp=NUMCMP((*a)[0], (*b)[0]))==0)
        return NUMCMP((*a)[1], (*b)[1]);
    else
        return tmp;
}
*/    
int main(void){
    int **array;
    int number = 10;
    int i;

    array = malloc(number * sizeof(int*));
    for (i = 0; i < number; i++){
        array[i] = malloc(2 * sizeof(int));
        array[i][0] = rand()%20;
        array[i][1] = rand()%20;
    }
    for(i = 0;i < number;++i)
        printf("%2d, %2d\n", array[i][0], array[i][1]);

    printf("\n");

    qsort(array, number, sizeof array[0], compare);

    for(i = 0;i < number;++i)
        printf("%2d, %2d\n", array[i][0], array[i][1]);

    return 0;
}

what *(const int **)pa

array = {(int *), (int *), (int *), ... , (int *) }

qsort need each element address for element (for swap, etc. Because the size and number and start address of the element since only the given information).

E.g &(int *), &(int *)

so (int **) pass to function compare.

call compare(int **, int **) &(int*) meant at arg int**

compare function prototypeis cmp(const void*, const void*)

cast (const int**)pa is cast to passed original pointer.

*((const int **)pa) is dereference original element pointer(int*)




回答2:


Since you now have an array of pointers, the arguments to your comparison function are going to be pointers to pointers. Use them like this:

int *const *a = pa;
int *const *b = pb;

Now you have a and b as two pointers into the array you're sorting. Each one points to a single element that the sort function is asking you to examine. You can access these elements as *a and *b or a[0] and b[0] but should not ever use a[1] or b[1]. If the sort function asks you to compare the first element in the array (*a) and the fifth element in the array (*b), a[1] and b[1] are the second and sixth elements of the array - completely irrelevant to the comparison you're supposed to be doing.

After the first level of dereferencing, you're allowed to do whatever you need to do to examine the elements being compared. Since your array elements are themselves pointers to arrays (of 2 int each), the ints can be accessed as a[0][0] a[0][1] b[0][0] b[0][1]. Notice this is the opposite order from your a[1][0] and b[1][0].

Writing them as (*a)[0] would provide a reminder that the first level of indirection is a "single-element-access-only" pointer. I'm undecided on whether this makes the whole thing clearer.




回答3:


I came across this thread in search of a ditto problem of mine, and I lastly end-up doing the below thing.

static int compareMatrixElements(const void *p1, const void *p2)
{
    return ((*(int const *) p1) - (*(int const *) p2));
}

void sortMatrix(int** matrix, int r, int c)
{
    int sort_matrix[r][c];

    for(int i = 0; i < r; i++) {

        memcpy(sort_matrix[i], matrix[i], c * sizeof(int));
    }

    qsort(sort_matrix, r*c, sizeof(int), compareMatrixElements);

    for(int i = 0; i < r; i++) {

        memcpy(matrix[i], sort_matrix[i], c * sizeof(int));
    }
}

In the above code of mine I used qsort API directly, one can use this api or any other sort algo on a contiguous memory, but what If you are having a matrix whose rows are pointer to the memory of its columns (like in my case as well as described in the question of this thread). Hence I copied such matrix into a contiguous memory, ran sort on that contiguous memory and copied back the sorted elements to the matrix.

The above solution worked for me, I thought it might be helpful others so I posted it, suggest any improvement for the same.




回答4:


sizeof array[0] will be "2 * sizeof(int)", for this static array.

int array[10][2];

sizeof array[0] will be "sizeof(int*)", for this pointer-to-pointer. sizeof array[0][0] will be "sizeof(int)", for this pointer-to-pointer.

int **array;

So, First thing is you cannot use "qsort( array, number, sizeof array[0], compare );" in case of pointer-to-pointer implementation.



来源:https://stackoverflow.com/questions/17202178/c-qsort-with-dynamic-n-by-2-multi-dimensional-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!