简体   繁体   English

关于 C++ 输入行为

[英]About c++ input behavior

#include <iostream>

using namespace std;
const int ArrSize = 400;

int main()
{
   char arr1[ArrSize];
   char arr2[ArrSize];
   char arr3[ArrSize];

   cout << "enter the first string ";
   cin >> arr1;
   cout << "enter the second string ";
   cin.get(arr2, ArrSize);
   cout << "enter the thrid string ";
   cin>>arr3;


   cout << endl << endl;

   cout << "first string is: " << arr1 << "\n";
   cout << "second string is:  " << arr2 << "\n";
   cout << "thrid string is:  " << arr3 << "\n";

   return 0;
}

execution result is执行结果是

input : "abc\\n"输入:“abc\\n”

output : first string is: abc second string is: thrid string is:(strange characters)输出:第一个字符串是:abc 第二个字符串是:第三个字符串是:(奇怪的字符)

Can you explain why the second cin didn't get input?你能解释为什么第二个cin没有得到输入吗?

I expected that cin would read leading white spaces form the stream buffer and ignore them and read new string.我预计 cin 会从流缓冲区中读取前导空格并忽略它们并读取新字符串。

Let's start by adjusting the program to check for errors.让我们从调整程序以检查错误开始。

#include <iostream>

using namespace std;
const int ArrSize = 400;

int main()
{
   char arr1[ArrSize];
   char arr2[ArrSize];
   char arr3[ArrSize];

   cout << "enter the first string ";
   if (!(cin >> arr1))
   {
       cout << "Failed cin >> arr1\n";
   }
   cout << "enter the second string ";
   if (!cin.get(arr2, ArrSize))
   {
       cout << "Failed cin.get(arr2, ArrSize)\n";
   }
   cout << "enter the third string ";
   if (!(cin>>arr3))
   {
       cout << "Failed cin >> arr3\n";
   }
   cout << endl << endl;

   cout << "first string is: " << arr1 << "\n";
   cout << "second string is:  " << arr2 << "\n";
   cout << "third string is:  " << arr3 << "\n";

   return 0;
}

The results should be something like结果应该是这样的

enter the first string abc
enter the second string Failed cin.get(arr2, ArrSize)
enter the third string Failed cin >> arr3


first string is: abc
second string is:  
third string is:  <garbage here>

We can see that the second and third reads failed.我们可以看到第二次和第三次读取失败。 Why is that?这是为什么? To find out, we need to do a little reading.为了找出答案,我们需要做一点阅读。 Here's some high-quality documentation for std::istream::get这是std::istream::get的一些高质量文档

The relevant overload is number 3, but 3 just calls number 4 with the delimiter set to '\\n' and 4 says two important things,相关的重载是数字 3,但 3 只是调用数字 4 并将分隔符设置为'\\n'并且 4 表示两件重要的事情,

Characters are extracted and stored until any of the following occurs:字符将被提取并存储,直到发生以下任一情况:

  • count-1 characters have been stored已存储count-1字符
  • end of file condition occurs in the input sequence ( setstate(eofbit) is called)文件结束条件出现在输入序列中( setstate(eofbit)
  • the next available input character c equals delim , as determined by Traits::eq(c, delim) .下一个可用的输入字符 c 等于delim ,由Traits::eq(c, delim) This character is not extracted (unlike basic_istream::getline() )不提取此字符(与basic_istream::getline()

If no characters were extracted, calls setstate(failbit) .如果未提取字符,则调用setstate(failbit) In any case, if count>0, a null character (CharT() is stored in the next successive location of the array.在任何情况下,如果 count>0,空字符 (CharT() 将存储在数组的下一个连续位置。

So if you only get a newline, delim in this case, the output string arr2 is null terminated and the stream is placed into fail state because no characters were extracted from the stream, making the stream unreadable until the failure is acknowledged by clearing it.因此,如果您只得到一个换行符,在这种情况下 delim,则输出字符串arr2以 null 终止并且流被置于失败状态,因为没有从流中提取任何字符,这使得流无法读取,直到通过清除它来确认失败。 This is what we are seeing: an empty string and fail bit.这就是我们所看到的:空字符串和失败位。

Why is the string empty?为什么字符串是空的? Why didn't it prompt for input?为什么不提示输入? Because cin >> arr1 reads one whitespace-delimited token from the stream.因为cin >> arr1从流中读取一个以空格分隔的标记。 It will ignore all whitespace up to the start of the token, but it leaves the whitespace after the token in the stream.它将忽略直到令牌开头的所有空白,但它会在流中的令牌之后留下空白。

If you type abc and hit enter, "abc\\n" goes into the stream.如果您键入 abc 并按回车键,“abc\\n”将进入流。 cin >> arr1 reads "abc" into arr1 . cin >> arr1将 "abc" 读入arr1 The "\\n" stays in the stream where cin.get(arr2, ArrSize) finds it. "\\n" 保留在cin.get(arr2, ArrSize)找到它的流中。 The get exit condition is immediately satisfied by the "\\n", so get stops and leaves the "\\n" in the stream. "\\n" 立即满足get退出条件,因此get停止并将 "\\n" 留在流中。 No characters were extracted.没有提取字符。 Fail bit is set and arr2 is null terminated.设置失败位并且arr2为空终止。

cin>>arr3 subsequently fails because you can't read from a failed stream. cin>>arr3随后失败,因为您无法从失败的流中读取。 Nothing is placed in arr3 , so when arr3 is printed, it is unterminated and << keeps printing until it finds a terminator.没有被放置在arr3 ,所以当arr3被印刷,它是未终结和<<保持打印,直到它找到一个终止子。 This is the garbage characters, though technically anything can happen .这是垃圾字符,尽管从技术上讲任何事情都可能发生

The question does not specify what is to be done with data left over after cin >> arr1 .该问题没有具体说明如何处理cin >> arr1之后剩余的数据。 Common solutions are to remove everything up to and including the newline character from the stream with常见的解决方案是从流中删除包括换行符在内的所有内容

cin.ignore(numeric_limits<streamsize>::max(), '\n');

but if you want to use any characters left on the line for arr2 , you'll have to be trickier.但是,如果您想将行上剩余的任何字符用于arr2 ,则必须更加棘手。 For example, always read lines, build an istringstream out of the line, and then parse the istringstream as is done in option 2 of this answer .例如,始终读取行,从行中构建istringstream ,然后按照本答案的选项 2 中的方法解析istringstream

Side note: Reading into character arrays with >> is always risky because it will keep reading until whitespace is found.旁注:用>>读入字符数组总是有风险的,因为它会一直读到找到空格为止。 If the program reads the size of the array from the stream without finding whitepace, sucks to be you .如果程序从流中读取数组的大小而没有找到空白,那么你很糟糕 get knows to stop before its overflowed. get知道其溢出之前停止。 >> doesn't. >>没有。 On the other hand, get will read until it finds the end of the line, not just a single whitespace delimited token.另一方面, get将读取直到找到行尾,而不仅仅是单个空格分隔的标记。

>> into a std::string will do the right thing and resize the string to fit the input. >>进入std::string会做正确的事情并调整string大小以适应输入。 Generally prefer std::string to char arrays.通常更喜欢std::stringchar数组。 And if you are using std::string prefer std::getline to get or istream 's getline .如果你正在使用std::string喜欢std::getlinegetistreamgetline

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM