简体   繁体   中英

qsort not working properly with long long

I am sorting a two dimensional array a[n][2], with respect to a[i][0],a[i+1][0] breaking ties with non-decreasing a[i][1],a[i+1][1]. qsort is working fine with integer array but not with long long array.

Integer array code

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>

int cmpfunc(const void* a, const void* b)
{
    int x = ((int*)a)[0] - ((int*)b)[0];
    if (x != 0) {
        return x;
    }
    return ((int*)a)[1] - ((int*)b)[1];
}

int main(int argc, char const* argv[])
{
    int n, i, j;
    scanf("%d", &n);
    int a[n][2];
    for (i = 0; i < n; i = i + 1) {
        scanf("%d %d", &a[i][0], &a[i][1]);
    }
    qsort(a, n, sizeof(a[0]), cmpfunc);
    for (i = 0; i < n; i = i + 1) {
        printf("%d %d\n", a[i][0], a[i][1]);
    }
    return 0;
}

long long array code

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>

int cmpfunc(const void* a, const void* b)
{
    int x = ((int*)a)[0] - ((int*)b)[0];
    if (x != 0) {
        return x;
    }
    return ((int*)a)[1] - ((int*)b)[1];
}

int main(int argc, char const* argv[])
{
    int n, i, j;
    scanf("%d", &n);
    long long a[n][2];
    for (i = 0; i < n; i = i + 1) {
        scanf("%I64d %I64d", &a[i][0], &a[i][1]);
    }
    qsort(a, n, sizeof(a[0]), cmpfunc);
    for (i = 0; i < n; i = i + 1) {
        printf("%I64d %I64d\n", a[i][0], a[i][1]);
    }
    return 0;
}

Input:

5
4 3
4 2
4 1
4 1
4 1

Output for first code:

4 1
4 1
4 1
4 2
4 3

Output for second code:

4 2
4 1
4 1
4 1
4 3

即使将数据类型更改为long long您也仍然会在比较函数中强制转换为int *

You actually have two issues: The first is the one with the invalid casting. The second is also about the invalid casting but for another reason.

As stated in one of my comments the qsort function passes pointers to the elements to the comparison function. If you haven an array arr then qsort will use something like &arr[0] for the arguments. That means if the data of the array is itself arrays then the arguments will be pointers to arrays. In your specific case the argument types are really long long (*)[2] , not only long long * .

So the comparison function should look something like this instead:

int cmpfunc(const void* a_, const void* b_)
{
    long long (*a)[2] = (long long (*)[2]) a_;
    long long (*b)[2] = (long long (*)[2]) b_;

    long long result;

    if ((*a)[0] - (*b)[0] != 0)
        result = (*a)[0] - (*b)[0];
    else
        result = (*a)[1] - (*b)[1];

    if (result < 0)
        return -1;
    else if (result > 0)
        return 1;
    else
        return 0;
}

If you enable warning while compiling ( -Wall -pedantic for gcc) you should notice that you need different place holder for long long int and you can't assume that it's 64-bit . You also mis-cast arguments of compare function. Notice that the difference between two long long int can be outside the range of an int so you can't use that (the one I wrote) qsort() compare implementation. Here's the code:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
int cmpfunc(const void *a,const void *b){
    long long int x=((long long int *)a)[0]-((long long int *)b)[0];
    if(x!=0){
        return x;
    }
    return ((long long int *)a)[1]-((long long int *)b)[1];
    }


int main(int argc, char const *argv[]){
    int n,i;
    scanf("%d",&n);
    long long a[n][2];
    for(i=0;i<n;i=i+1){
        scanf("%lld %lld",&a[i][0],&a[i][1]);
    }
    qsort(a,n,sizeof(a[0]),cmpfunc);
    for(i=0;i<n;i=i+1){
        printf("%lld %lld\n",a[i][0],a[i][1]);
    }
    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