C qsort 无法正常工作

发布于 2024-11-09 11:02:21 字数 1480 浏览 0 评论 0原文

我不知道我做错了什么,但以下代码无法正确对数组进行排序。

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

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

int main()
{
    int x[] = { -919238029,
            -889150029,
            -826670576,
            -579609061,
            -569653113,
            -305140505,
            -216823425,
            -193439331,
            -167683147,
            -49487019,
            -45223520,
            271789961,
            275570429,
            444855014,
            559132135,
            612312607,
            664554739,
            677860351,
            1005278191,
            1031629361,
            1089012280,
            1115952521,
            1521112993,
            1530518916,
            1907515865,
            1931470931,
            -1631034645,
            -1593702794,
            -1465300620,
            -1263094822
         };
    int i;

    qsort(x, 30, sizeof(int), compare);
    for(i = 0; i < 30; i ++)
        printf("%d\n", x[i]);

    return 0;
}

产生以下输出:

1521112993
1530518916
1907515865
1931470931
-1631034645
-1593702794
-1465300620
-1263094822
-919238029
-889150029
-826670576
-579609061
-569653113
-305140505
-216823425
-193439331
-167683147
-49487019
-45223520
271789961
275570429
444855014
559132135
612312607
664554739
677860351
1005278191
1031629361
1089012280
1115952521

我的意思是,问题/必须/出现在我的比较函数中。有人注意到有什么奇怪的吗?

I don't know what I'm doing wrong but the following code does not sort the array properly.

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

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

int main()
{
    int x[] = { -919238029,
            -889150029,
            -826670576,
            -579609061,
            -569653113,
            -305140505,
            -216823425,
            -193439331,
            -167683147,
            -49487019,
            -45223520,
            271789961,
            275570429,
            444855014,
            559132135,
            612312607,
            664554739,
            677860351,
            1005278191,
            1031629361,
            1089012280,
            1115952521,
            1521112993,
            1530518916,
            1907515865,
            1931470931,
            -1631034645,
            -1593702794,
            -1465300620,
            -1263094822
         };
    int i;

    qsort(x, 30, sizeof(int), compare);
    for(i = 0; i < 30; i ++)
        printf("%d\n", x[i]);

    return 0;
}

produces the following output:

1521112993
1530518916
1907515865
1931470931
-1631034645
-1593702794
-1465300620
-1263094822
-919238029
-889150029
-826670576
-579609061
-569653113
-305140505
-216823425
-193439331
-167683147
-49487019
-45223520
271789961
275570429
444855014
559132135
612312607
664554739
677860351
1005278191
1031629361
1089012280
1115952521

I mean, the problem /must/ be in my compare function. Anybody notice anything strange?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

夏尔 2024-11-16 11:02:21

