【问题标题】:Palindrome Checker Code Stuck in Infinite Loop回文检查器代码卡在无限循环中
【发布时间】:2019-06-10 02:08:16
【问题描述】:

我在设计回文检查器时遇到了问题。我对单个单词(“noon”,“2002”等)没有问题,但是每次我输入一个包含多个带空格的单词的短语(例如“laminate pet animal”)时,我的程序就会失去理智并进入无限循环。也许它与我放入的检查有关(确保字符串不是 NULL 或大于 80 个字符)?我一直在逐步调试,但没有成功。我认为这与字符串在内存中的存储方式有关,但我无法准确放置。

    //Preprocessor directives
    #include <iostream>
    #include <cstdlib>
    #include <string>
    #include <iterator>
    #include <vector>
    #include <stdlib.h>

    using namespace std;

    //Function declarations
    string input();
    bool check(string a);

    int main()
    {
        //Repeater variable
        bool rep = 1;
        bool result = 0;

    //Declares string to be checked
    string palin;
    while (rep == 1)
    {
        //Creates string and calls input function
        palin = input();

        //Close function if stopped midway
        if (palin == "2")
        return 0;

        result = check(palin);

        //Displays the results
        if (result == 1)
            cout << palin << " is a palindrome." << endl;
        else
            cout << palin << " is not a palindrome." << endl;

        //Ask if the user wants to enter another Palindrome
        cout << "Continue? (1 for yes, 0 for no): ";
        cin >> rep;
    }

    cout << "Closing program..." << endl;
    system("pause");
    return 0;
}

string input()
{
    //Asks for and receives input string
    string temp;
    cout << "Please enter a string (type zero or 0 to quit): ";
    cin >> temp;

    //Close program if user enters 0 or zero
    if (temp == "0" || temp == "zero")
    {
        cout << "Exiting program..." << endl;
        system("pause");
        return "2";
    }

    //Check if string is null, then ask for input again
    if (temp.empty())
    {
        cout << "There is nothing entered. Please enter a string: ";
        cin >> temp;
    }

    //Check if string is too long, ask for input again
    if (temp.length() >= 80)
    {
        while (temp.length() > 80)
        {
            cout << "The string is too long. Please enter a smaller string: ";
            cin >> temp;
        }
    }
    return temp;
}

bool check(string a)
{
    //Creates 2 iterators that traverse the string
    string::iterator test1;
    string::reverse_iterator test2;

    test1 = a.begin();
    test2 = a.rbegin();

    //Continue until the end of either side of the string
    while (test1 != a.end() && test2 != a.rend())
    {
        //Check if the current symbol is alphanumeric
        while (test2 != a.rend() && !isalnum(*test2))
            ++test2;
        while (test1 != a.end() && !isalnum(*test1))
            ++test1;
        //Break loop when you hit the end
        if (test1 == a.end() || test2 == a.rend())
            break;
        //If they're not the same it's not a palindrome, exit function
        if (tolower(*test1) != tolower(*test2))
            return 0;

        ++test1;
        ++test2;
    }
    return 1;
}

【问题讨论】:

  • 为什么不只是::std::string r = argv[1]; ::std::reverse(r.begin(),r.end()); return r != argv[1];

标签: c++ string loops iterator palindrome


【解决方案1】:

我觉得您将这段代码过于复杂化了:我将在几行代码内向您展示一个简化版本。代码干净、简洁、易读且富有表现力;它会完全按照它所说的去做。然后,我将解释您在使用适当的工具或算法完成工作的同时完成对我的实现的描述的错误之处:


#include <algorithm>
#include <iostream>
#include <string>

void runPalindrome();

int main() {
    runPalindrome();
    return 0;
}

