大家好,我刚开始学习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()没有起作用呢?
PHPz2017-04-17 13:25:30
你既然知道erase之後用返回值提供的迭代器,那麼insert同樣有可能會讓迭代器失效,而且你的這種替換方法邏輯有問題,如果"a",替換成"abc",你這個就無限替換了。 。 。
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;
}