简体   繁体   中英

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"

output : first string is: abc second string is: thrid string is:(strange characters)

Can you explain why the second cin didn't get input?

I expected that cin would read leading white spaces form the stream buffer and ignore them and read new string.

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

The relevant overload is number 3, but 3 just calls number 4 with the delimiter set to '\\n' and 4 says two important things,

Characters are extracted and stored until any of the following occurs:

  • count-1 characters have been stored
  • end of file condition occurs in the input sequence ( setstate(eofbit) is called)
  • the next available input character c equals delim , as determined by Traits::eq(c, delim) . This character is not extracted (unlike basic_istream::getline() )

If no characters were extracted, calls setstate(failbit) . In any case, if count>0, a null character (CharT() is stored in the next successive location of the array.

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. 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. 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. cin >> arr1 reads "abc" into arr1 . The "\\n" stays in the stream where cin.get(arr2, ArrSize) finds it. The get exit condition is immediately satisfied by the "\\n", so get stops and leaves the "\\n" in the stream. No characters were extracted. Fail bit is set and arr2 is null terminated.

cin>>arr3 subsequently fails because you can't read from a failed stream. Nothing is placed in arr3 , so when arr3 is printed, it is unterminated and << keeps printing until it finds a terminator. 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 . 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. 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 .

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. >> doesn't. On the other hand, get will read until it finds the end of the line, not just a single whitespace delimited token.

>> into a std::string will do the right thing and resize the string to fit the input. Generally prefer std::string to char arrays. And if you are using std::string prefer std::getline to get or istream 's getline .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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