Код проверки палиндрома застрял в бесконечной петле - PullRequest
0 голосов
/ 16 января 2019

У меня проблема с разработкой палиндромной проверки. У меня нет проблем с отдельными словами («полдень», «2002» и т. Д.), Но каждый раз, когда я набираю фразу, состоящую из нескольких слов с пробелами (например, «ламинатное животное»), моя программа теряет рассудок и идет в бесконечный цикл. Возможно, это как-то связано с проверками (убедитесь, что строка не 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;
}

Ответы [ 3 ]

0 голосов
/ 16 января 2019

Замените cin >> temp; на getline(cin, temp);, чтобы получить строки, разделенные пробелами, а после cin >> rep; добавьте cin.ignore();, чтобы очистить новую строку.

0 голосов
/ 16 января 2019

Я чувствую, что вы слишком усложняете этот код: я покажу вам упрощенную версию в нескольких строках кода. Код чистый, лаконичный, читаемый и очень выразительный; он будет делать именно то, что говорит. Затем я объясню, где вы ошиблись, заканчивая описанием моей реализации, используя соответствующий инструмент или алгоритм для выполнения работы:


#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 >> variable, и это будет принимать текст вплоть до первого white space character, который он видит. Остальная часть текста в этой строке все еще находится в буфере, но не сохраняется в вашей переменной. Здесь вам нужно использовать std::getline(), и он принимает как минимум два параметра, первый из которых является источником ввода, например std::cin или std::ifstream или std::istringstream и т. Д. Второй параметр - это переменная, которую вы хотите сохранить ваша информация.

Существует третий необязательный параметр, и в этом случае мы хотим его использовать. Третий параметр ищет разделитель, и в этом случае мы хотим найти первый символ новой строки '\n'. Причина, по которой мы хотим использовать это здесь, заключается в том, что он извлекает его из буфера iostream, но не сохраняет его в вашей строке. Это хорошо, когда мы проверяем, является ли это палиндромом.

Как только мы получим строку текста, введенную пользователем, мы создадим переменную std::string с именем checker и инициализируем ее исходным вводом. Нам нужно прямое копирование, потому что в заголовке algorithm, который называется std::reverse, есть алгоритм, который идеально подходит для наших целей!

Однако нам нужна эта копия, поскольку std::reverse будет выполнять операции на месте. Мы не хотим потерять нашу оригинальную строку. Так что теперь наша проверка будет в порядке, обратном исходному вводу. Тогда достаточно простого сравнения, чтобы увидеть, равны ли две строки, отображаются ли они в соответствующем сообщении, а если нет, то же самое. Наконец, мы печатаем сообщение с вопросом, хочет ли пользователь выйти или нет.


РЕДАКТИРОВАТЬ: - Примечание: - Я забыл или упустил простую вещь об этой программе, палиндром в приведенном выше является case sensitive, мы могли бы сделать одна из трех вещей, мы могли бы сначала оставить ее там, где мы ожидаем факт 'A' != 'a'. Мы могли бы исправить это, преобразовав всю альфу в ::toupper или ::tolower, удалив всю чувствительность к регистру, однако эти функции работают с одиночными символами, а не со всей строкой, поэтому нам нужно написать функцию, чтобы все символы в строка либо в верхнем, либо в нижнем регистре, либо вызовом другого хорошего алгоритма с помощью stl, и это std::transform(...). Снова std::transform() находится в библиотеке Algorithm. И последнее, но не менее важное: мы можем предоставить пользователю выбор между обеими версиями. Я оставлю эту часть на ваше усмотрение.

-Пример- 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';
}
0 голосов
/ 16 января 2019
Оператор

std::cin >> считывает только следующий пробельный символ. Если вы хотите прочитать всю строку, используйте std::getline().

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

То, что происходило, было то, что первая операция чтения после ввода «гоночной машины» читала «гонку», а затем оставляла «машину» в потоке, затем следующая операция чтения читала «машину», что приводило к неожиданному поведению, поскольку ваш код ожидал 1 или 0.

Это не имеет отношения к вашей проблеме, но обычно лучше не использовать using namespace std. Существует множество причин, но самая основная из них заключается в том, что если вы напишите собственную функцию с именем getline(), у вас возникнут проблемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...