简体   繁体   中英

Why qsort int array in descending order is incorrect?

I tried writing the compare function for qsorting an int array. And it gives correct results for ascending order. But is incorrect for descending order. Why? What would be a correct compare int function?

int compare(const void *a, const void *b){
    int x = *(int*)a;
    int y = *(int*)b;
    return (x > y) - (x < y);
}

int reverse(const void *a, const void *b){
    return -compare(a, b);
}

int main(){
    int x[] = {500, 456, 18, 13, 3, 89, 800, 6874};
    qsort(x, sizeof(x[0]), sizeof(x)/sizeof(x[0]), reverse);
    for (int i=0; i < sizeof(x)/sizeof(x[0]); i++){
    printf("%d\n", x[i]);

    return 0;
}

I expected descending order of printed ints from largest 6874 to smallest 3. But I received instead:

800 6874 500 456 18 13 3 89

You've swapped the second and third arguments of qsort -- it should be

qsort(x, sizeof(x)/sizeof(x[0]), sizeof(x[0]), reverse);

The way you are calling it, since your array happens to be 8 elements and sizeof(int) happens to be 4 on your machine, it is sorting pairs of ints based on the first int of each pair.

Before dealing with other aspects, you have switched the second and third parameters to qsort(3) the first is the array pointer, the second the number of elements, the third of size, and the fourth is the comparison function pointer. To make a good qsort(3) you first need to put the parameters in the correct order :) .

Well, compare() function must return < 0 (not -1) if a is lesser than b , > 0 (and not +1) if a is greater than b and zero in case a and b are equal. Your formula is correct, but a little overcomplicated expression, for something that can be achieved by just subtracting both parameters. If you check what many implementations of strcpy(3) do return (well, not all, but many) is the difference between char codes at the position both strings differ, which is enough to do an efficient implementation.

By the way, you know that a void * is a pointer compatible with any other pointer type, so one of the best ways to write a comparison function (based on references to integers and not on their values) is to write it like this:

int compare(int *a, int *b) 
{
    return *a - *b;
}

int reverse_compare(int *a, int *b) 
{
    return -compare(a, b);
}

(you'll get an ignorable warning in the call to qsort(3) ) or even simpler

int reverse_compare(int *a, int *b) 
{
    return compare(b, a);
}

and pass it directly to qsort(3) . Indeed, the reverse compare takes just the two pointers, and can be made completely generic by writing it as:

int reverse_compare(const void *a, const void *b)
{
    return compare(b, a);
}

pru.c

If you check the following example, you'll see that reverse is the routine passed to qsort (no warnings as the parameters match, and no warnings inside the body of reverse when converting them to void * in the call to compare_int .)

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

int compare_int(const int *a, const int *b)
{
    return (*a > *b) - (*b > *a);
}

int reverse(const void *a, const void *b)
{
    return compare_int(b, a);
}

int main()
{
    int x[] = {500, 456, 18, 13, 3, 89, 800,
        6874};
    qsort(x,
        sizeof(x)/sizeof(x[0]),
        sizeof(x[0]),
        reverse);
    for (int i=0; i <
            sizeof(x)/sizeof(x[0]); i++) {
        printf("%d\n", x[i]);
    }

    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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