【问题标题】:std::getline does not work inside a for-loopstd::getline 在 for 循环中不起作用
【发布时间】:2011-01-03 15:19:50
【问题描述】:

我正在尝试在一个字符串变量中收集用户的输入,该变量在指定的时间内接受空格。

由于通常的 cin >> str 不接受空格,所以我会使用 std::getline from

这是我的代码:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
    int n;
    cin >> n;
    for(int i = 0; i < n; i++)
    {
        string local;
        getline(cin, local); // This simply does not work. Just skipped without a reason.
        //............................
    }

    //............................
    return 0;
}

有什么想法吗?

【问题讨论】:

  • 很少有事情会无缘无故地失败。
  • 在 for 循环之前尝试以下操作: std::cout
  • 是的。 n 被正确读取。我为 n 输入了 2,它打印出“n: 2”
  • 我想我已经解决了你的问题。但是关于您的调试,您确实尝试了 2 以外的其他值,对吗?进入循环,它只是“跳过”第一个条目。

标签: c++ getline


【解决方案1】:

如果您输出存储在local 中的内容(顺便说一句,这是一个糟糕的变量名:P),您就会明白为什么会失败:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
    int n;
    cin >> n;
    for(int i = 0; i < n; i++)
    {
        string local;
        getline(cin, local);
        std::cout << "> " << local << std::endl;
    }

    //............................
    return 0;
}

您将看到它在输入您的号码后立即在&gt; 之后打印一个换行符。然后继续输入其余部分。

这是因为getline 为您提供了输入号码后剩下的空行。 (它会读取数字,但显然不会删除 \n,因此您会留下一个空白行。)您需要先删除任何剩余的空格:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
    int n;
    cin >> n;
    cin >> ws; // stream out any whitespace
    for(int i = 0; i < n; i++)
    {
        string local;
        getline(cin, local);
        std::cout << "> " << local << std::endl;
    }

    //............................
    return 0;
}

这按预期工作。

题外话,也许它只是为了手头的 sn-p,但如果你没有using namespace std;,代码往往可读。它违背了命名空间的目的。不过,我怀疑这只是为了在这里发帖。

【讨论】:

  • 我自己倾向于明确使用 std:: 命名空间前缀,但是在 cpp(不是 h)文件中使用 using 声明并没有错。
  • 或许在这样一个简单的例子中。不过,在命名空间std 中有很多 的东西。函数级是我将使用using 指令的最全局性。
【解决方案2】:

声明一个字符以在您输入数字后进入马车返回。char ws;int n;cin&gt;&gt;n;ws=cin.get(); 这样就可以解决问题了。

使用cin&gt;&gt;ws而不是ws=cin.get(),将使字符串的第一个字符位于变量ws中,而不是仅仅清除'\n'

【讨论】:

    【解决方案3】:

    这很简单。 你只需要在循环的末尾放一个 cin.get() 。

    【讨论】:

      【解决方案4】:

      你按回车了吗?如果没有得到线将不会返回任何内容,因为它正在等待行尾......

      【讨论】:

        【解决方案5】:

        我的猜测是你没有正确阅读n,所以它转换为零。由于 0 不小于 0,因此循环永远不会执行。

        我会添加一些工具:

        int n;
        cin >> n;
        std::cerr << "n was read as: " << n << "\n"; // <- added instrumentation
        for // ...
        

        【讨论】:

        • 没有。循环确实执行。我使用的是VC++ 2008,所以我可以通过逐行跟踪代码来调试。
        【解决方案6】:
        • n 是否从输入正确初始化?
        • 您似乎没有对 getline 进行任何操作。这是你想要的吗?
        • getline 返回一个 istream 引用。你把它丢在地上这件事重要吗?

        【讨论】:

        • 是的。我尝试打印它,n 已正确初始化。 --- 我在getline之后把代码剪掉了。
        【解决方案7】:

        你在哪个编译器上试过这个?我在 VC2008 上试过,效果很好。如果我在 g++ (GCC) 3.4.2 上编译了相同的代码。它不能正常工作。以下是在两个编译器中工作的版本。我的环境中没有最新的 g++ 编译器。

        int n;
        cin >> n;
        string local;
        getline(cin, local); // don't need this on VC2008. But need it on g++ 3.4.2. 
        for (int i = 0; i < n; i++)
        {
            getline(cin, local);
            cout << local;
        }
        

        【讨论】:

          【解决方案8】:

          重要的问题是“你对字符串做了什么,让你觉得输入被跳过了?”或者,更准确地说,“你为什么认为输入被跳过了?”

          如果您正在单步调试调试器,您是否在编译时进行了优化(允许重新排序指令)?我不认为这是你的问题,但有可能。

          我认为更有可能填充了字符串,但没有正确处理。例如,如果要将输入传递给旧的 C 函数(例如,atoi()),则需要提取 C 样式字符串(local.c_str())。

          【讨论】:

            【解决方案9】:

            你可以直接在使用分隔符的字符串中使用getline函数,如下:

            #include <iostream>
            using namespace std;
            int main()
            {
                string str;
                getline(cin,str,'#');
                getline(cin,str,'#');
            }
            

            您可以根据需要多次输入 str,但这里适用的一个条件是您需要传递 '#'(第三个参数)作为分隔符,即字符串将接受输入,直到按下 '#' 为止,无论换行符如何。

            【讨论】:

            • 同样可以插入循环中。
            【解决方案10】:

            getline(cin, local) 之前,只需添加if(i == 0) { cin.ignore(); }。这将从字符串中删除最后一个字符 (\n),这会导致此问题,并且仅在第一个循环中需要它。否则,它将在每次迭代时从字符串中删除最后一个字符。例如,

            i = 0 -> string
            i = 1 -> strin
            i = 2 -> stri
            

            等等。

            【讨论】:

              【解决方案11】:

              只需在循环前使用cin.sync()

              【讨论】:

              • 仅仅分发修复并没有帮助。请同时解释您的答案,以便对社区中的 OP 和其他人有益。背后的“原因”比“修复”更重要。
              【解决方案12】:

              只需在 getline 之前添加 cin.ignore() 即可完成工作

              #include <iostream>
              #include <vector>
              #include <string>
              #include <algorithm>
              using namespace std;
              int main()
              {
                  int n;
                  cin >> n;
                  for(int i = 0; i < n; i++)
                  {
                      string local;
                      cin.ignore();
                      getline(cin, local);
                  }
              
                  return 0;
              }
              

              【讨论】:

              • 这对 Pranav Rani 两个月前发布的答案有何改进?此外,他们提供了一个解释并且他们的答案有效。
              猜你喜欢
              • 1970-01-01
              • 2020-08-03
              • 2019-08-09
              • 1970-01-01
              • 2017-04-13
              • 2013-12-31
              • 2017-01-14
              • 2011-07-21
              • 2016-02-05
              相关资源
              最近更新 更多