【问题标题】:CPP for loop through characters of a string starts at unexpected index?CPP for 循环遍历字符串的字符从意外索引开始?
【发布时间】:2019-03-06 19:05:26
【问题描述】:
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 值的图像,旁边是长度明显不相关的字符串。怎么回事?

调试值:

【问题讨论】:

    标签: c++ string loops for-loop


    【解决方案1】:

    对于无符号值i>=0 始终为真。所以你的索引变为零,然后环绕到最大的 unsigned long 值,在你的情况下,它是 18446744073709551615。

    像这样写你的循环(例如)

    for (unsigned long i = add1.length(); i-- > 0; ) {
    

    【讨论】:

    • @Aidan 替代变体:for(i = length - 1; i < length; --i) - 任一变体:不要忘记最初检查长度是否 > 0。
    • 反向迭代器在这里也会有帮助。
    【解决方案2】:

    收集cmets到johnanswer

    由于无符号值永远不会小于 0,因此您最终会陷入无限循环,在达到 0 后循环并以一个巨大的值结束。

    你现在有几个选择:

    1. 在递减之前检查索引(对此的幽默观点请参阅here):

      for (unsigned long i = add1.length(); i-- > 0; )
    2. 从环绕下溢行为中获利:

      for (unsigned long i = add1.length() - 1; i 
      
    3. 反向迭代器——我认为这是最可取的变体;但我们需要初始化两个变量并依赖序列(逗号)运算符,有些人可能不赞成......:

      for(auto i1 = add1.rbegin(), i2 = add2.rbegin(); i1 != add1.rend(); ++i1, ++i2)
      // ++,即使是反向的! ^ ^
      {
          // 这里使用 *i1 和 *i2
      }

    您可能更喜欢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))) – 我几乎无法想象效率更低的事情......

    1. at 进行范围检查,但是通过您的循环,您已经确定了范围(假设您根据上述变体之一修复了它),因此没有的索引运算符 (addN[i]) 是更好的选择。承认,这一次,由于循环不正确,at 阻止了你未定义的行为。因此,您可以先从at 开始,并在您知道代码运行正确后立即替换为索引运算符...
    2. (重得多):中间琴弦(真的)很长。由于 C++ 标准保证具有后续代码点的数字(仅!!!),您可以简单地执行 addN[i] - '0'(或 *iX - '0',如果使用迭代器)来获取值。如果您想保持便携性,请不要假设字母也是如此,例如在 if('A' <= c && c <= 'Z') c += 'a' - 'A' 中(对于此示例,已经存在 function 做同样的事情,您绝对应该喜欢它)。

    如果我们已经处于效率状态:如果您将所有新密码添加到结果字符串的数字(好吧,代码没有显示,但我可以想象你这样做......),你会一次又一次地移动所有已经插入的值。而是追加新数字并在完成时将std::reverse 应用于结果。

    【讨论】:

      猜你喜欢
      • 2016-01-09
      • 1970-01-01
      • 2023-01-24
      • 1970-01-01
      • 2016-01-24
      • 2015-01-17
      • 2021-04-02
      • 2015-06-03
      • 1970-01-01
      相关资源
      最近更新 更多