【问题标题】:qsort comparator function doesn't order the entire array (leaves 1 element out)qsort 比较器函数不会对整个数组进行排序(留下 1 个元素)
【发布时间】:2018-04-25 18:15:59
【问题描述】:

相关代码(索引为数组的大小):

typedef struct elemento {
    unsigned long linha;
    unsigned long coluna;
    double valor;
} elemento; 

elemento Representados[MAXN];
qsort(Representados, index, sizeof(Representados[0]), lcomparator);

int lcomparator(const void *el1, const void *el2) {
    int l1 = ((elemento *)el1)->linha;
    int l2 = ((elemento *)el2)->linha;
    int c1 = ((elemento *)el1)->coluna;
    int c2 = ((elemento *)el2)->coluna;

    if (l1 < l2) {
        return -1;
    }
    else if (l1 == l2) {
        if (c1 < c2) {
            return -1;
        }
        else if (c1 == c2) {
            return 0;
        }
        else if (c2 > c1) {
            return 1;
        }
    }
    else {
        return 1;
    }

}

gcc 还为 lcomparator 打印出“控制到达结束”警告,但我看不出我的函数怎么可能不返回任何内容。

【问题讨论】:

  • 最里面的if 没有“默认”else 大小写,因此会出现警告。
  • 无关,它完全不会打扰你吗,你应该收到的那些编译器警告,尖叫着从unsigned long到@987654326的转换@ 可能会丢失精度?
  • 您好,感谢您的回复。我已经删除了最里面的 if 的 else,但是 qsort 仍然不能正确排序。
  • 请说明如何使用Minimal, Complete, and Verifiable example 调用qsort
  • 您将从这篇文章中了解为什么人们建议您发布最小、完整和可验证的示例。你表现得好像你在法庭上为你的案子辩护。你谈论探针,但你根本没有展示它们。你说index 被赋予了正确的值。我现在不知道你是否已经分配、初始化或#defined 它,以及如何,但你是对的......继续这样,你会感到绝望,因为你告诉我们绝对关于您的代码的真相......并且不要对错误一无所知。你看不到它。所以我们没有。

标签: c gcc comparator qsort


【解决方案1】:
else if (c2 > c1) {
    return 1;
}

错了,应该是

else if (c1 > c2) {
    return 1;
}

或更好

else {
    return 1;
}

当然也可以用unsigned long替换int

【讨论】:

  • 比较成功。
  • 看看我的回答中识别问题的自动化方法。
【解决方案2】:

我的建议:

  1. 将函数局部变量的类型更改为unsigned long。当它们是int 类型时,您将失去精度。这可能是您看到的问题的根源,但如果没有实际值就很难说。

  2. 使用辅助函数可以简化核心逻辑。

这是您的函数的更新版本。

int compare_helper(unsigned long l1, unsigned long l2)
{
   if ( l1 < l2 )
   {
      return -1;
   }
   if ( l2 < l1 )
   {
      return 1;
   }
   return 0;

   // The line below does the same thing but relies on the logical expressions 
   // to be 1 or 0.
   // return (l2<l1) - (l1<l2);
}

int lcomparator(const void *el1, const void *el2) {
    unsigned long l1 = ((elemento *)el1)->linha;
    unsigned long l2 = ((elemento *)el2)->linha;
    unsigned long c1 = ((elemento *)el1)->coluna;
    unsigned long c2 = ((elemento *)el2)->coluna;

    if ( l1 != l2 )
    {
       return compare_helper(l1, l2);
    }

    return compare_helper(c1, c2);
}

【讨论】:

  • helper 函数似乎 OTT。函数lcomparator 应该尽可能高效。或许是inline吧?
  • @WeatherVane,这不是过早优化的尝试吗?如果这被证明是性能瓶颈,可以使用(l2&lt;l1) - (l1&lt;l2) 的想法。
  • 很抱歉,但您第一次尝试回答 - 受到 2 个有效(现已删除)cmets 的挑战并没有好转。这么高的代表给出的答案很糟糕。否决票。我赞成的答案实际上发现了这个错误。
  • @WeatherVane,我尊重你的意见。
【解决方案3】:

之前的cmets和answers已经展示了unsigned longint的类型差异,以及比较bug。您的代码可能实际上总是返回一个值,但编译器不喜欢挂起的else

我建议如下:

int lcomparator(const void *el1, const void *el2) {
    unsigned long l1 = ((elemento *)el1)->linha;
    unsigned long l2 = ((elemento *)el2)->linha;
    unsigned long c1 = ((elemento *)el1)->coluna;
    unsigned long c2 = ((elemento *)el2)->coluna;

    if(l1 < l2) {
        return -1;
    } 
    if(l1 > l2) { 
        return 1;
    } 
    if(c1 < c2) { 
        return -1;
    } 
    if(c1 > c2) {
        return 1;
    }
    return 0;
}

【讨论】:

    【解决方案4】:

    要添加到@Stargateur 已经正确的答案,这里有一种使用SortChecker 自动查找代码中错误的方法:

    LD_PRELOAD=$HOME/SortCheck/bin/libsortcheck.so ./a.out
    a.out[3024]: qsort: comparison function is not symmetric (comparison function 0x400526 (/home/yugr/src/so/a.out+0x400526), called from 0x4005c6 (/home/yugr/src/so/a.out+0x4005c6), cmdline is "./a.out")
    

    这个警告表明lcomparator 在交换参数顺序时返回不一致的结果。要进一步调试此问题,请运行

    export SORTCHECK_OPTIONS=raise=1
    

    并检查生成的编码转储。

    【讨论】:

      猜你喜欢
      • 2021-06-23
      • 2019-07-23
      • 2016-04-11
      • 1970-01-01
      • 1970-01-01
      • 2021-09-30
      • 2018-05-16
      • 1970-01-01
      • 2018-12-12
      相关资源
      最近更新 更多