【问题标题】:cin.getline not executing c++cin.getline 不执行 C++
【发布时间】:2011-10-12 08:25:23
【问题描述】:

由于某些奇怪的原因,当我将输入行 cin.getline(oneLine, 80); 放入此 else if 块时,它被完全忽略了。我不明白为什么,因为当我将它移到程序中的其他位置时,它可以工作。

     else if (choice == "user-id")
     {   
        cout << endl << "Enter a full name e.g. John Smith ";
        char oneLine[80];
        cin.getline(oneLine, 80);
        cout << oneLine;                        
     }

这是我的其余代码。我是 C++ 新手,所以我确信我的许多约定充其量可能是有问题的。

int main( )
{
    while (true)
        {

        int pause;
        string choice = "proceed";
        string nameGiven;
        string userIdGiven;
        string result;
        using namespace std ;

        while ((choice != "name") && (choice != "user-id"))
        {   
            cout << "Would you like to search for a name or user-id? ";
            cin >> choice;
            if ((choice != "name") && (choice != "user-id"))
               cout <<"Please enter a valid choice (name or user-id)" << endl;
        }

        if (choice == "name") 
        {
            string dataType = "int";
            while (true)
            {    
                cout << endl << "Enter a valid user id (4 digit maximum) ";
                cin >> userIdGiven;

                if (valid(userIdGiven))
                   break;
                else
                    cout << endl << "Not a valid number. " << endl;
                   continue;
             }
             result = findData(userIdGiven, dataType);
             cout << "name: " << result;

         }

         else if (choice == "user-id")
         {   
            cout << endl << "Enter a full name e.g. John Smith ";
            char oneLine[80];
            std::getline(oneLine, 80);
            cout << oneLine;                       
         }

        string ans;
        cout << endl << "Would you like to play again? (yes/no) " << endl;
        cin >> ans;
        if ( (ans == "yes") || (ans == "Yes") || (ans == "Y") || (ans == "y") )
             continue;
          else
              break;

        cin >> pause;
     } 
return 0;
}

【问题讨论】:

  • 是否忽略了整个 else if 块?
  • std::getlinestd::string 一起使用比将std::istream::getlinechar[N] 一起使用要容易得多。
  • @jesus:不是,不是。第一行打印然后它只是忽略其余的并继续!快把我逼疯了
  • @KillianDS :通常这就是您想要做的,但是对于 std::string , == 运算符被重载,以便它在 C++ 中工作。此外,您确定一旦到达该语句就消耗了所有输入,因为 getline 将尝试使用任何存在的输入(如果您还没有)。
  • 我没有完全记住这一点,但是是否存在一些问题,您需要在 cin 之后刷新缓冲区,或者下次输入时将上一个输入中的换行符用作输入叫它?

标签: c++ inputstream getline


【解决方案1】:

FWIW,我在看到更新之前就猜到了问题会是什么(这很愚蠢),并对其他猜测自嘲一笑(尽管即使他们错过了 OP 的问题,它们也能提出很好的观点)。

这行代码工作正常,正如宣传的那样。它不会按你想要的方式工作。

当您从 std::cin 读取时,不会暂停程序并等待输入。导致暂停的原因是读取操作缺少足够的输入数据。

一次输入一行。请记住,控制台窗口也是一个程序。它负责将用户的按键转换为文本字符(实际上是字节),处理诸如退格键之类的事情,并将它们全部收集成行。

假设您使用operator&gt;&gt; 阅读int,然后使用getline 阅读一行。在用户按下 Return 键之前,该程序不会看到 int,因为这会触发控制台向您的程序提供一行输入。

operator&gt;&gt; 将跳过前导空格,读取整数,并单独保留尾随空格。换行符是空格。输入中有一个换行符(显然在行尾)。

getline()不会跳过任何前导空格,并一直阅读到下一个换行符。下一个字符恰好是换行符,因此getline() 愉快地读取了一个空行,然后程序继续执行。

那么你如何解决这个问题?如果您正在读取来自cin 的所有输入,您可能希望程序在每次执行读取操作时暂停。做到这一点的方法是确保此时永远没有任何可用数据,而做到这一点的方法是读取所有可用的数据 - 即整行 - 每次您阅读某些内容时。

