Проблемы с рекурсией и указателями в C ++ - PullRequest
0 голосов
/ 01 марта 2019

Прежде всего, это для назначения.

Что требуется:

1.Take in string input
2. copy string (stripping out white space, punctuation, and 
   covert all characters to uppercase in the process)
3. Then determine if this copied string is a palindrome.

Метод, необходимый для определения палиндрома:

Base Case:  string length is <= 1
General Case: if first letter != last letter, false, otherwise
               point to next letter and write '\0' to last letter and
               call the method again

Например:

RACECAR\0   R==R
ACECA\0     A==A
CEC\0       C==C
E\0         E <= 1  TRUE!

Я не могу заставить мою функцию isPalindrome работать правильно.Насколько я могу судить, все остальное на высоте.Я действительно думаю, что проблема заключается в моем рекурсивном вызове.Я отлаживал это в течение 2 дней, и я не могу понять, почему возврат неправильный.Любая помощь будет с благодарностью.Я не ищу руку, может быть, просто дополнительные глаза на этот код.Спасибо.

#include <iostream>
#include <string>
#include <cctype>   
using namespace std;

int charCount(char  * copy)
{
    int count = 0;

    for (int i = 0; copy[i] != '\0'; i++)
    {
        count++;
    }

    return count;
}

bool isPalindrome(char *copy)
{
    bool result = false;
    int size = charCount(copy);

    char * last = &copy[size - 1];

    if (size <= 1)
    {
        result = true;
    }

    if (copy != last)
    {
        result = false;
    }

    else
    {
        ++copy;
        last = '\0';
        isPalindrome(copy);
    }

    return result;
}

void stringCopy(char * source, char * destination)
{
    int sourceIndex = 0;
    int destIndex = 0;

    while (source[sourceIndex] != '\0')
    {
        while (!(isalnum(source[sourceIndex])) && source[sourceIndex] != '\0')
        {
            sourceIndex++;
        }

        if (source[sourceIndex] == '\0')
        {
            break;
        }

        if (isalpha(source[sourceIndex]))
        {
            destination[destIndex] = toupper(source[sourceIndex]);
        }

        if (isdigit(source[sourceIndex]))
        {
            destination[destIndex] = source[sourceIndex];
        }

        sourceIndex++;
        destIndex++;
    }

    destination[destIndex] = '\0';
}

int main()
{
    string input = "";

    cout << "Enter a string: ";
    getline(cin, input);

    char * source = &input[0];
    int sourceSize = charCount(source);

    char * copy = new char[sourceSize];

    stringCopy(source, copy);

    int copySize = charCount(copy);

    if (isPalindrome(copy))
    {
        cout << input << " is a palindrome!" << endl;
    }

    else
    {
        cout << input << " is not a palindrome" << endl;
    }

    return 0;
}

Ответы [ 3 ]

0 голосов
/ 01 марта 2019

copy! = Last

Эти переменные являются указателями на char.Вы должны разыменовать их перед сравнением.

Попробуйте: * copy! = * Last

0 голосов
/ 01 марта 2019

Это не предназначено для каких-либо проблем в вашем коде и не показывает, как писать код в соответствии с назначением.Код приведен только для полноты картины, чтобы показать, как вы решите проблему с помощью инструментов, которые уже предоставляет c ++, и не изобретая колесо.

std::copy_if и std::transform - это ваши stringCopy, а std::equal с оператором вперед и назад - это то, что вы делаете в своем isPalindrome.В любом случае использование рекурсии для этого случая не очень хорошая идея.

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


bool is_palindrom( const std::string &input ) {
    std::string copy;

    // copy everything except spaces and punctations using:
    // copy_if, isspace and ispunct
    std::copy_if(input.begin(), input.end(), std::back_inserter(copy), [] (int ch) -> bool {
        return !::isspace(ch) && !::ispunct(ch);
    });

    // transform to uppercase
    std::transform(copy.begin(), copy.end(), copy.begin(), ::toupper);

    // check if palindrom using iterators and revers iterators
    // copy.end()  - halfway is valid as std::string::iterator is a random access iterator
    size_t halfway = copy.size() / 2;
    bool isPalindrom = std::equal(copy.begin(),  copy.end()  - halfway, 
                                  copy.rbegin(), copy.rend() - halfway);

    return isPalindrom;
}

int main() {
    std::cout <<  is_palindrom("2aba2")  << std::endl; // 1
    std::cout <<  is_palindrom("2 ab a2")  << std::endl; // 1
    std::cout <<  is_palindrom("2 abb a2")  << std::endl; // 1
    std::cout <<  is_palindrom("abca")  << std::endl; // 0
}
0 голосов
/ 01 марта 2019

Четыре ошибки

Сначала у вас есть три случая, но вы хотите, чтобы только один из них выполнялся, поэтому это должен быть один оператор if ... else if ... else ..., а не оператор if ... if ... else ..., который у вас есть.

Во-вторых, ваше сравнение неверно, потому что вы сравниваете указатели, а не те символы, на которые они указывают.

Третья ошибка аналогична второй, когда вы пытаетесь сократить строку, которую вы назначаете указателю, а нек символу.

Наконец, вы забыли присвоить результат рекурсивного вызова вашей переменной result.Довольно распространенная ошибка новичка.

Вот мои усилия (непроверенный код)

bool isPalindrome(char *copy)
{
    bool result = false;
    int size = charCount(copy);

    char * last = &copy[size - 1];

    if (size <= 1)
    {
        result = true;
    }
    else if (*copy != *last) // else if and *copy != *last, not copy != last
    {
        result = false;
    }
    else
    {
        ++copy;
        *last = '\0'; // *last not last
        result = isPalindrome(copy); // capture return value from recursive call
    }

    return result;
}

Четыре ошибки в одной функции могут показаться довольно большими, но это глупые ошибки, которые легко исправить.Общее качество кода довольно хорошее.

Теперь для дополнительной информации посмотрим, сможете ли вы написать версию, которая не будет уничтожать строку, как она есть.Поскольку вы назначаете *last = '\0', вы меняете строку во время работы.

...