连续 cin 输入在C++中的工作原理

How continuous cin input works in C++

本文关键字:工作 C++ cin 输入 连续      更新时间:2023-10-16

很抱歉,我找不到更好的标题来回答这个问题。我正在遵循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 << "cmn";
else
cout << length << "cm == " << length/cm_per_inch << "inn";
}

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

这是对格式化输入提取运算符(又名)内部工作的严重过度简化。>>用于解释您观察到的输入行为。这是>>的工作原理:

第 1 步:跳过输入流中的任何空格。

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

对每个>>运算符执行这两个步骤。正如我所说,这过于简单化了。还有其他事情正在发生,例如用于异常处理的哨兵对象,这些事情在这里无关紧要。

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

而且它不必是空格。它可以是不再解析为提取的任何内容的任何内容。因此,在您的情况下:

cin >> length >> unit;

length是一个double.unit是一个char.您的输入是:

200.40i

>>仅提取"200.40"。字符i不可能属于double值,因此提取在该点停止,并且不会提取i。这样,第一个>>从中拉出的唯一东西。然后,第 2>>提取单独的"i"字符。

出于所有实际目的,格式化提取运算符始终使用 peek() 查看输入流中的下一个字符,以决定是否将其提取为从输入流中提取的任何内容的一部分。如果它看起来不错,那么它就会被吞噬。

现在,如果有一些空格:

200.40 i

第一个>>像以前一样将double从中取出并停止,但它不会提取空间。第二个>>跳过空格作为其"步骤 1"的一部分,然后提取char

因此,您会看到,>>格式的提取运算符不是在提取提取的任何内容之后丢弃空格,而是在提取之前丢弃空格。

其他一些注意事项:

  • 如果>>提取到一个std::string,这将提取除空格以外的任何内容,因此这里唯一停止提取的是尾随空格。但是尾随空格本身仍然没有被提取,而只能由下一个>>运算符提取。

  • 如果像本例一样,>>提取到一个孤独的char,这个char只能容纳一个角色,所以在这种情况下,这就是所有将被提取的内容。

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

使用提取运算符时,将执行以下过程:

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

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

为了理解它是如何工作的,你需要一点面向对象编程的知识。
在C++cin是一个对象。

但你可能会问,什么是物体?
基本上,对象是一种数据结构,可以用各种运算符进行操作:
例如+-*/%<<>>等。
C++中的两种类型的对象是:built-in typeuser-defined type

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

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

现在cin呢?
cin是用户定义类型istream的对象。
我们知道它支持运算符>>,称为按位右移运算符。
这个运算符(在cin的情况下)获取给定的输入数据并将其吐出(移动)到变量中。

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

但是链中的每个变量都必须由>>运算符分隔。