使用 cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n')

Posted

技术标签:

【中文标题】使用 cin.ignore(std::numeric_limits<std::streamsize>::max(),\'\\n\')【英文标题】:using cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n')使用 cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n') 【发布时间】:2021-03-14 19:56:43 【问题描述】:

所以我最近在看一个关于字符串流的教程,并且有一个代码可以进行“数据验证”

    std::cout << "\n--- Data validation ------------------------------------" << std::endl;
    
    int value;
    std::string entry ;
    bool done = false;
    do 
        std::cout << "Please enter an integer: ";
        std::cin >> entry;
        std::istringstream validator entry;
        if (validator >> value) 
            done = true;
        else 
            std::cout << "Sorry, that's not an integer" << std::endl;
            
         // discards the input buffer
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
     while (!done);
    
    std::cout << "You entered the integer: " << value << std::endl;
    
    std::cout << std::endl;

他说 std::cin.ignore(std::numeric_limits<:streamsize>::max(),'\n') 的原因是忽略一切在流中直到新行,然后我复制了整个代码并从中删除了该行代码并运行它,输入他在测试运行中所做的相同数据(10(ok),frank(失败),.45 (失败),10 frank(ok)),它的工作方式相同,完全没有问题,所以我的问题是为什么它没有改变任何东西以及在什么情况下我可能需要使用 std::cin.ignore (std::numeric_limitsstd::streamsize::max(),'\n')?

【问题讨论】:

只是我还是本教程忘记使用std::cin.clear() 清除失败时的cin 状态位? @Casey cin 如果提供了任何输入,则不应失败,因为它只读取字符串。 @IlCapitano 啊。我忽略了那部分。 istringstream 也会在每次迭代时重新创建。 【参考方案1】:

std::cin &gt;&gt; entry 只读取到下一个空格字符(有关更多详细信息,请参阅cppreference),因此如果您要输入例如some thing 对于第一个提示,只会读取 some。在some 失败并重新进入循环后std::cin &gt;&gt; entry 将读取thing,无论您的下一个输入行是什么。运行您的程序时,您的控制台将如下所示(为了清楚起见,我添加了一些 cmets):

Please enter an integer: some thing // "some" is read in
Sorry, that's not an integer
Please enter an integer: 42  // "thing" is read in even though you entered "42"
Sorry, that's not an integer // fails because "thing" is not an integer

当提示用户时,你应该读入他们输入的所有内容,否则他们的一些输入可能会被留下并在以后错误地读入。

忽略输入的其余部分的一种方法是通过std::cin.ignore(...)。另一个是使用std::getline 获取输入,它将读取整行。使用std::getline 看起来像这样:

    std::cout << "\n--- Data validation ------------------------------------" << std::endl;
    
    int value;
    std::string entry ;
    bool done = false;
    do 
        std::cout << "Please enter an integer: ";
        std::getline(std::cin, entry);
        std::istringstream validator entry;
        if (validator >> value) 
            done = true;
        else 
            std::cout << "Sorry, that's not an integer" << std::endl;
            
         // no need to use cin.ignore
     while (!done);
    
    std::cout << "You entered the integer: " << value << std::endl;
    
    std::cout << std::endl;

【讨论】:

假设我输入“12 三”进入条目,当我将它传递给验证器并且验证器将它传递给“int value”时,“三”是什么 当我用getline替换std::cin时,它要求输入两次,为什么? @Padawan 将留下“三”,下次您要求输入时会读取它。 @Padawan 它要求输入两次,为什么?我刚试过,std::getlinestd::cin &gt;&gt; entry 都没有这个问题。您确定在使用std::getline 时删除了cin.ignore(...) opps,修复了它,但我很好奇,为什么在没有删除 cin.ignore 时它要求输入两次【参考方案2】:

仅当整数从cin 读取直接 时,以这种方式使用ignore() 才有意义,但代码是从cin 读取string,然后使用@ 987654325@ 来解析整数,因此 ignore() 是错误的,因为它将忽略 cin 上的 next 输入,而不是 failed 输入。

不仅如此,无论输入是成功还是失败,代码都会擦除cin 缓冲区。

代码应该看起来更像这样:

std::cout << "\n--- Data validation ------------------------------------" << std::endl;
    
int value;
do 
    std::cout << "Please enter an integer: ";
    if (std::cin >> value) 
        break;
    
            
    std::cout << "Sorry, that's not an integer" << std::endl;

    // clear the error state
    std::cin.clear();

    // discard all input up to the next line break
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

while (true);
    
std::cout << "You entered the integer: " << value << std::endl;
    
std::cout << std::endl;

或者这个:

std::cout << "\n--- Data validation ------------------------------------" << std::endl;
    
int value;
std::string entry;
do 
    std::cout << "Please enter an integer: ";
    if (std::cin >> entry) 
        std::istringstream validator entry;
        if (validator >> value) 
            break;
        
    
    else 
        std::cin.clear();
    

    std::cout << "Sorry, that's not an integer" << std::endl;            

    // uncomment this to discard all input up to the next line break, if desired...
    /*
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    */

while (true);
    
std::cout << "You entered the integer: " << value << std::endl;
    
std::cout << std::endl;

【讨论】:

std::cin &gt;&gt; entry 只读取到下一个空格字符,所以如果你要输入例如a b 它不会在下一个提示输入内容之前忽略 b @IlCapitano 如果a 无法转换为int,则原始代码将忽略后续ignore()b。我的第一个示例重现了相同的行为。第二个例子没有 您答案中的代码不会忽略b,这可能是个问题。 @IlCapitano 第一个示例忽略了b,就像原始代码一样 但第二个没有。如果您要为第一个提示输入asdf asdf,为第二个提示输入42,即使在第二个提示之后它也会失败,因为它没有忽略第一个提示中的第二个asdf

以上是关于使用 cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n')的主要内容,如果未能解决你的问题,请参考以下文章

[转]cin.clear()cin.sync()和cin.ignore()的用法

cpp►cin.ignore()函数——缓冲区

cin.clear() 和 cin.ignore() 不起作用[关闭]

使用 cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n')

PAT甲级1077 Kuchiguse (20 分)(cin.ignore()吃掉输入n以后的回车接着用getine(cin,s[i])输入N行字符串)

C++ --- getline 和 cin ignore () . 删除输出字符串中的第一个字符