for(unsigned long i=add1.length()-1;i>=0;i--){
int presum = stoi(to_string(add1.at(i))) + stoi(to_string(add2.at(i))) + curcarry;
我有这段代码在字符串(add1)的各个字符之间循环,从字符串的最后一个到第一个。然后,它使用索引获取当前字符并将其转换为整数,并将其添加到保证长度相等的另一个字符串(add2)的当前字符中。
我收到一个字符串out_of_range错误,在查看调试菜单时,我看到虽然我的字符串都应该是正确的,但长度只有3个,但是i值最终以18446744073709551615
附加的是i值的图像,以及长度显然不相关的字符串。发生了什么事?
调试值:
答案 0 :(得分:5)
对于无符号值i>=0
始终为true。因此,您的索引为零,然后回绕到最大的unsigned long
值,在您的情况下为18446744073709551615。
像这样编写循环(例如)
for (unsigned long i = add1.length(); i-- > 0; ) {
答案 1 :(得分:1)
由于无符号值永远不会小于0,因此您将陷入无穷循环,并在达到0后环绕并以一个巨大值结束。
您现在有几个选择:
在递减之前检查索引(有关此内容的幽默观点,请参见here):
for (unsigned long i = add1.length(); i-- > 0; )
通过围绕下溢行为进行补偿:
for (unsigned long i = add1.length() - 1; i < add1.length(); --i)
反向迭代器–我认为这是最可取的变体。但是我们需要初始化两个变量并依赖于序列(逗号)运算符,有些可能不赞成...:
for(auto i1 = add1.rbegin(), i2 = add2.rbegin(); i1 != add1.rend(); ++i1, ++i2) // ++, even if going reverse! ^ ^ { // use *i1 and *i2 here }
您可能更喜欢size_t
类型而不是unsigned long
,它将始终具有适当的大小,并且是std::string::length
或任何STL容器的size
函数返回的类型也是如此。
不过,我看不到在处理add2
是较短字符串的情况下–上面的 any 会导致未定义的行为!如果add1
是较短的那个,则您将从add2
的中间开始。涵盖两者:
decltype(add1.rend()) ir, er;
for(auto i1 = add1.rbegin(), i2 = add2.rbegin(); ; ++i1, ++i2)
^ leaving out condition!
{
if(i1 == add1.rend())
{
ir = i2; // handle rest of add2 after loop
er = add2.rend(); // needed to be able to compare with appropriate end
break;
}
if(i2 == add2.rend())
{
ir = i1; // handle rest of add1 after loop
er = add1.rend(); // needed to be able to compare with appropriate end
break;
}
// adding the values as you did before
}
for(; ir != er; ++ir)
{
// special handling: append whatever remained from add1 or add2
}
最后:stoi(to_string(addN.at(i)))
–我简直无法想象效率低下的任何事情……
at
会进行范围检查,但是通过循环,您已经确定了范围(假定已根据上述变体之一对其进行了修复),因此索引运算符(addN[i]
)不会,是更好的选择。诚然,这次,因为循环不正确,at
阻止了您未定义的行为。因此,您可以先从at
开始,然后在知道代码正确运行后立即替换为索引运算符... addN[i] - '0'
(或*iX - '0'
,如果使用迭代器)来获取值。如果您想保持便携性,也不要像字母if('A' <= c && c <= 'Z') c += 'a' - 'A'
那样使用字母(对于此示例,已经有function这样做,您绝对应该这样做)。如果我们已经达到了效率:如果您将所有新密码的数字都前缀(在结果字符串之前)(嗯,没有显示代码,但是我可以想象您正在这样做……),您将一次又一次地移动所有已插入的值。宁可追加新数字,完成后将std::reverse
应用于结果。