根据c ++教程和关于find()
的教学,实现了以下代码,以便在string
中搜索所有“cat”事件:
std::string input;
std::size_t i = 0, x_appearances = 0;
std::getline(std::cin,input);
for(i = input.find("cat",0); i != std::string::npos; i=input.find("cat", i))
{
++x_appearances;
++i; //Move past the last discovered instance to avoid finding the same string
}
然后教程挑战学徒改变find()
rfind()
,这就是问题出现的地方,首先我尝试了一些看似明显的方法:
for(i = input.rfind("cat",input.length()); i != std::string::npos; i=input.rfind("cat", i))
{
++x_appearances;
--i; //Move past the last discovered instance to avoid finding the same string
}
但是通过这个解决方案我陷入了无限循环。然后我发现它发生了,因为增量是在条件检查之前执行的,并且增量rfind()
总是找到匹配,即使是i==std::string::npos
(如果匹配在字符串的开头,例如“猫”)。我的最终解决方案是:
int n=input.length();
for(i = input.rfind("cat",input.length()); n>0 && i!=std::string::npos; i=input.rfind("cat", i))
{
++x_appearances;
n=i;
--i; //Move past the last discovered instance to avoid finding the same string
}
使用n
我可以跟踪string
中的位置,并在搜索完整个for loop
后退出string
。
所以我的问题是:我的方法是否正确?我需要一个额外的变量还是有其他更简单的方法吗?
答案 0 :(得分:1)
for(i = input.rfind("cat",input.length()); i != std::string::npos; i=input.rfind("cat", i))
{
++x_appearances;
--i; //Move past the last discovered instance to avoid finding the same string
}
以上问题是循环内的--i
。假设输入字符串以“cat”开头。您的算法最终会找到i
为0的“cat”。由于您已将i
声明为std::size_t
,因此从0减去1会产生最大的std::size_t
。没有警告,没有溢出,没有未定义的行为。根据标准,这正是无符号整数的工作方式。
不知何故,你需要处理这种特殊情况。您可以在循环中使用辅助变量和更复杂的测试。另一种方法是保持代码简单,同时明显地明确处理这种特殊情况:
for (i = input.rfind("cat"); i != std::string::npos; i=input.rfind("cat", i-1))
{
++x_appearances;
// Finding "cat" at the start means we're done.
if (i == 0) {
break;
}
}
另请注意,我已经改变了循环语句。 pos
的默认值为std::string::npos
,表示从字符串末尾搜索。初始化器不需要第二个参数。我还将--i
移到了for循环的更新部分,将input.rfind("cat",i)
更改为input.rfind("cat",i-1)
。由于此时i
总是正数,因此减去一个没有危险。