void runPalindrome() {
    std::string quit;
    do {
        std::cout << "Please enter text to test if it is a palindrome:\n";
        std::string input;
        std::getline(std::cin, input, '\n');

        std::string checker(input);
        std::reverse(checker.begin(), checker.end());

        if (input == checker)
            std::cout << input << " is a palindrome!\n";
        else 
            std::cout << input << " is not a palindrome!\n";

        std::cout << "Press Q or q to (Q)uit or any other character to continue...\n";
        std::getline(std::cin, quit, '\n');

    } while ( quit != std::string( "Q" ) && quit != std::string( "q" ) );

    std::cout << "Exiting the program!\n";
}

您遇到的问题是您使用的是std::cin &gt;&gt; variable,这将接收到它看到的第一个white space character 的文本。该行的其余文本仍在缓冲区中,但未存储到您的变量中。这里你需要使用std::getline(),它至少需要两个参数,第一个是输入的来源,例如std::cinstd::ifstreamstd::istringstream等。第二个参数是你要存储的变量你的资料。

还有第三个参数是可选的,在这种情况下我们确实想使用它。第三个参数查找分隔符,在这种情况下,我们要查找第一个换行符'\n'。我们想在这里使用它的原因是它会从 iostream 缓冲区中检索它,但不会将它存储到您的字符串中。当我们检查它是否是回文时,这很有用。

一旦我们得到用户输入的文本字符串,我们就会创建一个名为checkerstd::string 变量,并使用原始输入对其进行初始化。我们想要一个直接复制,因为在 algorithm 标头中找到了一种算法,称为 std::reverse,对于我们的目的来说这是完美的!

但是我们需要该副本,因为std::reverse 将执行适当的操作。我们不想丢失我们的原始字符串。所以现在我们的检查器将与原始输入的顺序相反。然后,只需进行一次比较即可查看两个字符串是否相等,它们是否显示适当的消息,如果不一样,则执行相同的操作。最后,我们打印一条消息,询问用户是否要退出。


编辑: -- 注意: - 我忘记或忽略了关于这个程序的一个简单的事情,上面的回文是casesensitive,我们可以做三件事之一,我们可以先把它留在我们期望'A' != 'a'的地方。我们可以通过将所有 alpha 转换为 ::toupper::tolower 来消除所有大小写敏感性来解决这个问题,但是这些函数适用于单个字符而不是完整的字符串,因此我们必须编写一个函数来使字符串要么全部大写,要么全部小写,或者通过 stl 调用另一个不错的算法,即std::transform(...)。在Algorithm 库中再次找到std::transform()。最后但同样重要的是,我们可以让用户在两个版本之间进行选择。我将把这部分留给你作为练习。

-示例-std::transform

{
    std::string str( "HelLo" );
    std::cout << str << '\n';
    std::transform( str.begin(), str.end(), str.begin(), ::toupper );
    std::cout << str << '\n';
    std::transform( str.begin(), str.end(), str.begin(), ::tolower );
    std::cout << str << '\n';
}

【讨论】:

    【解决方案2】:

    std::cin&gt;&gt; 运算符只能读取到下一个空白字符。如果您想阅读整行,请使用std::getline()

    cin >> temp; //reads until the next whitespace
    getline(cin, temp); //reads until the next newline character
    

    发生的情况是,您输入“race car”后的第一次读取操作会读取“race”,然后将“car”留在流中,然后下一次读取操作会读取“car”,导致出现意外行为,因为您的代码需要 1 或 0。

    这与您的问题无关,而是it's usually good form to not use using namespace std。原因有很多种,但最基本的原因是,如果您编写自己的函数称为getline(),就会遇到问题。

    【讨论】:

      【解决方案3】:

      cin &gt;&gt; temp; 替换为getline(cin, temp); 以获得空格分隔的字符串,并在cin &gt;&gt; rep; 之后添加cin.ignore(); 以刷新换行符。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-05-19
        • 1970-01-01
        • 1970-01-01
        • 2021-06-02
        • 1970-01-01
        • 2012-03-15
        • 1970-01-01
        • 2013-12-30
        相关资源
        最近更新 更多