因此,请始终从cin 中读取整行。 正如 wilx 所述,请为此使用免费功能 std::getline。不要使用流的.getline 成员函数。使用std::string 表示文本字符串。这就是它的用途。这将使您的生活变得更加轻松。这也意味着,如果您期望一个整数并且用户键入“76 个长号”,您就可以摆脱“长号”数据(并且可以决定 不管你是想把它扔掉,还是对用户大喊大叫,让他重新输入一个数字,而没有任何有趣的评论)。

然后呢?你只有一个字符串,你可能想要一个 int。幸运的是,有一个简单的解决方案。我们可以使用标准库类std::stringstream 将字符串视为流数据的来源。我们只是从字符串构造一个字符串流,然后像std::cin 一样使用它——即我们可以使用operator&gt;&gt; 从它读取,检查流状态以查看读取是否成功,等等。

正如 sbi 所指出的,始终检查读取是否成功!如果您尝试读取 int 并且流包含诸如“hi mom”之类的文本,那么 (a) int 变量将不会被更改(因此,如果它未初始化,它仍然未初始化,处于非常危险的状态),并且 (b) 流将进入“失败”状态并且将 在清除之前不要继续阅读,并且(c)即使您清除它,数据仍然存在,如果您不小心可能会触发无限循环。

幸运的是,有了单独的stringstream,我们避免了各种复杂情况。如果读取失败,那么所有这些事情都会发生在stringstream 对象上——而不是std::cingetline 操作将始终在 std::cin 上成功,除非用户明确指示文件结束(Linux 上的 control-D 字符,或 Windows 上的 control-Z)。我们可以轻松检查stringstream 是否处于失败状态,循环并创建另一个 - 旧的会自动清理。

我们甚至可以创建一个辅助函数,例如:

template <typename T>
// Attempt to read into to_read, and return whether successful.
bool read_primitive_from_input(std::istream& input, T& to_read) {
    std::string line;
    std::getline(std::cin, line);
    std::istringstream iss(line);
    return iss >> to_read;
}

std::stringstream 由标准库头文件&lt;sstream&gt; 提供。 std::string当然来自&lt;string&gt;

【讨论】:

  • 实际上,我误读了代码并假设您正在阅读 ints 和 std::cin 以及整行。但是,使用operator&gt;&gt; 阅读单词的逻辑基本相同。顺便说一句,使用 operator&gt;&gt;std::string 对象将读取一个单词,就像使用 char[] 缓冲区一样 - 除非您不必担心缓冲区大小或指针有效性等。
【解决方案2】:

twsaef 的评论基本上是正确的...您正在将一个字符串流式传输到选择中,这会消耗字符直到但不包括下一个空白字符 - 您可能正在输入换行符来终止您的输入,所以它留在缓冲区中.然后你使用 getline 来查看换行符并读取一个空字符串。

最简单的解决方案是调用getline() 来读取初始字符串,然后检查选项是“name\n”还是“user-id\n”。更好 - 编写一个“trim”函数以在比较之前从行中删除空格(提升字符串库已经有了这个)。否则,您可以使用来自std::cin 的读取和忽略字符,直到获得“\n”。或者甚至读取一行然后放入一个字符串流并从那里读取一个字符串......很多选择。

还有,请检查您的直播状态!尝试使用:

if (std::cin >> x)
    // x was parsed from stream... use it
else
    // print an error so you know where things failed!

【讨论】:

    【解决方案3】:

    您的 std::cin 对象在之前的输入操作中处于错误状态 (std::cin.good() == false)。例如,您可能试图读取一个数字,但输入缓冲区中只有非数字字符。

    在继续使用 std::istream 之前始终检查输入是否成功。

    注意: 不要使用在char* 上运行的旧输入函数,因为它们比在@ 上运行的新输入函数更复杂且更不安全987654325@。在您的情况下,请使用std::getline(std::istream&amp;, std::string&amp;, char = '\n')

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-08
      • 2015-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多