2

I'm very new to this C++ world and trying write a input validation function for numeric password. This is what I got so far:

#include <iostream>
#include <limits>
using namespace std;

void isNumeric(int &iN)
{
    while (1) {
        cin >> iN;

        if (cin.fail()) {
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
            cout << "Only 'numeric' value(s) are allowed: ";
            continue;
        }

        // alpha-numeric entry also not allowed 
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
        if (cin.gcount() >  1) continue;

        // check against the -ve value
        if (iN <= 0 ) continue;

    break;
    }
}

int main()
{
    int x;

    cout << "Enter your number: ";
    isNumeric(x);
    cout << "You've entered: " << x << endl;

    return 0;
}

It's working just fine for incorrect value(s) but not breaking out of the loop upon valid entry. Any idea what I'm missing here? Cheers!!


ErroR from James Kanze's script:

test.cpp: In function ‘bool parseNumber(const string&, int&)’:
test.cpp:11:20: error: no match for ‘operator>>’ in ‘text >> results’
test.cpp:11:20: note: candidates are:
/usr/include/c++/4.6/bits/basic_string.tcc:998:5: note: template<class _CharT, class _Traits, class _Alloc> std::basic_istream<_CharT, _Traits>& std::operator>>(std::basic_istream<_CharT, _Traits>&, std::basic_string<_CharT, _Traits, _Alloc>&)
/usr/include/c++/4.6/bits/istream.tcc:957:5: note: template<class _CharT2, class _Traits2> std::basic_istream<_CharT, _Traits>& std::operator>>(std::basic_istream<_CharT, _Traits>&, _CharT2*)
/usr/include/c++/4.6/bits/istream.tcc:925:5: note: template<class _CharT, class _Traits> std::basic_istream<_CharT, _Traits>& std::operator>>(std::basic_istream<_CharT, _Traits>&, _CharT&)
/usr/include/c++/4.6/istream:709:5: note: template<class _Traits> std::basic_istream<char, _Traits>& std::operator>>(std::basic_istream<char, _Traits>&, unsigned char&)
/usr/include/c++/4.6/istream:714:5: note: template<class _Traits> std::basic_istream<char, _Traits>& std::operator>>(std::basic_istream<char, _Traits>&, signed char&)
/usr/include/c++/4.6/istream:756:5: note: template<class _Traits> std::basic_istream<char, _Traits>& std::operator>>(std::basic_istream<char, _Traits>&, unsigned char*)
/usr/include/c++/4.6/istream:761:5: note: template<class _Traits> std::basic_istream<char, _Traits>& std::operator>>(std::basic_istream<char, _Traits>&, signed char*)
test.cpp:11:42: error: ‘const string’ has no member named ‘peek’
test.cpp:11:52: error: ‘EOF’ was not declared in this scope


New code: using getline() and validation as a string Thanks everyone (especially James Kanze) for helping me out. This thing is pretty much working here.

void isNumeric( int &iN )
{
    string sN; 

    while (1) {
        getline(cin, sN);

        bool valNum = true;
        for ( unsigned iDx=0; iDx < sN.length(); iDx++ )
            if ( !isdigit(sN[iDx]) ) { 
                valNum = false;
                break;
            }   

        if ( !valNum ) { 
            cout << "Wrong entry; Try again: ";
            continue;
        }   

        stringstream sStream (sN );
        sStream >> iN; 

        if ( iN<=0 ) {
            cout << "Cannot be 0; Try again: "; 
            continue;
        }     
    break;   
    }   
}

Is there any room in there for any more improvement? Cheers!!

2
  • @Shahbaz I always knew my c++ is hopeless but didn't know it has gone that far! Commented Apr 16, 2012 at 17:53
  • It's not about your code, your question title somehow reminded me of this funny I saw once! Commented Apr 16, 2012 at 18:04

2 Answers 2

3

This looks like line oriented input. In which case, the usual solution is to use getline:

bool parseNumber( std::string const& text, int& results )
{
    std::istringstream parser( text );
    return parser >> results >> std::ws && parser.peek() == EOF;
}

int getNumber()
{
    int results;
    std::string line;
    while ( ! std::getline( std::cin, line ) || ! parseNumber( line, results ) ) 
    {
        std::cin.clear();
        std::cout << "Only 'numeric' value(s) allowed:";
    }
    return results;
}
Sign up to request clarification or add additional context in comments.

16 Comments

Isn't getline() missing the second parameter?
@James Kanze: it returns this error: error: variable ‘std::istringstream parser’ has initializer but incomplete type - what does it mean? cheers!!
@jrok Yes. it should be std::getline( std::cin, line ).
@MacUsers It means that you're missing an include. Add #include <sstream> at the top of the file.
#include <sstream> - yes that's what I was looking for. On a separate note, where can I find the info like this? i.e. what needs to be included for a certain module (is it called 'module'?)? Cheers!!
|
2

If there is a failure to convert then the stream itself evaluates to false so you can do this:

int get_int() {
    int i;
    std::cout << "Please enter a number: " << std::endl;
    while(!(std::cin >> i)) {
        std::cin.clear();   //clear flags
        //discard bad input
        std::cin.ignore(std::numeric_limits<std::streamsize>::max()); 
        std::cout << "Incorrect, must be numeric: " << std::endl;
    }
    return i;
 }

4 Comments

It's not actually doing what I intend to do. An input like this: 123asd, should be rejected but it's accepting 123 (as expected). And if I enter: asd123, it doesn't do anything at all. Cheers!!
This will succeed if the user enters "1abc".
@James Kanze: That's some thing I don't want. My goal is: Anything else other than numeric values should be rejected. Cheers!!
@MacUsers That means that you shouldn't use std::ignore. My preference is still to read a complete line, using std::getline, and then parse it, consuming all of the characters in it. For validation, you can just read an int, followed by whitespace, then check that you have end of file, or you can pre-validate using regular expressions: "\\s+\\d+\\s+", for example. (This has the advantage/disadvantage that is will reject negative numbers.) The regex solution is the most general, but in this case, is probably overkill.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.