是的,你的“比较”溢出了。 :(

原因:

当你用正数减去负数时,你的结果不一定是正数;如果它不能用数据类型表示,它会“环绕”另一边。

示例:

如果你的整数只能保存-8到7(4位),那么当你比较4和-4时会发生什么?
好吧,你得到 8,即二进制的 1000,也就是 -8。所以 4 小于 -4。

寓意:

不要用减法代替比较,即使他们在学校告诉你“看看这有多酷”!

Yeah, your "comparison" overflows. :(

Reason:

When you subtract a negative number from a positive number, your result is not necessarily positive; if it can't be represented in the data type, it'll "wrap around" the other side.

Example:

If your integer can only hold from -8 to 7 (4 bits), then what happens when you compare 4 to -4?
Well, you get 8, which is 1000 in binary, which is -8. So 4 is less than -4.

Moral:

Don't do subtraction instead of comparison, even if they tell you "look how cool this is" at school!

野味少女 2024-11-16 11:02:21

一般情况下,不能使用减法来比较整数。或者,更准确地说,您可以,但前提是您确定减法不会溢出。在您的情况下,减法溢出,产生完全无意义的结果(甚至没有提到当有符号整数减法溢出时,行为是未定义的)。

在值 ab 之间生成三态 C 风格比较的常见习惯用法是 (a > b) - (a < b)< /代码> 表达式。它几乎适用于任何类似类型的数据。在您的情况下,比较函数可能如下所示

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

In general case you can't use subtraction to compare integers. Or, more precisely, you can, but only in situations when you are sure that the subtraction will not overflow. In your case subtraction overflows, producing totally meaningless results (not even mentioning that when signed integer subtraction overflows the behavior is undefined).

The common idiom for generating tri-state C-style comparisons between values a and b is the (a > b) - (a < b) expression. It works for data of virtually any comparable types. In your case the comparison function might look as follows

int compare(const void* a, const void* b)
{
  int va = *(const int*) a;
  int vb = *(const int*) b;
  return (va > vb) - (va < vb);
}
何时共饮酒 2024-11-16 11:02:21

为了添加 Mehrad 的正确答案,这里有一种使用 SortChecker 查找代码中错误的自动方法:

$ LD_PRELOAD=$HOME/sortcheck-master/bin/libsortcheck.so ./a.out
a.out[38699]: qsort: comparison function is not transitive (comparison function 0x40057d (/home/iuriig/a.out+0x40057d), called from 0x400693 (/home/iuriig/a.out+0x400693), cmdline is "./a.out")
-919238029
-889150029
...

此警告表示 compare 报告 x y,y< z 而不是 x z 对于某些输入。要进一步调试此问题,请运行

export SORTCHECK_OPTIONS=raise=1

并检查生成的代码转储。

To add to Mehrad's correct answer, here's an automated way to find bug in your code using SortChecker:

$ LD_PRELOAD=$HOME/sortcheck-master/bin/libsortcheck.so ./a.out
a.out[38699]: qsort: comparison function is not transitive (comparison function 0x40057d (/home/iuriig/a.out+0x40057d), called from 0x400693 (/home/iuriig/a.out+0x400693), cmdline is "./a.out")
-919238029
-889150029
...

This warning says that compare reports x < y, y < z and not x < z for some inputs. To further debug this issue, run with

export SORTCHECK_OPTIONS=raise=1

and examine generated codedump.

四叶草在未来唯美盛开 2024-11-16 11:02:21

我使用上面的信息给出了一个代码示例。在我的编译器和系统中,我得到了与提出问题的 Ram 相同的结果。这表明我的整数类似于 Ram 的整数。我按照 Mehrdad 建议的方式修改了代码,使用比较运算符而不是减法。然后我对数字进行了正确排序。

这是代码:

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

    int compare(const void* a, const void* b)
    {
        int
            n1 = * (int *) a,
            n2 = * (int *) b;

        /*
        Usine the ternary to express along the lines of
            if
            elseif
            elseif
            .
            .
            .
            else
        */

        return 
            n1 > n2             // if
            ? 1                 // then
            : n1 == n2          // else if
            ? 0                 // then
            : -1                // else
            ;                   // end if
    }

    int main(int argc, char * argv[])
    {
        int x[] = 
        { 
            -919238029, -889150029, -826670576, -579609061, -569653113, -305140505, -216823425, -193439331,
            -167683147, -49487019,  -45223520,  271789961,  275570429,  444855014,  559132135,  612312607,
            664554739,  677860351,  1005278191, 1031629361, 1089012280, 1115952521, 1521112993, 1530518916,
            1907515865, 1931470931, -1631034645,-1593702794,-1465300620,-1263094822
        };

        int 
            i = 0,                          // index
            imax = sizeof(x)/sizeof(int);   // max value for index

        FILE * outf = 0;

        if ( !(outf = fopen("output.txt", "wt")) )
        {
            puts("outf == 0 which is an error trying to open \"output.txt\" for writing.\n");
            getch();
            return;
        }

        qsort(x, imax, sizeof(int), compare);


        for(i = 0; i < imax; i ++)
            fprintf(outf, "%d\n", x[i]);

        fclose(outf);

        return 0;
    }

我得到这个输出:

-1631034645
-1593702794
-1465300620
-1263094822
-919238029
-889150029
-826670576
-579609061
-569653113
-305140505
-216823425
-193439331
-167683147
-49487019
-45223520
271789961
275570429
444855014
559132135
612312607
664554739
677860351
1005278191
1031629361
1089012280
1115952521
1521112993
1530518916
1907515865
1931470931

I'm giving a code example using the information above. In my compiler and system, I get the same results as Ram who asked the question. This indicates that my integers are something like Ram's integers. I modified my code along the lines suggested by Mehrdad to use comparison operators instead of a subtraction. Then I got the numbers sorted properly.

Here is the code:

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

    int compare(const void* a, const void* b)
    {
        int
            n1 = * (int *) a,
            n2 = * (int *) b;

        /*
        Usine the ternary to express along the lines of
            if
            elseif
            elseif
            .
            .
            .
            else
        */

        return 
            n1 > n2             // if
            ? 1                 // then
            : n1 == n2          // else if
            ? 0                 // then
            : -1                // else
            ;                   // end if
    }

    int main(int argc, char * argv[])
    {
        int x[] = 
        { 
            -919238029, -889150029, -826670576, -579609061, -569653113, -305140505, -216823425, -193439331,
            -167683147, -49487019,  -45223520,  271789961,  275570429,  444855014,  559132135,  612312607,
            664554739,  677860351,  1005278191, 1031629361, 1089012280, 1115952521, 1521112993, 1530518916,
            1907515865, 1931470931, -1631034645,-1593702794,-1465300620,-1263094822
        };

        int 
            i = 0,                          // index
            imax = sizeof(x)/sizeof(int);   // max value for index

        FILE * outf = 0;

        if ( !(outf = fopen("output.txt", "wt")) )
        {
            puts("outf == 0 which is an error trying to open \"output.txt\" for writing.\n");
            getch();
            return;
        }

        qsort(x, imax, sizeof(int), compare);


        for(i = 0; i < imax; i ++)
            fprintf(outf, "%d\n", x[i]);

        fclose(outf);

        return 0;
    }

And I get this output:

-1631034645
-1593702794
-1465300620
-1263094822
-919238029
-889150029
-826670576
-579609061
-569653113
-305140505
-216823425
-193439331
-167683147
-49487019
-45223520
271789961
275570429
444855014
559132135
612312607
664554739
677860351
1005278191
1031629361
1089012280
1115952521
1521112993
1530518916
1907515865
1931470931
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文