cin与getline混合使用时的换行符陷阱

cin与getline混合使用时的换行符陷阱

Content #

需要读入的数据如下:

4
1 2 3 4
2 1 3
3 1 2 4
4 1 3
0
0

最开始的数字N,表示图的节点的个数,接下来若干行。每行的第1个数字表示起点u,后续的数字v表示从u开始到v有一条边。如果第1个数字为0,表示图的输入结束。

读取的代码如下:

int N;
while (cin >> N && N > 0) {
    string s;
    while (getline(cin, s)) {
        istringstream iss(s);
        int u;
        iss >> u;
        if (u == 0) break;
        int v;
        while (iss >> v) {
            //...
        }
    }
}

上面的代码存在换行符陷阱。读取N后,第1行的换行符还在,接下来调用 getline时,会得到空行,第1轮循环会马上结束,进入第2轮循环后会将第2行的第1个数字当作N读进来,导致数据读取错误。

解决方法是在读取N后,调用cin.ignore()来丢弃换行符:

int N;
while (cin >> N && N > 0) {
    cin.ignore(); //忽略当前的换行符,没有这一句,第一次调用getline会得到空行。
    //...
}

getline官方文档说明: When consuming whitespace-delimited input (e.g. int n; std::cin >> n;) any whitespace that follows, including a newline character, will be left on the input stream. Then when switching to line-oriented input, the first line retrieved with getline will be just that whitespace. In the likely case that this is unwanted behaviour, possible solutions include:

  1. An explicit extraneous initial call to getline.
  2. Removing consecutive whitespace with std::cin >> std::ws.
  3. Ignoring all leftover characters on the line of input with cin.ignore(std::numeric_limits<std::streamsize>::max(), ‘\n’);.

From #