In using "cin" for getting input I have about a 99% success rate. In the remaining
1% of cases the program does not pause for input. What causes this and how does one fix it?

In ancient times when we programmed in C rather than C++ the same problem occurred
occasionally if "getc" or "getchar" was used for input. You could solve the problem by
putting the line "flushall()" before the input statement but that doesn't seem to
work with cin.

I ought to give an example but the only ones I have are in longish programs that I
wouldn't ask anyone to read.

Ancient Dragon commented: clever thread title +10

Recommended Answers

All 17 Replies

same problem as in old days. when you enter a number and press <Enter> cin does not remove the "\n" from the keyboard -- you have to do that

int x;
cin >> x;
cin.ignore(); // remove '\n' key

In using "cin" for getting input I have about a 99% success rate. In the remaining 1% of cases the program does not pause for input. What causes this and how does one fix it?

You are probably mixing formatted and unformatted input. Formatted input treats whitespace differently than unformatted input, and if a formatted operation leaves '\n' in the stream, the unformatted operation will fail to do what you want depending on your program's logic. You fix it either by flushing the input stream at the right time or by not mixing formatted and unformatted input on the same stream.

In ancient times when we programmed in C rather than C++ the same problem occurred occasionally if "getc" or "getchar" was used for input. You could solve the problem by putting the line "flushall()" before the input statement but that doesn't seem to work with cin.

flushall() is not a standard function so you cannot expect it to work. You use cin.ignore() in C++.

#include <iostream>
#include <limits>

int main()
{
  using namespace std;

  // Create the problem by leaving a '\n' in the stream
  char letter = 0;

  cout << "Please type one letter: ";
  cin.get( letter );
  cout << "The next character is: " << (int)cin.get() << '\n';

  // Create the same problem and fix it with cin.ignore()
  cout << "Please type one letter: ";
  cin.get( letter );

  // Ignore the maximum value of the streamsize type or until '\n' is ignored
  cin.ignore( numeric_limits<streamsize>::max(), '\n' );

  // Now the cin.get() call will block because the stream is empty
  cout << "The next character is: " << (int)cin.get() << '\n';

  return 0;
}

The best fix is to avoid the problem completely by not mixing formatted and unformatted input. You always use unformatted input and then include logic to do the formatting. With C we did it using fgets and sscanf or something like that. With C++ you do it with getline and stringstream or something comparable.

#include <iostream>
#include <limits>
#include <sstream>
#include <stdexcept>
#include <string>

namespace Raye {
  using namespace std;

  template <class T, class U>
  T CType( U src )
  {
    stringstream ss;
    T dst;

    if ( !( ss << src ) )
      throw runtime_error( "CType: stringize error" );
    
    if ( !( ss >> dst ) )
      throw runtime_error( "CType: invalid conversion" );

    return dst;
  }

  template <class T>
  T GetType( istream& is )
  {
    string s;

    if ( !getline( is, s ) )
      throw runtime_error( "GetInt: input failure" );

    return CType<T>( s );
  }
}

int main()
{
  using namespace std;

  int age;
  string name;

  // Create the problem as an example
  cout << "Please type your age: ";
  cin >> age;
  cout << "Please type your name: ";
  getline( cin, name );
  cout << name << " is " << age << " years old\n";

  // Clean up the stream for an accurate test
  cin.ignore( numeric_limits<streamsize>::max(), '\n' );

  // Eliminate the problem with GetType
  cout << "Please type your age: ";
  age = Raye::GetType<int>( cin );
  cout << "Please type your name: ";
  getline( cin, name );
  cout << name << " is " << age << " years old\n";

  return 0;
}

It is more work at first but the result is more robust. :)

commented: You obviously spent time typing this up... -joeprogrammer +4

flushall() is not a standard function so you cannot expect it to work. You use cin.ignore() in C++.

#include <iostream>
#include <limits>

int main()
{
  using namespace std;

  char letter = 0;
  cout << "Please type one letter: ";
  cin.get( letter );
  cout << "The next character is: " << (int)cin.get() << '\n';

  cout << "Please type one letter: ";
  cin.get( letter );

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

   cout << "The next character is: " << (int)cin.get() << '\n';

  return 0;
}

Though it would be really better if cin.clear( ) was placed before the call to cin.ignore( ) to deal with corrupted input stream along with the stray characters or junk in it. (eg. user enters a float in place of character).

Keep in mind, cin is the C++ version of C's scanf() and must be used appropriately. IMAO that means -- don't! ;)

Yes true, but if already used, why not make it a bit more er... robust...:D

Keep in mind, cin is the C++ version of C's scanf() and must be used appropriately. IMAO that means -- don't! ;)

Don't you mean >> operator is like c's scanf() ? cin by itself is similar to c's stdin file pointer.

Though it would be really better if cin.clear( ) was placed before the call to cin.ignore( ) to deal with corrupted input stream along with the stray characters or junk in it. (eg. user enters a float in place of character).

Well, in real code I would check the error state of cin and deal with legitimate problems long before trying to do cin.ignore(). But real code is harder to read and has lots of extras that hide the point I'm trying to make. :)

Keep in mind, cin is the C++ version of C's scanf() and must be used appropriately. IMAO that means -- don't! ;)

Not to be nitpicky, but cin is the C++ version of C's stdin. The overloaded >> operator is the C++ version of scanf.

Not to be nitpicky, but cin is the C++ version of C's stdin. The overloaded >> operator is the C++ version of scanf.

So don't be nitpicky :p

Yes, you guys are right. So I change my statement:

