【问题标题】:Clarification on a basic behavior of cin in C++澄清 C++ 中 cin 的基本行为
【发布时间】:2015-08-08 12:26:25
【问题描述】:

我很好奇为什么cin 的行为方式如下。我想我可能有 对其行为的一些误解。

考虑一下这个简单的代码。此代码要求输入一些输入,所有这些都在最后一条语句中打印出来。

#include <iostream>
#include <string>
using namespace std;

int main(int argc, char** argv) {
  cout << "Please enter your input: " ;
  int a=3, b=87; // initialized to some random integers
  string s = "Mary" ; // initialized to a random string
  cin >> a ;
  cin >> b ;
  getline(cin,s);
  cout << "You entered the following " << a << "  " << b << "  " << s << endl;
  return 0;  
}

现在如果输入是12 34 cat,输出是12 34 cat 这是意料之中的。

但是,如果输入为 cat 23 dog,则输出为 0 87 Mary

这就是为什么我认为这是出乎意料的:

cin &gt;&gt; a 应该会失败,因为 cat 无法转换为整数。但是,a 被我认为是垃圾值所取代。

现在由于输入的第二个数字是整数 23,cin &gt;&gt; b 必须成功。然而这个操作似乎失败了,b 继续保持其原始值,这与a 发生的情况不同。

同样getline 未能将字符串&lt;space&gt;dog 放入字符串s 它继续保留其原始值Mary

我的问题如下。

  1. 某些cin 操作的失败是否要求全部失败 使用&gt;&gt; 运算符或getline 函数的后续cin 操作。

  2. 为什么第一次cin操作失败会改变a的值 而bs 的初始值没有改变?

【问题讨论】:

  • 将字符串输入读入 int 是错误的。检查cin 的状态,您会看到设置了失败标志。获取输入的正确方法是将所有内容作为字符串获取,然后尝试解析。另外,当你混合getline()cin 时要小心,因为cin 将换行符留在缓冲区中,getline 可能会错误地抓取。
  • 这个问题只有一个有趣的地方:为什么a变成0虽然输入失败了。 (由于失败状态,另一个被阻止)
  • 另外,看看this。也很有用。

标签: c++ cin


【解决方案1】:

某些cin操作的失败是否要求所有的失败 使用 >> 运算符或 getline 的后续 cin 操作 功能。

是的。直到您使用cin.clear() 清除错误。此外,当提取失败时,字符会留在缓冲区中,因此如果再次尝试读取相同的类型,则会再次失败。

为什么第一次cin操作失败改变了a的值 而b和s的初始值没有变化?

因为(自 C++11 起),它被定义为在从(以前的)有效流中提取失败的情况下将值更改为 0。在 C++11 之前,它会保持不变。对于处于错误状态的流,操作什么都不做,这就是bs 不变的原因。

【讨论】:

    【解决方案2】:
    1. 某些 cin 操作的失败是否会导致所有使用 >> 运算符或 getline 函数的后续 cin 操作失败。

    是的。您的代码希望完全按照该顺序读取输入值

    cin >> a ; // 1st integer value
    cin >> b ; // 2nd integer value
    getline(cin,s); // string value
    

    给它一个像

    这样的输入
    cat 23 dog
    

    在尝试读取第一个int 值时,导致在cin 上设置fail() 状态,并且以下operator&gt;&gt;() 调用都不会成功。


    cin &gt;&gt; a 应该会失败,因为 cat 无法转换为整数。但是,a 被我认为是垃圾值所取代。

    这不是垃圾值,但定义明确,请参阅下面的参考引用。

    现在由于输入的第二个数字是整数 23,cin &gt;&gt; b 必须成功。然而,这个操作似乎失败了,b 继续保留其原始值,这与 a 发生的情况不同。

    没有这个假设是错误的,正如提到的cin此时处于fail()状态,并且完全跳过解析进一步的输入。

    您必须在每次operator&gt;&gt;() 调用后调用clear(),以确保输入将被解析:

    cin >> a ; // 1st integer value
    cin.clear();
    cin >> b ; // 2nd integer value
    cin.clear();
    getline(cin,s); // string value
    

    1. 为什么第一次 cin 操作失败,a 的值改变了,而 b 和 s 的初始值没有变化?

    因为std::basic_istream::operator&gt;&gt;()的引用说

    "如果提取失败,则将零写入 value 并设置 failbit。如果提取导致 value 太大或太小而无法容纳 value,则写入 std::numeric_limits&lt;T&gt;::max()std::numeric_limits&lt;T&gt;::min() 并 @ 987654343@ 标志已设置。(C++11 起)"

    【讨论】:

    • 您的“解决方案”意味着cin 会跳过无效输入,但它不会。如果输入是“cat 23 dog”,那么 a=0, b=0,s="cat",我认为 OP 会发现它出乎意料。
    • @MooingDuck:实际上,s="cat 23 dog"
    • @MooingDuck 我试图改进我的答案来解释特定的行为。
    【解决方案3】:

    您应该使用@AndyG 所说的cin.good() 函数或速记符号if(cin) 来检查cin 对象的状态。变量a 的类型是int 那么你怎么能&你为什么要输入字符串?因此,它为变量 a 提供了意外的输出。

    【讨论】:

    • cin 隐式转换为bool,因此if(cin) 就足够了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-21
    • 2013-10-22
    • 1970-01-01
    • 2018-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多