getline() 不等待开关内部的输入.案例(C++)

getline() not waiting for input inside switch...case (C++)

本文关键字:输入 案例 C++ 开关 等待 getline 内部      更新时间:2023-10-16

我正在尝试使用 getline() 从用户那里获取输入。

以下代码工作正常。它等待用户键入文件名并将其存储在文件名中。

#include <iostream>
#include <string>
using namespace std;
string inputFile();
int main() 
{
    string fileName;
    cout << "Enter the name of the file including the path" << endl;            
    getline(cin, fileName);
    return 0;
}

但是,此代码不能正常工作。

#include <iostream>
#include <string>
using namespace std;
string inputFile();
int main() 
{
    int option;
    cout << "Enter option number" << endl;
    cin >> option;
    switch (option)
    {
        case 1:
        {
            string fileName;
            cout << "Enter the name of the file including the path" << endl;            
            getline(cin, fileName);
            break;
        }
        case 2:
            cout << "You chose option 2";
            break;
        case 3:
            cout << "You chose option 3";
            break;
        default:
            cout << "value unknown";
    }   
    return 0;
}

用户输入 1 后,程序进入开关...在这种情况下,将再次要求用户输入文件名。但是,这次程序不会等待响应。

为什么 getline() 不能像在开关外那样工作......案例结构?

任何建议将不胜感激。

cin在流中保留换行符(n)。 cin.ignore()提取和丢弃字符。它可用于冲洗cin,直到达到n

因此,解决方案是在第二次调用之前添加std::cin.ignore(std::numeric_limits<std::streamsize>::max(), 'n'); getline(cin, fileName);
还要添加cin.clear()以删除cin上的错误标志

例:

case 1:
    {
        std::string fileName;
        std::cout << "Enter the name of the file including the path" << std::endl; 
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), 'n');
        getline(std::cin, fileName);
        break;
    }

问题可能是,您正在通过>>读取整数变量中案例的编号。这样,由 Enter 键生成的换行符仍在缓冲区中。现在,getline 尝试从输入流中读取并立即收到换行符。而且因为它只在下一个换行符上读取,所以它会退出。

问题与switch语句无关!相反,它与混合格式化输入(使用 operator>>() )和未格式化输入(在本例中为 std::getline())有关:一旦字符与格式不匹配,格式化输入就会停止读取。读取整数时,一旦找到非数字,它就会停止。也就是说,在数字之后输入的任何换行符都将卡在流中,std::getline()会很乐意将此换行符作为停止输入的机会。

在格式化和未格式化输入之间切换时,您通常希望删除空格。例如,您可以使用

if (std::getline(std::cin >> std::ws, fileName)) { ... }

首先跳过任何空格,然后尝试读取fileName如果成功,则处理输入(始终需要检查输入是否成功)。

您正在单个流上混合格式化输入和行输入。这是一个坏主意,使用格式化的输入operator>>或行输入std::getline()永远不要在同一流上。

这基本上是因为处理空格的方式。在这种情况下,当您读取选项时,您将在输入上留下一个n字符。

cin >> option;

这将读取选项,但在输入流(包括n字符)上保留选项后(整数之后)的任何内容。因此,std::getline() 的下一次使用只是读取n字符(这可能给你零个字符)。

交互式用户输入是基于行的。
特别是因为std::cin流是缓冲的(因此在您点击回车之前不会刷新)。

因此,当我读取交互式用户的输入时,我总是一次阅读一行文本。然后解析此行以获取我正在寻找的内容。

 std::string  optionLine;
 std::getline(std::cin, optionLine);
 int option = boost::lexical_cast<int>(optionLine);

注意:您不需要boost::lexical_cast,您可以使用std::stringstream和另一个变量实现相同的效果。

 // A simple alternative to boost::lexical_cast
 // Not quite as pedantic as above but you can add more tests as required.
 std::stringstream optionLineStream(optionLine);
 int option;
 if (optionLineStream >> option)
 {
     // reading the option worked.
 }
一次

读取一行,然后解析输入还有一个优点,即您永远不会将输入置于错误状态并需要重置它(任何错误状态都设置在中间std::stringstream对象上)。因此,修复错误的用户输入更容易。