Validating input

K

Kavya

I saw these two ways for validating input

First Way
--------------
#include <iostream>
#include <limits>

using namespace std;

int main() {
int number = 0;
cout << "Enter an integer: ";
cin >> number;
cin.ignore(numeric_limits<int>::max(), '\n');

if (!cin || cin.gcount() != 1)
cout << "Not a numeric value.";
else
cout << "Your entered number: " << number;
return 0;
}

Second Way
--------------------
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
int main() {

int inum,count=0;
cout<<"Enter integers, <Return> after each, <Ctrl>Z to
finish"<<endl;
while(cin>>inum,cin.good()) {
cout<<"Number "<<++count<<":"<<inum<<endl;
}
return 0;
}

Which of them is better? I find 2nd method easier than the other. Won't
second method be sufficient?
 
S

Salt_Peter

Kavya said:
I saw these two ways for validating input

First Way
--------------
#include <iostream>
#include <limits>

using namespace std;

int main() {
int number = 0;
cout << "Enter an integer: ";
cin >> number;
cin.ignore(numeric_limits<int>::max(), '\n');

if (!cin || cin.gcount() != 1)
cout << "Not a numeric value.";
else
cout << "Your entered number: " << number;
return 0;
}

Second Way
--------------------
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
int main() {

int inum,count=0;
cout<<"Enter integers, <Return> after each, <Ctrl>Z to
finish"<<endl;
while(cin>>inum,cin.good()) {
cout<<"Number "<<++count<<":"<<inum<<endl;
}
return 0;
}

Which of them is better? I find 2nd method easier than the other. Won't
second method be sufficient?

How about:

#include <iostream>
#include <ostream>
#include <vector>
#include <iterator>
#include <limits>
#include <typeinfo>
#include <stdexcept>

// may need a specialization to capture std::string
template < typename T >
void parseInput( std::vector< T >& r_vt ) {
std::cout << "Enter a series of " << typeid(T).name();
std::cout << " (any char to terminate)" << std::endl;
T t;
while ( std::cin >> t ) {
if ( !std::cin.good() ) {
throw std::runtime_error( "reading input stream." );
}
r_vt.push_back( t );
}
std::cin.clear();
std::cin.ignore(std::numeric_limits< int >::max(), '\n');
}

// op<< for std::vector< T >
template< typename T >
std::eek:stream&
operator<<( std::eek:stream& os,
const std::vector< T >& r_vt )
{
std::copy( r_vt.begin(),
r_vt.end(),
std::eek:stream_iterator< T >( os, "\n" ) );
return os;
}

int main() {
try {
std::vector< int > vn;
parseInput( vn );
std::cout << vn;

std::vector< double > vd;
parseInput( vd );
std::cout << vd;

} catch ( std::exception & r_e ) {
std::cerr << "\nError: " << r_e.what();
std::cerr << std::endl;
}
}

/*
Enter a series of i (any char to terminate)
-1
0
1
a // <- terminated
-1
0
1
Enter a series of d (any char to terminate)
-11.1
0.009
3.14159
a // <- terminated
-11.1
0.009
3.14159
*/
 
K

Kavya

Salt_Peter said:
How about:

#include <iostream>
#include <ostream>
#include <vector>
#include <iterator>
#include <limits>
#include <typeinfo>
#include <stdexcept>

// may need a specialization to capture std::string
template < typename T >
void parseInput( std::vector< T >& r_vt ) {
std::cout << "Enter a series of " << typeid(T).name();
std::cout << " (any char to terminate)" << std::endl;
T t;
while ( std::cin >> t ) {
if ( !std::cin.good() ) {
throw std::runtime_error( "reading input stream." );
}
r_vt.push_back( t );
}
std::cin.clear();
std::cin.ignore(std::numeric_limits< int >::max(), '\n');
}

// op<< for std::vector< T >
template< typename T >
std::eek:stream&
operator<<( std::eek:stream& os,
const std::vector< T >& r_vt )
{
std::copy( r_vt.begin(),
r_vt.end(),
std::eek:stream_iterator< T >( os, "\n" ) );
return os;
}

int main() {
try {
std::vector< int > vn;
parseInput( vn );
std::cout << vn;

std::vector< double > vd;
parseInput( vd );
std::cout << vd;

} catch ( std::exception & r_e ) {
std::cerr << "\nError: " << r_e.what();
std::cerr << std::endl;
}
}

