【问题标题】:Segmentation fault in C++ recursive functionC++ 递归函数中的分段错误
【发布时间】:2018-05-08 12:41:57
【问题描述】:

问题是删除相邻的相同字母对,直到没有这样的对。我为此使用了递归。但是代码给出了分段错误。这个递归有什么问题?

#include<iostream>
#include<string>
using namespace std;
string super(string s)
{
        for(int i=0;i<s.length();i++)
        {
                if(s[i]==s[i+1])
                {
                        s.erase(s.begin()+i);
                        s.erase(s.begin()+i+1);
                        s=super(s);
                        cout<<s;
                        break;
                }
                if(i+1==s.length())
                        return s;
        }
        return s;
}
int main()
{
        string s;
        cin>>s;
        s=super(s);
        if(s.length()<0)
                cout<<s;
        else
                cout<<"Empty String";
}

【问题讨论】:

  • 请考虑您正在取消引用 i 和 i+1。为简单起见,如果字符串中只有一个字符怎么办?
  • 仅供参考:当你让它工作时,你可能想改变if(s.length()&lt;0) cout&lt;&lt;s;
  • 请注意,在s.erase(s.begin() + i) 之后,曾经s.begin() + i + 1 的字符现在位于s.begin() + i
  • 当我切换for循环的顺序时发生了同样的事情
  • 为什么你既循环又递归?

标签: c++ recursion segmentation-fault


【解决方案1】:

您的条件检查出现故障,s[s.length()] 根据定义会导致分段错误,因此您需要在尝试访问之前确保i+1 小于 s 的长度。

现在您正在访问s[i+1],然后检查i+1 &lt; s.length()

【讨论】:

    【解决方案2】:

    您的索引超出范围。如果 i == s.length()-1 (这是最后一个字符的 index),那么您的 s[i+1] 将超出范围。

    一般来说,逻辑是有缺陷的,因为每次遇到匹配时都会从头开始重新操作。如果你有'abccba',我假设你会想要'abcba',但是你的代码会返回abca。 您的解决方案的时间复杂度并不理想。这可以在线性时间内完成。

    在最后一行你希望 s.length() > 0(或者你可以只使用 s.empty())。

    【讨论】:

      【解决方案3】:

      据我了解,人们讨厌代码中的 cmets,所以我将在答案的顶部重复它们:

      首先在for cicle中,为了不超出索引,您必须从1开始并检查字符串的i-1和i位置是否相等。

      其次,您可以简单地从 i - 1 位置擦除到 i + 1 位置。

      最后,当你想在 main 中打印字符串时,你必须检查字符串的长度是否不为空,长度不能为

      最重要的是,仅调用自己内部的方法并不能使其成为“递归解决方案”,下面的代码是您问题的迭代解决方案

      #include<iostream>
      #include<string>
      using namespace std;
      string super(string s){
              for(int i=1;i<s.length();i++)                                 // you start from 1 to doesn't go out of bound
                      if (s[i-1]==s[i])
                              s.erase(s.begin() + (--i), s.begin() + i + 1);// you decrease i and erase from i decreased to i + 1
              return s;
      }
      int main(){
              string s;
              cin>>s;
              s = super(s);
              cout << ((s.length())? s : "Empty String");                    // the string is empty if the lenght is not 0, you have to change < with >
              return 0;
      }
      

      这反而是一个递归的解决方案,你可以看到for循环的消失(不是错误使用循环而是使用它们很容易出错)

      #include<iostream>
      #include<string>
      using namespace std;
      string super(string s, int i){
          if (i < s.length()){
              if (s[i-1]==s[i]){
                  s.erase(s.begin() + i - 1, s.begin() + i + 1);
                  s = super(s, i);
              }
              else
                  s = super(s, i + 1);
          }
          return s;
      }
      int main(){
          string s;
          cin>>s;
          s = super(s, 1);    //from input the size can't be 0 so give 1 is ok
          cout << ((s.length())? s : "Empty String");
          return 0;
      }
      

      【讨论】:

      • 不鼓励仅使用代码回答。请详细说明代码以及与 OPs 代码相比,您编写它的原因。
      • 里面有解释变化的cmets
      • 不确定其他人,但我倾向于完全忽略代码中的 cmets。它们中的大多数也隐藏在滚动条后面。
      • ...好吧,如果我使用滚动条,我可以阅读 cmets 但看不到代码:-(
      猜你喜欢
      • 2017-12-25
      • 1970-01-01
      • 2016-01-14
      • 2019-08-13
      • 2013-03-05
      • 2014-11-05
      • 2019-11-16
      相关资源
      最近更新 更多