【问题标题】:Unexpectedly recieving "std::out_of_range" error while using the same function使用相同功能时意外收到“std::out_of_range”错误
【发布时间】:2018-01-05 14:53:41
【问题描述】:

我编写了一个递归回文函数,它在第一个代码中只接收一个单词,而在第二个代码中接收一个句子。然而出乎意料的是,第二个代码给了我“超出范围”的错误。

这个函数(它工作正常)在两个代码中都使用了:

bool palindrome( string str, int first, int last )
{
    if( first == str.size() - 1 ) //if string is a single alphabet.
        return true;
    if( str[ first ] == str[ last ] )
        return palindrome( str.substr( first + 1, last - 1 ), first, last - 2 );
}

在第一个代码中,即使我输入了一个很长的字符串,它也会按预期工作:

int main()
{
    string str = "madamhelloollehmadam";
    palindrome( str, 0, str.size() - 1 ) ? cout << "palindrome!" << '\n' : cout << "not palindrome." << '\n';
}

在第二个代码中,我需要将输入的句子转换为单词,同时将所有字符变为小写(我在其他函数中执行所有这些操作)。我实际上在第二个代码中输入了相同的字符串,但我仍然在页面底部收到错误:

int main()
{
    string str = "madam hello olleh madam"; //this becomes "madamhelloollehmadam" after going to "normalString" function.
    palindrome( normalString(str), 0, normalString(str).size() - 1 ) ? cout << "palindrome!" << '\n' : cout << "not palindrome." << '\n';
}

这是我得到的错误(对于第一个得到单词而不是句子的代码,我不会得到这个错误但是两个“回文”函数是相同的。我猜“normalString”函数有问题但我无法检测到任何大小差异......)

terminate called after throwing an instance of 'std::out_of_range'
  what():  basic_string::substr
Aborted

这也是 normalString 函数:

string normalString( string str )
{
    vector<string> vec;
    for( int i = 0; i < str.size(); ++i )
        vec.push_back( charToString(str[ i ]) );

    for( int i = 0; i < vec.size(); ++i )
    {
        if( !isAlpha( vec[ i ] ) )
            vec[ i ].erase();
        if( isupper( stringToChar(vec[ i ]) ) ) 
            vec[ i ] = charToString( tolower( stringToChar( vec[ i ] ) ) );
    } 

    string str2 = vectorToString( vec );
    return str2;
}

这是我所有的第二个代码:

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <locale>
using namespace std;

bool palindrome( string, int, int );
bool isAlpha( string );
string charToString( char );
string normalString( string );
char stringToChar( string );
string vectorToString( vector<string> );

int main()
{
    cout << "Enter a word or a sentence: ";

    string str;
    while( cin >> str )
    {
        palindrome( normalString(str), 0, normalString(str).size() - 1 ) ? cout << str << " is palindrome!" << " (" << normalString(str) << ") " 
                                                    << '\n' : cout << str << " is not palindrome!" << " (" << normalString(str) << ") " << '\n';    
        cout << "Enter a word or a sentence: ";
    }
    return 0;
}

string vectorToString( vector<string> vec )
{
    stringstream ss;
    for( int i = 0; i < vec.size(); ++i )
        ss << vec[ i ];
    string str;
    ss >> str;
    return str;
}

string charToString( char c )
{
    stringstream ss;
    string s;
    ss << c;
    ss >> s;
    return s;
}

char stringToChar( string str )
{
    stringstream ss;
    ss << str;
    char c;
    ss >> c;
    return c;
}

bool isAlpha( string s )
{
    return s == "a" || s == "b" || s == "c" || s == "d" || s == "e" || s == "f" || s == "g" || s == "h" || s == "i" || s == "j" || s == "k" || s == "l"||
           s == "m" || s == "n" || s == "o" || s == "p" || s == "q" || s == "r" || s == "s" || s == "t" || s == "u" || s == "v" || s == "w" || s == "x"||
           s == "y" || s == "z" ||
           s == "A" || s == "B" || s == "C" || s == "D" || s == "E" || s == "F" || s == "G" || s == "H" || s == "I" || s == "J" || s == "K" || s == "L"||
           s == "M" || s == "N" || s == "O" || s == "P" || s == "Q" || s == "R" || s == "S" || s == "T" || s == "U" || s == "V" || s == "W" || s == "X"||
           s == "Y" || s == "Z" ; 
}

string normalString( string str )
{
    vector<string> vec;
    for( int i = 0; i < str.size(); ++i )
        vec.push_back( charToString(str[ i ]) );

    for( int i = 0; i < vec.size(); ++i )
    {
        if( !isAlpha( vec[ i ] ) )
            vec[ i ].erase();
        if( isupper( stringToChar(vec[ i ]) ) ) 
            vec[ i ] = charToString( tolower( stringToChar( vec[ i ] ) ) );
    } 

    string str2 = vectorToString( vec );
    return str2;
}

bool palindrome( string str, int first, int last )
{
    if( first == str.size() - 1 ) //if string is a single alphabet.
        return true;
    if( str[ first ] == str[ last ] )
        return palindrome( str.substr( first + 1, last - 1 ), first, last - 2 );
}

