字符串迭代器不会在字符串末尾停止

时间:2019-12-27 18:49:10

标签: c++ string loops iterator segmentation-fault

我正在从由不同子字符串组成的一行中按以下顺序读取美味食谱:;

  • 食谱索引(R1

  • 要烹饪的数量(1

  • 食谱名称(Ensalada Mixta

  • 成分及其数量(Lechuga 200;...

前三个工作就像一个超级按钮,您可以看到它们存储在data数组中并打印在printf块中。问题出在阅读其余部分。 reader迭代器可以完美地读取该行,但不会在结尾处停止,因此它将垃圾值添加到该对中并引发段错误。这是此MRE的输出:

:: R1
:: 1
:: Ensalada Mixta
-> Lechuga 200
-> Tomate 50
-> Pepino 50
-> Cebolla 50
-> Aceite Oliva 5
-> Vinagre De Vino 10
-> Sal 1
[1]    85313 segmentation fault (core dumped)

循环应该在Sal 1之后停止,那么我在做什么错呢?这是代码:

#include <cmath>
#include <list>
#include <string>
#include <utility>
#include <cstdio>

using namespace std;

int main () {
    string line = "R1;1;Ensalada Mixta;Lechuga 200;Tomate 50;Pepino 50;Cebolla 50;Aceite Oliva 5;Vinagre De Vino 10;Sal 1";
    list<pair<string, unsigned> > ings;

    string recipe_data[3];
    string::const_iterator reader = line.cbegin();

    //Lectura del código, plato y ing_name de la receta
    for (int i = 0; i < 3; ++reader) {
        if (*reader != ';')
            recipe_data[i].push_back(*reader);
        else
            ++i;
    }

    printf(":: %s\n", recipe_data[0].c_str());
    printf(":: %s\n", recipe_data[1].c_str());
    printf(":: %s\n", recipe_data[2].c_str());
/*
 * This is the problematic loop. The problem is in the while boolean
 * expression, which always evaluates to false.
 */
    while (reader != line.cend()) {
        string ing_name = "";
        unsigned ing_quantity = 0;

        while (*reader != ';' && reader != line.cend()) {
            ing_name += *reader;
            ++reader;
        }

        string::reverse_iterator it = ing_name.rbegin();

        for (int i = 0; *it != ' '; i++) {
            char c[1] = {*it};
            ing_quantity += atoi(c) * pow(10, i);
            ++it;
            ing_name.pop_back();
        }
        ing_name.pop_back();

        pair<string, unsigned> ing(ing_name, ing_quantity);
        ings.push_back(ing);

        printf("-> %s %d\n", ing.first.c_str(), ing.second);

        ++reader;
    }
}

这是在最后++reader行使用断点的gdb输出:

Breakpoint 1, main () at so.cpp:52
52          ++reader;
1: reader = 59 ';'
2: line.cend() = 0 '\000'
3: ing = {first = "Tomate", second = 50}
(gdb) 
Continuing.
-> Pepino 50

Breakpoint 1, main () at so.cpp:52
52          ++reader;
1: reader = 59 ';'
2: line.cend() = 0 '\000'
3: ing = {first = "Pepino", second = 50}
(gdb) 
Continuing.
-> Cebolla 50

Breakpoint 1, main () at so.cpp:52
52          ++reader;
1: reader = 59 ';'
2: line.cend() = 0 '\000'
3: ing = {first = "Cebolla", second = 50}
(gdb) 
Continuing.
-> Aceite Oliva 5

Breakpoint 1, main () at so.cpp:52
52          ++reader;
1: reader = 59 ';'
2: line.cend() = 0 '\000'
3: ing = {first = "Aceite Oliva", second = 5}
(gdb) 
Continuing.
-> Vinagre De Vino 10

Breakpoint 1, main () at so.cpp:52
52          ++reader;
1: reader = 59 ';'
2: line.cend() = 0 '\000'
3: ing = {first = "Vinagre De Vino", second = 10}
(gdb) 
Continuing.
-> Sal 1

Breakpoint 1, main () at so.cpp:52
52          ++reader;
1: reader = 0 '\000'
2: line.cend() = 0 '\000'
3: ing = {first = "Sal", second = 1}
(gdb) n
47          pair<string, unsigned> ing(ing_name, ing_quantity);
1: reader = 0 '\000'
2: line.cend() = 0 '\000'
3: ing = {first = "Sal", second = 1}
(gdb) 
29          string ing_name = "";
1: reader = 0 '\000'
2: line.cend() = 0 '\000'
3: ing = {first = "Sal", second = 1}
(gdb) 
28      while (reader != line.cend()) {
1: reader = 0 '\000'
2: line.cend() = 0 '\000'
(gdb) 
29          string ing_name = "";
1: reader = 0 '\000'
2: line.cend() = 0 '\000'
3: ing = {first = "Sal", second = 1}

如您所见,由于迭代器和cend()相等,所以它不应该重新进入循环吗?

1 个答案:

答案 0 :(得分:1)

内部while递增,直到找到;cend为止,在两种情况下都继续。仅在下一次迭代时才停止,因为reader != line.cend()false,但这已经太迟了。

此外,您还必须首先检查自己是否末尾,然后才取消引用reader

    while (reader != line.cend() && *reader != ';') {
        ing_name += *reader;
        ++reader;
    }
    if (reader == line.cend()) break;