/*
Enter a series of i (any char to terminate)
-1
0
1
a // <- terminated
-1
0
1
Enter a series of d (any char to terminate)
-11.1
0.009
3.14159
a // <- terminated
-11.1
0.009
3.14159
*/

That didn't answer my question. Your solution is way beyond my reach.
 
S

Salt_Peter

Kavya said:
That didn't answer my question. Your solution is way beyond my reach.

I don't see why you seem to think its beyond your reach, there isn't
anything misterious about it.
It also emphasizes that i like better your #2 solution except that i'ld
not combine a std::cin >> extraction with a std::cin.good check
together in a conditional expression for a while loop.

If you prefer without exceptions, return with an error message. What
you do not want to do is have a while loop fail silently without some
kind of feedback.

....
while( std::cin >> inum )
{
if( !std::cin.good() )
{
std::cerr << "error in standard input.\n";
return -1;
}
// do stuff
}
....

Besides, if you needed a while loop to process 2 conditionals, you'ld
do it like so:

while( !condition1 || condition2 )
{
// do stuff
}

which would mean that if either condition fails, the program exits the
while loop silently.
Not exactly what you want. And note that condition2 above is not even
processed should the first condition fail.
 
K

Kavya

anything misterious about it.
It also emphasizes that i like better your #2 solution except that i'ld
not combine a std::cin >> extraction with a std::cin.good check
together in a conditional expression for a while loop.

If you prefer without exceptions, return with an error message. What
you do not want to do is have a while loop fail silently without some
kind of feedback.

...
while( std::cin >> inum )
{
if( !std::cin.good() )
{
std::cerr << "error in standard input.\n";
return -1;
}
// do stuff}...

Besides, if you needed a while loop to process 2 conditionals, you'ld
do it like so:

while( !condition1 || condition2 )
{
// do stuff

}which would mean that if either condition fails, the program exits the
while loop silently.
Not exactly what you want. And note that condition2 above is not even
processed should the first condition fail.

Thanks for the explanation. But I have 2 more questions regarding this.
1) Why have you used <limits>?
2) In case of this
if( !std::cin.good() )
{
std::cerr << "error in standard input.\n";
return -1;
}
I am not able to see the error message on screen if I enter wrong input.
 
S

Salt_Peter

Kavya said:
Thanks for the explanation. But I have 2 more questions regarding this.
1) Why have you used <limits>?

<limits> is for the std::numeric_limits<> class which helps clean up
any residual values in std::cin before the next loop ( like the newline
entered by the user). Some implementations include <limits>
automatically from iostream and other includes. I don't know nor care,
since i use it, i include it.
If you comment out that line in the aforementioned program, you'll see
what i mean.
Note:
[15.6] Why is my program ignoring my input request after the first
iteration?
http://www.parashift.com/c++-faq-lite/input-output.html#faq-15.4
2) In case of this
if( !std::cin.good() )
{
std::cerr << "error in standard input.\n";
return -1;
}
I am not able to see the error message on screen if I enter wrong input.

good() returns an input stream flag, if you enter a char for example,
std::cin will not extract that char to an integer variable. That
does_not_constitute_an_error in the input stream itself. That
non-integer value stays in the std::cin input stream waiting to be
collected or extracted . The good() flag checks whether the std::cin
input stream itself has been compromised, which is a different
situation altogether.
Consult the following for an overview of the flags available:
http://www.cplusplus.com/ref/iostream/ios/good.html
i/o errors are very rare, but if you are writing a program that is
accidentally corrupting something like std::cin, you definitely want to
know, therefore the error check.

To answer your question, you know when a non-integer was entered since
that stops the while loop. Your thinking that the process is more
complicated than it is - its actually quite basic.
If you want to see a char that stopped the while-int loop, all you'ld
need to do is collect it...

int inum;
while( std::cin >> inum ) // keep reading integers until no ints
available
{
...
}
char c;
while( std::cin >> c ) // collect residual char values
{
std::cout << "non-int captured! -> " << c << std::endl;
}

For the moment, focus on the fact that a user presses enter to input
his integer. The integer is then extracted to the variable which leaves
that enter in the std::cin stream. What enter actually is depends on
the platform.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,265
Latest member
TodLarocca

Latest Threads

Top