【问题标题】:qsort unexpectedly working while using "a > b" as comparatorqsort 在使用“a > b”作为比较器时意外工作
【发布时间】:2014-12-24 12:33:44
【问题描述】:

我遇到了一个 qsort 比较器函数,它错误地使用“a > b”作为比较操作。我希望这段代码只是随机地重新排序阵列,但它正在我学校的教学服务器(Ubuntu 12.04.4 LTS)上运行。它没有像预期的那样在我自己的笔记本电脑上工作,所以我不确定是什么导致了这个错误。

#include <cstdio>
#include <cstdlib>

void print_arr(int* arr, size_t n) {
  for (int i = 0; i < n; i++)
    printf("%d ", arr[i]);
  printf("\n");
}

int int_compar(const void *x, const void *y)
{
  int i_x = *((int*)x);
  int i_y = *((int*)y);
  return i_x > i_y;
}

int main(int argc, char *argv[])
{
  int n = (1<<4);
  int in[n];

  for(int i = 0; i < n; i++)
    in[i] = rand() % 100;

  printf("Before: ");
  print_arr(in, n);

  qsort(in, n, sizeof(int), int_compar);

  printf("After: ");
  print_arr(in, n);

  return 0;
}

我的笔记本电脑:

$ ./qsort_test
Before: 7 49 73 58 30 72 44 78 23 9 40 65 92 42 87 3
After: 23 7 9 3 58 44 42 40 49 30 65 72 73 78 87 92

Ubuntu:

$ ./qsort_test
Before: 83 86 77 15 93 35 86 92 49 21 62 27 90 59 63 26
After: 15 21 26 27 35 49 59 62 63 77 83 86 86 90 92 93

【问题讨论】:

  • 完全靠运气“工作”;显然,该特定qsort 实现的一些细节恰好为具有该特定(损坏的)比较器的该特定输入集产生正确的结果。
  • Ubuntu qsort() 显然在fcmp() 返回值为&lt; 00 时做同样的事情。 OP 的 qsort() 采用不同的路径,可能在 &gt; 00 上也是如此。
  • glibc中qsort通常的implementation只关心比较器是否quicksort,它会关心它是否是
  • @Tavian Barnes 是的,它不太可能完全靠运气。也许有效的排序实现会不必要地交换被认为相等的值,这将适用于i_x &lt; i_y 的情况

标签: c std qsort


【解决方案1】:

您违反了使用qsort 的合同,因此调用了Undefined Behavior
具体来说,您的比较功能很糟糕:

7.22.5.2 qsort 函数

概要

#include <stdlib.h>
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));

说明
2 qsort函数对nmemb对象数组进行排序,其初始元素为 由base 指向。每个对象的大小由size指定。
3 数组的内容按一次比较升序排序 compar 指向的函数,该函数使用两个指向 被比较的对象。 函数应返回一个小于、等于或 如果认为第一个参数分别小于、等于、则大于零 或大于秒。
4 如果两个元素比较相等,则它们在结果排序数组中的顺序未指定。
退货
5 qsort 函数无返回值。

应该更接近于:

int int_compar(const void *x, const void *y)
{
  int i_x = *(int*)x;
  int i_y = *(int*)y;
  return i_x > i_y - i_x < i_y;
}

现在,比较函数是部分功能而不是完全损坏,它确实指示第一个是否大于第二个,但不区分它们是相等还是第二个变大
根据算法的编写方式,这可能会使算法认为所有人都是平等的,根本不会对您的错误做出反应,或者做一些有趣的事情。
例如,所有 C++ 标准库排序算法都被编写为仅使用小于进行比较。

【讨论】:

  • 我没有投反对票,但问题是“为什么它似乎可以在特定机器上工作?”。
  • OP很清楚知道实现是错误的这一事实。他感兴趣的是为什么它可以在他学校的 Ubuntu 机器上运行,而不是为什么它不能在他的笔记本电脑上运行。
  • @TheParamagneticCroissant 你的评论应该是答案,而不仅仅是重复OP已经知道的事实(这是错误的),即使有更多细节。
  • @Weather Vane ix - iy 遭受int 溢出。考虑INT_MAX - (-1)
  • @alotofdavid:但那是 C++ 标准库,而不是其中包含的 C 标准库。无论如何,好主意,看起来 C qsort 是独立于 C++ std::sort 实现的,至少对于 Linux。
猜你喜欢
  • 2020-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-02
  • 2019-10-27
  • 2016-09-08
  • 2020-09-20
  • 2021-07-17
相关资源
最近更新 更多