C++ 合并排序分段错误?

Posted

技术标签:

【中文标题】C++ 合并排序分段错误?【英文标题】:C++ Mergesort Segmentation Fault? 【发布时间】:2013-11-06 00:59:12 【问题描述】:

我似乎在让这个合并排序运行时遇到了一些麻烦。当我尝试使用 g++ 运行它时,终端显示“分段错误(核心转储)”,我不知道是什么导致了这种情况发生(你可能会说我还是个初学者)。有人可以帮忙吗?

#include <iostream>
using namespace std;


void merge (int*, int, int, int);

void mergesort (int* A, int p, int r)

 if (p < r)

  int q = (p+r)/2;
  mergesort (A, p, q);
  mergesort (A, q+1, r);
  merge ( A, p , q, r);
  


void merge (int* A, int p, int q, int r)


  int n = q-p+1;
  int m = r-q ;
   int L [n+1];
  int R [m+1];

  for (int i=1;i <n+1;i++)
       L[i] = A[p+i-1];

  for (int j=1; j< m+1; j++)
      R[j] = A[q+j];

L[n+1];
R[m+1];

 int i= 1;
 int j=1;

for (int k = p; k= r + 1; k++)
   if (L[i] <= R[j])
      A[k] = L[i];
       i+=1;
   
   else
     j += 1;
    




int main() 

int A [15] = 1, 5, 6, 7,3, 4,8,2,3,6;

mergesort (A, 0, 9);

for (int i=0; i <9; i++)
cout << A[i] << endl;


return 0;

非常感谢!

【问题讨论】:

你希望语句L[n+1]; 做什么? 严重的是,分段错误可能由无数种原因引起:缓冲区溢出、取消引用悬空指针、双重释放、写入只读内存和加载更多。您是否尝试过运行调试器,或者至少确定了一些可能存在问题的行? 使用调试器查找错误源,例如linux上的gdb 你能在这里稍微解释一下你的逻辑吗?合并排序应该采用两个排序数组并将它们合并为一个排序数组,应该抽象出只有一个数组开始的事实。您应该首先构建一个执行我上面提到的功能并从那里向后工作的函数,这可能是执行依赖递归的最简单的方法。 @SevenBits 这就是为什么它在评论中,而不是答案。而且由于 OP 没有声明 not 的使用情况,因此它更适用。如果你对此有问题,我很抱歉。许多人甚至不知道标准库中存在这样的功能,我认为 OP 是其中之一,就像你必须假设他们是初出茅庐的学生一样。 【参考方案1】:

您的实现中有三件事没有意义或完全错误:

首先是这些:

L[n+1];
R[m+1];

这些声明都没有任何效果,我不知道你想做什么。

接下来,一个重大的错误:

for (int k = p; k= r + 1; k++)

这个 for 循环的条件子句是 assignment k = r + 1。由于r 在循环中的任何地方都不会更改,因此表达式为false 的唯一方法是如果r == -1,它永远不会。您刚刚在计数器k 上创建了一个无限循环,它将永远运行到平流层,并在进程索引中,并写入内存,在您的进程中不再有效。因此,这是未定义的行为。我很确定你想要这个:

for (int k = p; k< (r + 1); k++)

虽然我无法评论这是否是一个有效的限制,因为我没有进一步剖析你的算法。我没有花时间进一步调试这个。我留给你的。

编辑。在您的主要合并排序中,这不是“错误”,但很容易溢出

int q = (p+r)/2;

请考虑这个:

int q = p + (r-p)/2;

尤其重要的是:

int L [n+1];
int R [m+1];

使用 C++ 标准不支持的可变长度数组扩展。您可能想改用std::vector&lt;int&gt; L(n+1) 等。

【讨论】:

【参考方案2】:

在您的情况下,当您尝试读取变量不存在的内存时,可能会导致分段错误,例如,假设您有一个名为 foo 的大小为 10 的数组(所以foo[10])而您这个语句foo[11] 会导致分段错误。

您需要做的是使用调试语句打印出您的索引变量(i、j、n、m、p 和 q)并查看其中是否有任何大于您的数组大小

编辑:另一个不相关的问题是你不应该使用using namespace std,如果你不小心,这行代码可能会导致范围问题,请记住一些事情:)

【讨论】:

我会建议他使用调试器逐行执行代码,而不是告诉他使用打印语句。打印语句是在大型程序中调试的一种非常糟糕的方法。相反,也许使用 Valgrind 是一个不错的选择...? 它不是一个大程序,他是初学者,与打印语句的简单性相比,调试时开始时可能会有点不知所措 我同意@SevenBits。如果您有一个调试器供您使用,并且使用它来跟踪此类问题,那么您就是在给自己带来伤害。事实上,这正是理想,因为它是如此之小。这不是压倒性的,现在开发调试器技术将从那时起真正为自己付出代价。是的,这就像用锤子杀死苍蝇一样,但是在进行更大的项目的道路上,不知道如何挥动锤子,并且只用苍蝇拍撞到花岗岩上会更加痛苦。 如果不能使用调试器,就不能开发软件。就这么简单。 @MartinJames 这是错误的,而且心胸狭窄。 ***.com/questions/1544289/…

以上是关于C++ 合并排序分段错误?的主要内容,如果未能解决你的问题,请参考以下文章

C++ 代码的分段错误(核心转储)

向量下标超出范围 C++ 合并排序

链表上的合并排序

使用链表合并排序 C 实现

合并排序算法中的 C++“以 std::out_of_range:vector 类型的未捕获异常终止”错误

归并排序分段故障 NASM