Keep in mind, cin << is the C++ version of C's scanf() and must be used appropriately. IMAO that means -- don't! ;)

So don't be nitpicky :p

But then I couldn't be nitpicky. :sad: Isn't nitpicking supposed to be one of life's true joys or something?

Keep in mind, cin << is the C++ version of C's scanf() and must be used appropriately. IMAO that means -- don't! ;)

cin >> , you mean. ;)

I am sure you meant cin >> I wonder what you had just before logging in....;)

Keep in mind, cin >> is the C++ version of C's scanf() and must be used appropriately. IMAO that means -- don't! ;)

But I don't change my stmt:
Yes true, but if already used, why not make it a bit more er... robust...:D

[edit]Cripes, this Ravalon guy is everywhere...;)[/edit]

Whatever!

same problem as in old days. when you enter a number and press <Enter> cin does not remove the "\n" from the keyboard -- you have to do that

int x;
cin >> x;
cin.ignore(); // remove '\n' key

Thanks for the explanation. I still have a question. Now I can't see why the
little program below works.

#include <iostream>
using namespace std;

main()
{   int x,y;
    cout << "Enter x: ";
    cin >> x;
    cout << "Enter y: ";
    cin >> y;
    cout << "I read two values, " << x << " and "<< y << '\n';
}

The first use of "cin" reads x but, according to your note, leaves a newline
character in the input buffer. The second call to "cin" should then see this
newline characteras the first character in the input buffer and therefore
stop reading. But it doesn't. What is the error in my reasoning?

The first use of "cin" reads x but, according to your note, leaves a newline character in the input buffer. The second call to "cin" should then see this newline characteras the first character in the input buffer and therefore stop reading. But it doesn't. What is the error in my reasoning?

There's no error in your reasoning, and that's why this is probably the most irritating problem for people learning C/C++. Think of cin>> as that bloke who works great by himself but messes things up in a team. cin >> x does leave a newline character in the stream, but the first thing cin >> y does is remove any leading whitespace. The newline is thusly ignored without your intervention. Other input methods don't remove leading whitespace, and that's where the problem lies.

>>Think of cin>> as that bloke who works great by himself but messes things up in a team.

I like that analagy. Well done!

There's no error in your reasoning, and that's why this is probably the most irritating problem for people learning C/C++. Think of cin>> as that bloke who works great by himself but messes things up in a team. cin >> x does leave a newline character in the stream, but the first thing cin >> y does is remove any leading whitespace. The newline is thusly ignored without your intervention. Other input methods don't remove leading whitespace, and that's where the problem lies.

So what's a poor programmer to do? Since it's apparently not possinble to know when this troubelsome newline char will appear would you recommend that cin.ignore() be used before any call to cin >>? If cin worked in a particular program with a particular set of input data without the ignore statement would it be safe to assume that it will work in the same program when it's run with different data?

So what's a poor programmer to do?

Maybe resort to more robust methods of accepting input.
Just to rehash Mr. Ravalon's robust attempt at trying to solve the problem:

#include <iostream>
#include <limits>
#include <sstream>
#include <stdexcept>
#include <string>

namespace Raye {
  using namespace std;

  template <class T, class U>
  T CType( U src )
  {
    stringstream ss;
    T dst;

    if ( !( ss << src ) )
      throw runtime_error( "CType: stringize error" );
    
    if ( !( ss >> dst ) )
      throw runtime_error( "CType: invalid conversion" );

    return dst;
  }

  template <class T>
  T GetType( istream& is )
  {
    string s;

    if ( !getline( is, s ) )
      throw runtime_error( "GetInt: input failure" );

    return CType<T>( s );
  }
}

int main()
{
  using namespace std;

  int age;
  string name;

  // Create the problem as an example
  cout << "Please type your age: ";
  cin >> age;
  cout << "Please type your name: ";
  getline( cin, name );
  cout << name << " is " << age << " years old\n";

  // Clean up the stream for an accurate test
  cin.ignore( numeric_limits<streamsize>::max(), '\n' );

  // Eliminate the problem with GetType
  cout << "Please type your age: ";
  age = Raye::GetType<int>( cin );
  cout << "Please type your name: ";
  getline( cin, name );
  cout << name << " is " << age << " years old\n";

  return 0;
}

Since it's apparently not possinble to know when this troubelsome newline char will appear would you recommend that cin.ignore() be used before any call to cin >>?

The combination of cin.clear( ) along with cin.ignore( ) seems to work in most cases but the above given solution appears to be more robust.

If cin worked in a particular program with a particular set of input data without the ignore statement would it be safe to assume that it will work in the same program when it's run with different data?

No, its never safe to assume anything as far as C++ is concerned since it hates people who take it for granted..;)

BTW the current software development senario is such that the process of getting input from console has been limited to programs which accept command line parameters. Nowadays its more like GUI everywhere, but still getting your concepts cleared on how actually the standard input stream of C++ works is a good thing.

So what's a poor programmer to do?

'Don't use cin>> ' seems to be the common consensus. :) Separate parsing from I/O so that you only work with strings when reading or writing. The code ends up being longer and more complicated, but it's easier to predict stream behaviour when it's only doing one thing at a time.

Since it's apparently not possinble to know when this troubelsome newline char will appear would you recommend that cin.ignore() be used before any call to cin >>?

cin.ignore() for that purpose is a workaround, and if you're doing the right thing to begin with you shouldn't need it to clean up your mess. ;)

If cin worked in a particular program with a particular set of input data without the ignore statement would it be safe to assume that it will work in the same program when it's run with different data?

Assume nothing and you'll never be disappointed. ;)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.