简体   繁体   English

字符串迭代器不可递减

[英]string iterator not decrementable

I have an issue with string::iterator . 我对string :: iterator有问题。 VS says string iterator not decrementable . VS说字符串迭代器不可递减 My first project works fine with the same function Is_Palindrom 我的第一个项目使用相同的功能Is_Palindrom可以正常工作

 #include <iostream> 
#include <string> 
#include <vector>
#include <array>
#include <valarray>
#include <functional>
#include <iterator> 
#include <algorithm>
#include <iterator>
#include <cctype>

using namespace std;

string Is_Palindrom(string str)
{
    string::iterator iter = str.begin();

    transform(str.begin(), str.end(), str.begin(), tolower);

    for (iter; iter != str.end(); iter++)
    {
        if (ispunct(*iter) || *iter == *" ")
        {
            str.erase(iter);
            iter--;
        }
    }

    return str;
}

void main()
{
    ostream_iterator<string, char>out(cout, "\n");
    string tmp;
    vector<string>str;

    while (getline(cin, tmp) && tmp != "quit")
        str.push_back(tmp);

    transform(str.begin(), str.end(), out, Is_Palindrom);
}

But if I load some words from a .txt and apply Is_Palindrome function it crashes, but if I change string::iterator to a simple loop with a [ ] access it works correct. 但是,如果我从.txt加载一些单词并应用Is_Palindrome函数,则会崩溃,但是如果我将string :: iterator更改为具有[]访问权限的简单循环,则它可以正常工作。 Here the problem code. 这里是问题代码。

#include <cstdlib> 
#include <ctime> 
#include <vector>
#include <fstream>
#include <iostream> 
#include <string> 
#include <vector>
#include <array>
#include <valarray>
#include <functional>
#include <iterator> 
#include <algorithm>
#include <iterator>
#include <cctype>

using std::string;
using std::vector;
using std::cout;
using std::cin;
using std::tolower;
using std::endl;
using std::ifstream;

string Is_Palindrom(string str);

int main()
{
    vector <string> wordlist;

    std::srand(std::time(0));

    ifstream fin;
    fin.open("text.txt");
    if (fin.is_open() == false)
    {
        std::cerr << "Can't open file. Bye.\n"; // не удается открыть файл 
        exit(EXIT_FAILURE);
    }

    string item;
    int count = 0;
    getline(fin, item, ' ');
    wordlist.push_back(item);
    transform(wordlist.begin(), wordlist.end(), wordlist.begin(), Is_Palindrom);

    while (fin) // до тех пор, пока нет ошибок ввода 
    {
        cout << count << " : " << wordlist[count] << endl;
        ++count;
        getline(fin, item, ' ');
        wordlist.push_back(item);
        transform(wordlist.begin(), wordlist.end(), wordlist.begin(), Is_Palindrom);
    }
    cout << "Done\n";
    fin.close();

    char play;
    cout << "Will you play a word game? <y/n> "; // запуск игры в слова 
    cin >> play;
    play = tolower(play);
    while (play == 'y')
    {
        string target = wordlist[std::rand() % wordlist.size()];
        int length = target.length();
        string attempt(length, '-');
        string badchars;
        int guesses = 6;
        cout << "Guess my secret word. It has " << length
            << " letters, and you guess\n"
            << "one letter at a time. You get " << guesses
            << " wrong guesses.\n";
        cout << "Your word: " << "attempt" << endl; // вывод слова
        while (guesses > 0 && attempt != target)
        {
            char letter;
            cout << "Guess a letter: ";
            cin >> letter;
            if (badchars.find(letter) != string::npos || attempt.find(letter) != string::npos)
            {
                cout << "You already guessed that. Try again.\n";
                continue;
            }
            int loc = target.find(letter);
            if (loc == string::npos)
            {
                cout << "Oh, bad guess !\n";
                --guesses;
                badchars += letter; // добавить к строке 
            }
            else
            {
                cout << "Good guess!\n";
                attempt[loc] = letter;
                // Проверить, не появляется ли буква еще раз 
                loc = target.find(letter, loc + 1);
                while (loc != string::npos)
                {
                    attempt[loc] = letter;
                    loc = target.find(letter, loc + 1);
                }
            }
            cout << "Your word: " << attempt << endl;
            if (attempt != target)
            {
                if (badchars.length() > 0)
                    cout << "Bad choices: " << badchars << endl;
                cout << guesses << " bad guesses left\n";
            }
        }
        if (guesses > 0)
            cout << "That's right!\n";
        else
            cout << "Sorry, the word is " << target << " . \n";
        cout << "Will you play another? <y/n> ";
        cin >> play;
        play = tolower(play);
    }
    cout << "Bye\n";
    return 0;
}

string Is_Palindrom(string str)
{
    string::iterator iter = str.begin();

    //for (int i = 0; i < str.length(); i++)
    for (iter; iter != str.end(); iter++)
    {
        //if (ispunct(str[i]) || str[i] == *" ")
        if (ispunct(*iter) || *iter == *" ")
        {
            //str.erase(i, 1);
            //i--;
            str.erase(iter, iter+1);
            if (iter == str.end())
                break;
            iter--;
        }
    }

    return str;
}

The problem in your code is 您的代码中的问题是

if (ispunct(*iter) || *iter == *" ")
{
    str.erase(iter);
    iter--;
}

First, if you want to check a character you should use ' not " . So your statement should be 首先,如果要检查字符,则应使用' not " 。因此,您的声明应为

if (ispunct(*iter) || *iter == ' ')
//or even better
if (ispunct(*iter) || isspace(*iter))

Secondly, you are using erase() . 其次,您正在使用erase() When you call erase it invalidates all references and iterators to the current element to the end. 当您调用擦除时,它将使对当前元素的所有引用和迭代器无效。 Since you are using the same iterator that you used to delete the element this is undefined behavior . 由于使用与删除元素相同的迭代器,因此这是未定义的行为 Just because it works in the first example doesn't mean it will work in another piece of code. 仅仅因为它在第一个示例中有效并不意味着它将在另一段代码中有效。 Luckily erase() returns an iterator to the element after the erased element. 幸运的是, erase()将迭代器返回到该元素之后的元素。 We can capture that iterator and use that for the next iteration. 我们可以捕获该迭代器,并将其用于下一次迭代。 In order to do this, you need to change your for loop into a while loop like: 为此,您需要将for循环更改为while循环,例如:

while(iter != str.end())
{
    if (ispunct(*iter) || isspace(*iter))
        iter = str.erase(iter);  // erase and don't increment as we are already on the next character
    else
        iter++; // increment since it was a valid character
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM