【问题标题】:How can I iterate through the last element of the vector without going out of bounds?如何在不超出范围的情况下遍历向量的最后一个元素?
【发布时间】:2021-10-03 11:44:13
【问题描述】:

预期的输出是 1a1b1c 但我只得到 1a1b 如果我尝试在 for 循环中的 input.size() 旁边放置“-1”,但这只会忽略错误。我正在寻找的是我希望能够遍历字符串的最后一个成员而不会越界。

 std::string input = "abc";

for (unsigned int i = 0; i < input.size(); i++){
     int counter = 1;
    while(input.at(i) == input.at(i+1) && i < input.size()-1){

        counter++;
        i++;
    }
        number.push_back(counter);
        character.push_back(input.at(i));
}

【问题讨论】:

  • 切换while循环中的测试顺序,这样当i &lt; input.size() - 1的测试失败时,您就不会尝试从i + 1读取。
  • 你不能用开箱即用的 std::string 来做到这一点,它不包含尾随 0。所以在这种情况下它的大小确实是 3。(在调试器中尝试) .但是,您可以手动添加额外的 0:输入 += '\0';
  • @PepijnKramer: C++11 及更高版本std::string 确实自动持有\0 终止符。但它不是报告大小的一部分。
  • @ShadowRanger 不,它没有,尾随零不需要在为 std::string 分配的内存中。如有必要,调用 c_str()、data() 或 const char* 运算符将附加它。 akrzemi1.wordpress.com/2014/03/20/strings-length
  • @PepijnKramer:您的链接不支持您所说的任何(它正确地说是C++ 字符串可以包含嵌入的NUL)。请参阅 the summary here:“指向 s[0] 的指针可以传递给期望指向 [null 终止(C++11 起)] CharT[] 数组的第一个元素的指针的函数。”或here, on StackOverflow, the same info。您正确地描述了 C++11 之前的工作方式。您对 C++11 及更高版本中标准的要求是 100% 错误的。

标签: c++ rle


【解决方案1】:

您需要考虑的几点:

1:for (unsigned int i = 0; i &lt; input.size(); i++) 特别是 i++。这是一个后缀操作,意味着它返回 i 然后增加 i 的值。这里对整数没什么大不了的,但是对于迭代器,这可能会变得非常昂贵,因为您每次都创建迭代器的副本。更愿意说出你的意思/你真正想要的,即增加 i,而不是获取 i 的副本并在之后增加 i。所以更喜欢++i,它只会增加 i 而不会复制。

2: unsigned int i = 0 首先,它比每次与input.size() 比较时都使用具有签名-> 无符号对话的int 更好,后者返回size_t。其次,unsigned int 不能保证足够大以容纳字符串的大小,并且需要从(可能)32 位 -> 64 位无符号提升以与 size_t 进行比较

3:认知复杂性,嵌套循环都改变相同的不变量(在本例中为 i)使代码更难以推理,并且随着时间的推移最终会导致更多的错误。在可能的情况下,只有一个循环不变量发生突变的地方。

4:正如其他人指出的那样,while 循环 while(input.at(i) == input.at(i+1) &amp;&amp; i &lt; input.size()-1) 可以超过字符串的大小,并且使用字符串的 .at 成员函数将抛出越界访问。这可以通过将嵌套循环重构为单个循环来通过第 3 点简单地解决。

5:避免多次调用.at,我们完全控制用于索引字符串的索引,因此您可以安全地使用operator[],只要我们可以保证 i 始终是有效索引在这种情况下,我认为你可以。

6:i &lt; input.size() 使用&lt;,当它不是您想要的支票并且它比您实际想要的支票i != input.size() 贵得多。在compiler explorer中查看这个简单的比较

谢天谢地,shadowranger 的修复完全解决了您的问题,即:while(i &lt; s.size()-1 &amp;&amp; s.at(i) == s.at(i+1)) 但是我想提供一个没有嵌套循环的替代方案,向您展示如何避免我的第 3、4、5 和 6 点:

void do_the_thing(std::string const& s) {
    std::cout << "Considering: \"" + s + "\"\n";
    if(s.empty()) {
        return;
    }

    size_t const length = s.length(); // avoiding repeated calls to length which never changes in this case
    if(length == 1) {
        std::cout << "1" << s[0] << "\n";
        return;
    }

    std::vector<unsigned> number;
    std::vector<char> character;

    // do the stuff your example did
    char last = s[0];
    unsigned same_count = 1;
    for(size_t ii = 1; ii != length; ++ii) {
        char const cur = s[ii];
        if(cur == last) {
            ++same_count;
        } else {
            number.push_back(same_count);
            character.push_back(last);
            last = cur;
            same_count = 1;
        }
    }

    if(*s.rbegin() == last) {
        number.push_back(same_count);
        character.push_back(last);
    }

    // print the things or use them in some way
    assert(number.size() == character.size());

    size_t const out_len = character.size();
    for(size_t ii = 0; ii != out_len; ++ii) {
        std::cout << number[ii] << character[ii];
    }
    std::cout << "\n";
}

【讨论】:

    猜你喜欢
    • 2022-11-26
    • 2015-06-03
    • 1970-01-01
    • 1970-01-01
    • 2021-10-23
    • 1970-01-01
    • 2021-11-12
    • 2021-01-28
    • 1970-01-01
    相关资源
    最近更新 更多