【问题讨论】:

  • 我正在测试你的代码,第一个 'madamhelloollehmadam' 也会抛出错误 btw
  • 这里提示:substr 的第二个参数不是索引,而是长度。
  • @travisjayday 我刚刚再次测试了“madamhelloollehmadam”它正在工作并且没有错误。这是我的第一个代码:pastebin.com/3YMAMerx
  • 这是出乎意料的证明它的工作。如果这是预期的,那将不是异常行为。如果不是例外,那也不是例外。
  • @AndyG 我将始终为“0”的“First”作为第二个参数发送到 substr。我不是吗???还是你的意思是别的?

标签: c++ string function recursion char


【解决方案1】:

使用 Visual Studio 中的 Windows Debug,您可以将问题定位到特定的行。

所以这是你的问题:在函数 normalString(string) 中你必须这样做:

for (int i = 0; i < vec.size(); ++i)
{
    if (!isAlpha(vec[i]))
        vec[i].erase();
    else if (isupper(stringToChar(vec[i])))  //this is where your error was. use visual studio to debug your application 
        vec[i] = charToString(tolower(stringToChar(vec[i])));
}

你试图在一个奇怪的角色上使用函数isupper,这导致你的程序崩溃。如果你使用 else if 语句,它会起作用,因为它不会尝试调用 isupper() 如果它不是字母字符。

课程:使用 Visual Studio 调试模式

编辑:我相信您尝试过这样做isupper('{0}')。 isupper() 显然不喜欢字符串终止符(它会崩溃)

【讨论】:

  • 在循环中删除这样的东西是 O(n^2) 没有充分的理由。此外,您必须先转换为unsigned char,然后再将内容传递给tolower
  • 是的,我同意。 @Dietrich Epp 的答案很可能更好,但这对于 OP 来说是一个快速修复。我希望他能够欣赏并学习调试程序的价值,以便他将来能够自己解决类似的问题。
  • 我只使用 Linux 进行编程(gedit)并使用终端进行调试...谢谢
  • @travisjayday 我不确定这是不是问题,因为我在这个函数上扔的任何东西都会把它变成一个词......
【解决方案2】:

这段代码有很多问题。

回文函数

首先,让我们稍微重写一下签名。由于palindrome 不需要字符串的副本,因此我们传入一个 const 引用。索引也应该更改为std::size_t,因为这是用于索引字符串的类型。

bool palindrome(const std::string &str, std::size_t first, std::size_t last) {

接下来,我们需要处理字符串只有一个字符的情况……但是处理字符串为零的情况很重要。这是原始代码:

    // if (first == str.size() - 1) // Wrong!

首先,这并不像它所说的那样。我们正在处理的字符串的长度应该是从firstlast,而不是从firstsize() - 1(否则为什么last 甚至存在?)其次,这行不通如果size() 为0。它将溢出!这是更正后的代码。

    // Empty string, or only one character
    std::size_t length = last - first;
    if (length <= 1)
        return true;

接下来,我们比较第一个和最后一个字符。但最后一个字符实际上不是str[last],而是str[last-1]

    if (str[first] == str[last - 1])

既然我们有方便的firstlast 参数,让我们使用它们而不是调用substr

        return palindrome(str, first + 1, last - 1);

但是我们要记得如果条件不成立就返回...

    return false;
}

普通字符串函数

原来std::stringpush_back,所以你不需要向量,而且isAlpha可以改成对char而不是string进行操作,这样就简单多了。

bool isAlpha(char c) {
    return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}

std::string normalString(std::string str) {
    std::string result;
    for (char c : str) {
        if (isAlpha(c))
            result.push_back(std::tolower(c));
    }
    return result;
}

完整代码

也删除了using namespace std;

#include <iostream>
#include <string>
#include <vector>
#include <locale>

bool palindrome(const std::string &, std::size_t, std::size_t);
std::string normalString(std::string);

int main() {
    while (true) {
        std::cout << "Enter a word or a sentence: ";
        std::string str;
        if (!(std::cin >> str))
            break;
        str = normalString(str);
        if (palindrome(str, 0, str.size())) {
            std::cout << str << " is palindrome!"
                << " (" << str << ")\n";
        } else {
            std::cout << str << " is not palindrome!"
                << " (" << normalString(str) << ") \n";
        }
    }
    return 0;
}

bool isAlpha(char c) {
    return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}

std::string normalString(std::string str) {
    std::string result;
    for (char c : str) {
        if (isAlpha(c))
            result.push_back(std::tolower(c));
    }
    return result;
}

bool palindrome(const std::string &str, std::size_t first, std::size_t last) {
    // Empty string, or only one character
    std::size_t length = last - first;
    if (length <= 1)
        return true;
    if (str[first] == str[last - 1])
        return palindrome(str, first + 1, last - 1);
    return false;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-04
    • 1970-01-01
    • 1970-01-01
    • 2019-09-30
    • 1970-01-01
    相关资源
    最近更新 更多