DaniWeb IT Discussion Community

DaniWeb IT Discussion Community (http://www.daniweb.com/forums/)
-   C++ (http://www.daniweb.com/forums/forum8.html)
-   -   It's cinfull! (http://www.daniweb.com/forums/thread66176.html)

murschech Jan 1st, 2007 11:00 pm
It's cinfull!
 
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 Jan 1st, 2007 11:02 pm
Re: It's cinfull!
 
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

Ravalon Jan 2nd, 2007 10:55 am
Re: It's cinfull!
 
Quote:

Originally Posted by murschech (Post 295744)
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.
Quote:

Originally Posted by murschech (Post 295744)
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. :)

~s.o.s~ Jan 2nd, 2007 2:46 pm
Re: It's cinfull!
 
Quote:

Originally Posted by Ravalon (Post 295942)
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).

WaltP Jan 2nd, 2007 2:58 pm
Re: It's cinfull!
 
Keep in mind, cin is the C++ version of C's scanf() and must be used appropriately. IMAO that means -- don't! ;)

~s.o.s~ Jan 2nd, 2007 3:04 pm
Re: It's cinfull!
 
Yes true, but if already used, why not make it a bit more er... robust...:D

Ancient Dragon Jan 2nd, 2007 3:11 pm
Re: It's cinfull!
 
Quote:

Originally Posted by WaltP (Post 296039)
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.

Ravalon Jan 2nd, 2007 3:11 pm
Re: It's cinfull!
 
Quote:

Originally Posted by ~s.o.s~ (Post 296033)
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. :)
Quote:

Originally Posted by WaltP (Post 296039)
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.

WaltP Jan 2nd, 2007 3:18 pm
Re: It's cinfull!
 
Quote:

Originally Posted by Ravalon (Post 296052)
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! ;)

Ravalon Jan 2nd, 2007 3:20 pm
Re: It's cinfull!
 
Quote:

Originally Posted by WaltP (Post 296061)
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?
Quote:

Originally Posted by WaltP (Post 296061)
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. ;)


All times are GMT -4. The time now is 6:44 pm.

Forum system based on vBulletin Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
©2003 - 2008 DaniWeb® LLC