【问题标题】:How continuous cin input works in C++连续 cin 输入在 C++ 中的工作原理
【发布时间】:2018-04-13 02:58:40
【问题描述】:

很抱歉,我无法为这个问题找到更好的标题。我正在关注 Stroustrup 的编程:使用 C++ 的原则和实践。这个示例代码引起了我的注意。我的问题是,cin 如何在一个单词中识别两种不同的类型,例如 200.40i(200.40 double 和 i char)?我的意思是,它不应该期待至少一个空格分隔的输入吗?

int main()
{
    constexpr double cm_per_inch = 2.54;
    double length = 1;
    char unit = 0;
    cout << "Please enter a length followed by a unit (c or i):\n";
    cin >> length >> unit;
    if (unit == 'i')
        cout << length << "in == " << cm_per_inch*length << "cm\n";
    else
        cout << length << "cm == " << length/cm_per_inch << "in\n";
}

如果我只是运行程序并输入:200.40i 工作正常,同样适用于:200.40 i 和:200.40 \n i。

【问题讨论】:

  • i 不能以&gt;&gt; 将解析的double 的任何表示形式出现在那里,因此它知道double 在那里结束。不过,它真的很脆弱——尝试用e 替换i。流输入需要大量的错误检查。

标签: c++


【解决方案1】:

这是对格式化输入提取操作符(又名&gt;&gt;)内部工作的过度简化,用于解释您观察到的输入行为。这就是&gt;&gt; 的工作原理:

第 1 步:跳过输入流中的所有空格。

第 2 步:将输入流的下一部分转换为 &gt;&gt; 将要使用的任何数据类型。 仅从输入流中提取已转换的输入。

这两个步骤针对每个&gt;&gt; 运算符执行。正如我所说,这是过于简单化了。还有其他事情正在发生,例如用于异常处理的哨兵对象,这与此处无关。

重要的是&gt;&gt; 在看到提取后的空格时不会“停止”。这就是 &gt;&gt; 在介绍性 C++ 文本中经常被解释的方式,但它并不完全正确。 &gt;&gt; 在完成提取所提取的内容后立即停止,并且不 提取其后面的内容。现在,在“提取的任何内容”之后,您通常会有额外的空格。没关系。格式化输入提取运算符将在该点停止。但重要的是它不会提取空白。这将由后续 &gt;&gt; 提取(如果有的话)处理。

而且它不一定是空格。它可能是任何不再被解析为被提取的东西。所以,在你的情况下:

cin >> length >> unit;

length 是 double。 unit 是 char。您的输入是:

200.40i

第一个 &gt;&gt; 仅提取“200.40”。字符 i 不可能属于 double 值,因此提取会在该点停止,并且 i 被提取。所以第一个&gt;&gt; 唯一能从中提取出来的东西。然后,第二个&gt;&gt; 提取唯一的“i”字符。

格式化的提取操作符,出于所有实际目的,总是uses peek() to look at the next character in the input stream,以便决定是否将其提取为从输入流中提取的内容的一部分。如果它看起来不错,那么它就会被吞噬。

现在,如果有一些空格:

200.40 i

第一个&gt;&gt; 像以前一样从中取出double,然后停止,但它不提取空间。 2nd &gt;&gt; 跳过空格作为其“步骤 1”的一部分,然后提取 char。

所以,你看,&gt;&gt; 格式化的提取运算符丢弃空格,而不是 在 它提取它提取的任何内容,而是 在。

其他几点说明:

  • 如果&gt;&gt; 提取到std::string,这将提取除空格之外的任何内容,因此此处停止提取的唯一内容是尾随空格。但是后面的空格本身仍然没有被提取,而只是被下一个&gt;&gt; 运算符提取。

  • 如果在这种情况下,&gt;&gt; 提取到一个孤独的char,则这个char 只能包含一个字符,所以在这种情况下,这就是要提取的全部内容。

【讨论】:

    【解决方案2】:

    http://www.learncpp.com/cpp-tutorial/5-10-stdcin-extraction-and-dealing-with-invalid-text-input/

    当使用抽取运算符时,会发生以下过​​程:

    1. 如果输入缓冲区中已有数据,则使用该数据进行提取。
    2. 如果输入缓冲区不包含数据,则要求用户输入数据以进行提取(大多数情况下都是这种情况)。当用户按下回车键时,一个“\n”字符将被放置在输入缓冲区中。
    3. operator>> 从输入缓冲区中提取尽可能多的数据到变量中(忽略任何前导空白字符,例如空格、制表符或“\n”)。
    4. 任何无法提取的数据都会留在输入缓冲区中以供下次提取。

    因此,在您的示例中,200.40 将被提取并转换为双精度。由于输入缓冲区仍然有i,它将被提取到字符中。

    【讨论】:

      【解决方案3】:

      要了解它的工作原理,您需要了解一点面向对象编程的知识。
      在 C++ 中,cin 是一个对象。

      但你可能会问,什么是对象?
      基本上,对象是一种可以用各种运算符操作的数据结构:
      例如+-*/%&lt;&lt;&gt;&gt;等
      C++ 中的两种类型的对象是:built-in type 和 user-defined type。

      无论您是否知道,您一直在 C++ 中使用对象!
      例如,您的变量length 是一个内置类型double 的对象。

      现在你可以用length 做什么?
      那么它支持+-*/等等。
      这是一种非常直观的类型。

      现在cin 呢?
      cin 是用户定义类型istream 的对象。
      而且我们知道它支持运算符&gt;&gt;,也就是所谓的按位右移运算符。
      此运算符(在cin 的情况下)获取给定的输入数据并将其吐出(转移)到您的变量中。

      此运算符的一个特点是您可以链接多个变量:
      例如cin &gt;&gt; variable1 &gt;&gt; variable2 &gt;&gt; variable3;
      就像在 double 类型的对象中使用运算符 + 一样:
      例如length + 1 + 2 + 3;

      但是链中的每个变量都必须用&gt;&gt; 运算符分隔。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-02
        • 1970-01-01
        • 2013-11-21
        • 1970-01-01
        • 2011-08-03
        • 1970-01-01
        相关资源
        最近更新 更多