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

  • 配方索引(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()相等,因此它不应该重新进入循环,对吗?

    最佳答案

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

    另外,您必须首先检查您是否在结尾处,然后才取消引用reader:

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

    09-10 04:58
    查看更多