【问题标题】:sort function C++ segmentation fault排序函数 C++ 分段错误
【发布时间】:2010-12-05 05:41:15
【问题描述】:

在这段代码中,对于向量大小,n >=32767,它给出了分段错误,但高达 32766,它运行良好。可能是什么错误?这是完整的代码。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<utility>
#include<algorithm>
#include<sys/time.h>
using namespace std;
#define MAX 100000

bool compare(pair<int,int> p1,pair<int,int> p2) {
    if(p1.second < p2.second)
        return 1;
    else if(p1.second > p2.second)
        return 0;
    if(p1.first <= p2.first)
        return 1;
    else
        return 0;
}

int main() {
    freopen("randomin.txt","r",stdin);
    int n;
    scanf("%d",&n);
    vector< pair<int,int> > p(n);
    for(int i=0;i<n;i++)
        scanf("%d%d",&p[i].first,&p[i].second);
    **printf("%d\n",(int)p.max_size()); // prints 536870911**
    sort(p.begin(),p.begin()+n,compare);

    //for(int i=0;i<n;i++)
        //printf("%d %d\n",p[i].first,p[i].second);
        printf("%.6f\n",(p[n-1].second+p[n-2].second)/(20.0+p[n-1].first+p[n-2].first));

    return 0;
}

【问题讨论】:

  • 您使用的是什么编译器和操作系统?也许它只是没有足够的内存?
  • 我编译了一个稍微修改过的版本(我不想从控制台输入 35000 个数字 :-))并且使用 VS2008 运行良好。我想问题出在其他地方。发布可重现问题的代码。
  • 它的 GNU g++ 和 cygwin 在 netbeans 上运行。我正在使用 freopen 并从文件中获取输入。
  • 我已经包含了整个代码。
  • 永远不要在不检查返回值的情况下使用scanf() 读取用户输入。

标签: c++ sorting segmentation-fault


【解决方案1】:

尝试使用从n = 3276632770 的所有值。我怀疑你会发现你正在经历某种溢出。这是因为 2^15 (32768) 是可以使用 16 位表示的最大数字(假设您也允许负数)。您将不得不使用不同的数据类型。

建议:

让它输出向量的最大尺寸:

cout << p.max_size();

让我们知道它的作用。一切正常,我希望它达到数亿(我的计算机上的 536870911)。但如果它更像是 32768,那可能就是问题所在。

【讨论】:

  • 您的比较函数应该在相等时返回 false,而不是 true。不知道为什么这会导致 segv...
  • aditya,基思有道理。对于 n = 350000,其中每对是 (0,0) 程序崩溃。添加 if(p1==p2) 后返回 0;它工作正常。
  • @aditya,总是 1 不是比较函数。比较 codepad.org/s3vvaai5 [工作正常] 和 codepad.org/sD7kz0b4 [崩溃]
  • @Keith - 好点,但如果这是真正的问题,我会感到惊讶。可能会打乱排序结果,但是是段错误? @aditya - 要修复它,相比之下,将
  • @aditya - 这只是 Keiths 的做法不同。您违反了 sort 对比较的期望。我很惊讶它有段错误,但是......
【解决方案2】:

在 C++ 中,compare 谓词必须是 strict weak ordering。特别是compare(X,X) 必须为任何 X 返回“false”。在您的比较函数中,如果两对相同,则您点击测试 (p1.first &lt;= p2.first) 并返回 true。因此,这个compare 谓词没有强加严格的弱排序,传递给sort 的结果是不确定的。

【讨论】:

  • 没有刻意的隐式检查——只是一个混乱的排序算法。不同的输入 => 不同的混淆。
  • +1 - 很好看! @aditya:请记住,STL 比较函数是在询问“第一个小于第二个”——而不是“它们是否相等”。
  • @Aditya:非严格符合的 C++ 程序可能在某些输入上工作,而在其他输入上失败的原因有很多。考虑这样一种情况:库对大型容器使用一种算法(如果违反严格的弱排序,则转储核心),而对较小的 N 值使用一种更简单(且更宽容)的算法。
  • 也许它过于深入地递归(例如,因为错误的比较函数弄乱了算法的最坏情况保证)?我还想指出 std::pair 已经定义了比较运算符(除了它使用 first 作为第一个标准)。
  • 这对我造成了一些相当随机的段错误。我仍然无法相信糟糕的排序机制实际上会破坏堆栈。很好的收获,谢谢。
【解决方案3】:

C++ 有时表现得很奇怪。我在 basic_string.h 文件中遇到了分段错误!我正在将我的代码库从 GCC 4.2.1 升级到 GCC 5.4.0,突然发生了这个 SEG FAULT,我想知道为什么相同的代码更早地工作,现在它在 C++ 自己的 STL 内部被破坏。然后我查看了回溯,发现它来自std::sort的指针向量,它使用自定义比较器在通过成员函数ptr-&gt;GetName()获取对象名称的基础上比较指针。这个GetName() 正在返回一个字符串。

我花了一整天的时间来弄清楚 basic_string 文件中的更改可能会导致此错误。然后我了解了这个“严格弱排序”的事情,并相应地更改了我的比较器功能。还是没有运气。

然后我进行了调整,将原来的比较器函数更改为 Functor。而现在,它奏效了。我不知道它背后的确切原因,但它奏效了。

这是我原来的比较器函数:

bool swap (CLwPatternObj *a, CLwPatternObj *b){
    return a->GetName() < b->GetName() ) 
}

这是新的函数对象。

class CLwPatternComparator
{
public:
    bool operator() (CLwPatternObj *a, CLwPatternObj *b) 
    {
        return a->GetName() < b->GetName();
    }
};

相同的逻辑,但它适用于函数对象。

【讨论】:

    【解决方案4】:

    由于按值传递两个向量,您的溢出可能与堆栈溢出有关。

    std::vector &vec - 这是通过引用传递向量的方式。

    改变 bool compare(pair&lt;int,int&gt; p1,pair&lt;int,int&gt; p2)bool compare(pair&lt;int,int&gt; &amp;p1,pair&lt;int,int&gt; &amp;p2)

    如果你想通了,通过引用传递会将堆栈数据的大小从大小(2*n*4)*2字节更改为2x8字节指针

    对于n == 32767,您将堆栈帧减少了大约(2*32767*4)*2

    根据经验,除非您的设计另有要求,否则通过引用传递。

    【讨论】:

    • 我同意按值传递这些是不明智的。它仍然可能不应该仅仅因为这个而崩溃。
    • 主题开始不按值传递向量。他传递了 std::pair,这是 8 个字节,在 x64 平台上完全适合 CPU 寄存器
    猜你喜欢
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 2015-03-24
    • 2016-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多