加密字符串但接收无限循环
Encrypting a string but receiving an infinite loop
问题:
我试图使用单个规则加密std::string
密码:
- 元音前后添加"0">
这样bAnanASplit
就变得b0A0n0a0n0A0Spl0i0t
. 然而,我陷入了一个无限循环。
这是代码:
const std::string VOWELS = "AEIOUaeiou";
std::string pass = "bAnanASplit";
//Add zeroes before and after vowels
for (int i = 0; i < pass.length(); ++i)
{
i = pass.find_first_of(VOWELS, i);
std::cout << pass << "n";
if(i != std::string::npos)
{
std::cout << pass[i] << ": " << i << "n";
pass.insert(pass.begin() + i++, '0');
pass.insert(pass.begin() + ++i, '0');
}
}
。结果是:
bAnanASplit
A: 1
b0A0nanASplit
a: 5
b0A0n0a0nASplit
A: 9
b0A0n0a0n0A0Split
i: 15
b0A0n0a0n0A0Spl0i0t
b0A0n0a0n0A0Spl0i0t
A: 2
b00A00n0a0n0A0Spl0i0t
a: 8
b00A00n00a00n0A0Spl0i0t
A: 14
b00A00n00a00n00A00Spl0i0t
i: 22
b00A00n00a00n00A00Spl00i00t
b00A00n00a00n00A00Spl00i00t
...
有什么帮助吗?这确实看起来很奇怪。
编辑:所有的答案都是有用的,因此我接受了我认为最能回答这个问题的答案。但是,此答案显示了解决问题的最佳方法。
永远不要修改您正在迭代的集合/容器!
这样为您省去了很多麻烦。
让我们从您的代码开始,并生成一个新字符串,其元音被0
包围。
const std::string VOWELS = "AEIOUaeiou";
std::string pass = "bAnanASplit", replacement;
//Add zeroes before and after vowels
for (auto ch : pass)
{
if(VOWELS.find(ch) != std::string::npos)
replacement += '0' + ch + '0';
else
replacement += ch;
}
你有它!
由于 OP 似乎在寻找不当行为的确切原因,我想添加另一个答案,因为现有答案没有显示确切的问题。
意外行为的原因在以下行中可见。
for (int i = 0; i < pass.length(); ++i)
{
i = pass.find_first_of(VOWELS, i);
...
问题1:
循环计数器i
是一个int
(即signed int
(。但是 std::string::find_first_of 如果没有匹配项,则返回 std::string::npos。这通常是unsigned long
可表示的最大数量。将一个巨大的unsigned
值分配给较短的signed
变量将存储一个完全出乎意料的值(假设您不知道这一点(。在这种情况下,i
意志在大多数平台中变得-1
(如果您需要确定,请尝试int k = std::string::npos;
并打印k
(。i = -1
是循环条件i < pass.length()
的有效状态,因此将允许下一次迭代。
问题2:
与上述问题密切相关的是,使用相同的变量i
来定义find
操作的起始位置。但是,如前所述,i
不会像您期望的那样代表字符的索引。
溶液:
存储格式错误的值可以通过使用正确的数据类型来解决。在当前情况下,最好的选择是使用std::string::size_type
因为这始终保证有效(很可能这等于size_t
任何地方(。为了使程序使用给定的逻辑,您还必须使用不同的变量来存储find
结果。
但是,更好的解决方案是使用std::stringstream
来构建字符串。这将比通过在中间插入字符来修改字符串的性能更好。
例如
#include <iostream>
#include <sstream>
int main() {
using namespace std;
const string VOWELS = "AEIOUaeiou";
const string pass = "bAnanASplit";
stringstream ss;
for (const char pas : pass) {
if (VOWELS.find(pas) == std::string::npos) {
ss << pas;
} else {
ss << '0' << pas << '0';
}
}
cout << pass << "n";
cout << ss.str() << endl;
}
如果循环变得std::string::npos
i
您不会退出循环。因此,当i
值到达 i 之后的最后一个 i 或 0 的位置时,它会被更改为一些意外的值(可能类似于 -1((这里我指的是 spl i t 的i(。这是因为i
是一个有符号整数,但在这种情况下,find_first_of()
返回std::string::npos
这是size_t
可以持有的最大值。在这种情况下,终止条件i < pass.length()
可能成立,循环继续。因此,我建议对您的代码进行以下更改 -
for (size_t i = 0; i < pass.length(); ++i)
{
i = pass.find_first_of(VOWELS, i);
if(i == std::string::npos)
break;
pass.insert(pass.begin() + i++, '0');
pass.insert(pass.begin() + ++i, '0');
}
同样,if (i != std::String::npos)
不会做你期望它做的事情。
但话又说回来,最好不要在迭代容器时修改容器,@Tanveer在他的回答中提到过
- 过载'operator new'如何导致无限循环?
- C++正则表达式无限循环
- 程序在尝试猜测它选择的随机数时进入无限循环?
- 遍历链表时的无限循环
- 循环链表:无限循环
- 比较两个字符串后卡在无限循环中
- 在做一段时间内检查字符的无限循环
- 逐字读取文本文件中的每一行并转换为 int(无限循环或崩溃?
- 在这个无限循环中,当输入 0 时终止,当输入 int 范围之外的任何内容时,程序行为不正常
- 可能的无限循环
- 加密字符串但接收无限循环
- 当我的 if 语句在字符串中找到空格时,在无限循环中切换
- 开关大小写语句中函数中的字符串输入会导致无限循环和绕过输入
- 输入 2 个非常基本的 C 字符串时的无限循环
- 输入验证,需要数字,而不是字符串.代码导致无限循环
- C++用户输入到字符串数组的无限循环
- C++字符串替换函数无限循环
- 无限循环记录字符串
- 为什么字符串中的空格使我的代码无限循环
- 当输入字符串而期望输入数字时,使用cin进行无限循环