>  Q&A  >  본문

c++11 - 如何设置C++string迭代器循环终止条件?

大家好,我刚开始学习C++,学习教材是C++ Primer 第五版。今天在完成书上的一个练习时(324页,练习9.43),总是发生out_of_range错误,经过调试发现,函数find_and_replace中的for循环没有终止。

代码如下:

#include <iostream>
#include <string>

int find_and_replace(std::string& org_str, const std::string& str4find, const std::string& str4replace);

int main(int argc, char const *argv[])
{

    std::string str("I am a very loooooong string to be process!");
    int find_times;
    find_times = find_and_replace(str, "a", "###");
    std::cout << find_times << std::endl;
    std::cout << str << std::endl;

    return 0;
}

int find_and_replace(std::string& org_str, const std::string& str4find, const std::string& str4replace)
{
    int find_times = 0;
    // 被检查字符串长度小于等于匹配字符串长度的情况
    if (org_str.size() < str4find.size())
    {
        std::cout << "Error: The original string is too short!" << std::endl;
        return find_times;
    }
    else if (org_str == str4find)
    {
        org_str.assign(str4replace);
        ++find_times;
        return find_times;
    }

    // 其他情况
    for (auto i = org_str.begin(), j = i + str4find.size(); j != org_str.end(); )
    {
        std::string temp(i, j);
        std::cout << temp << std::endl;
        if (temp == str4find)
        {
            j = org_str.erase(i, j);
            org_str.insert(i, str4replace.begin(), str4replace.end());
            std::cout << org_str << std::endl;
            std::cout << *i << std::endl;
            j = i + str4find.size();
            std::cout << *j << std::endl;
            ++find_times;
        }
        else
        {
            ++i;
            ++j;
        }
    }

    // 跳出循环时,迭代器i和org_str.end()中间的字符串还没有检查
    if (org_str.substr(org_str.size() - str4find.size()) == str4find)
    {
        org_str.erase(org_str.size() - str4find.size(), str4find.size());
        org_str.insert(org_str.end(), str4replace.begin(), str4replace.end());
        ++find_times;
    }

    return find_times;
}

我在擦除和插入操作后都及时更新了迭代器j而且能够保证i始终在j之前,请问为什么我的循环终止条件j != org_str.end()没有起作用呢?

PHP中文网PHP中文网2765일 전640

모든 응답(3)나는 대답할 것이다

  • PHPz

    PHPz2017-04-17 13:25:30

    你既然知道erase之后用返回值提供的迭代器,那么insert同样有可能会让迭代器失效,而且你的这种替换方法逻辑有问题,如果"a",替换成"abc",你这个就无限替换了。。。

    회신하다
    0
  • 阿神

    阿神2017-04-17 13:25:30

    你遍历的时候去改变这个string, 很可能迭代器已经失效了. 你看看是不是这个问题

    회신하다
    0
  • PHPz

    PHPz2017-04-17 13:25:30

    现在这个问题我搞明白了,算是自问自答吧,正如上面两位朋友所言,问题出在擦除和插入数据后i和j是失效的迭代器,尽管std::cout输出的看上去正确,但是其本质上还是失效的。由于我的编译器不支持i = org_str.insert(i, str4replace.begin(), str4replace.end());因此我只好写了一个循环,新版的更正后的代码如下:

    #include <iostream>
    #include <string>
    
    int find_and_replace(std::string& org_str, const std::string& str4find, const std::string& str4replace);
    
    int main(int argc, char const *argv[])
    {
        std::string str("I am a very loooooong string to be process!");
        int find_times;
        find_times = find_and_replace(str, "o", "!@#");
        std::cout << find_times << std::endl;
        std::cout << str << std::endl;
    
        return 0;
    }
    
    int find_and_replace(std::string& org_str, const std::string& str4find, const std::string& str4replace)
    {
        int find_times = 0;
        // 被检查字符串长度小于等于匹配字符串长度的情况
        if (org_str.size() < str4find.size())
        {
            std::cout << "Error: The original string is too short!" << std::endl;
            return find_times;
        }
        else if (org_str == str4find)
        {
            org_str.assign(str4replace);
            return ++find_times;
        }
    
        // 其他情况
        // 终止条件是为了保证最后一段能够处理完毕,如果按照之前的j != org_str.end(),则还需要在循环外写一段代码处理最后一段字符串
        for (auto i = org_str.begin(), j = i + str4find.size(); (i + (str4find.size() - 1)) != org_str.end(); )
        {
            std::string temp(i, j);
            // std::cout << temp << std::endl;
            if (temp == str4find)
            {
                // 更新i
                i = org_str.erase(i, j);
                for (auto k = str4replace.begin(); k != str4replace.end(); ++k, ++i)
                {
                    // 每次都更新i
                    i = org_str.insert(i, *k);
                }
                // 用i更新j
                j = i + str4find.size();
                ++find_times;
            }
            else
            {
                ++i;
                ++j;
            }
        }
    
        return find_times;
    }

    회신하다
    0
  • 취소회신하다