how to validate integer and not allow decimal, etc to input as integer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
int num;
do{
		
		cout << "How many values ?";
		cin >> num;
		cin.clear();
		cin.ignore();
		if (cin.fail())
		{
			cout << " must interger !" << endl;
			cin.clear();
			cin.ignore();
			
		}
		else if (num <= 0)
		{
			cout << " value greater than 0!" << endl;
			
			
		}

		else if (num == double(num))
		{

			cout << "no decimal place!" << endl;
			
			

		}
		
	} while (cin.fail()||num<=0||num==double(num));


what's wrong with the code? i want to check whether the input is an integer or not.
requirements: prompt error when it is decimal,alphabetic and negative value.thanks
Last edited on
closed account (48T7M4Gy)
http://www.cplusplus.com/forum/beginner/195925/
Something along these lines, perhaps:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <string>
#include <cctype>

int get_int( const std::string& prompt = "enter an integer" )
{
    std::cout << prompt << ": " ;

    int value ;

    // if we successfully read in an integer and the next character in the input buffer
    // is a white space, the user has entered an integer value; return it.
    if( std::cin >> value && std::isspace( std::cin.peek() ) ) return value ;

    // handle input error
    std::cout << "error: input is not an integer\n" ; // inform the user
    std::cin.clear() ; // clear the failed state
    std::cin.ignore( 1000000, '\n' ) ; // throw the bad input away
    return get_int(prompt) ; // and try again
}

int get_int( std::string prompt, int minv, int maxv )
{
    const int value = get_int( prompt + " [" + std::to_string(minv) + '-' + std::to_string(maxv) + ']' ) ;

    if( value >= minv && value <= maxv )
        return value ; // value is within range, return it

    std::cout << "error: input is out of range\n" ; // inform the user
    return get_int( prompt, minv, maxv ) ; // and try again
}


int main()
{
    const int n = get_int() ;
    std::cout << "value is " << n << '\n' ;

    const int score = get_int( "test score", 0, 100 ) ;
    std::cout << "the score is " << score << '\n' ;
}


Another option is to read a complete line of input as a string and then parse it. For instance:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int get_int( const std::string& prompt = "enter an integer" )
{
    std::cout << prompt << ": " ;

    std::string str ;
    std::getline( std::cin, str ) ;

    // begin of string, optional + or -, one to eight decimal digits, end of string
    static const std::regex int_re( "^[-+]?\\d{1,8}$" ) ; // #include <regex>

    // if the input matches the regular expression, return the string converted to an int
    if( std::regex_match( str, int_re ) ) return std::stoi(str) ;

    std::cout << "error: input is not an integer\n" ; // error in input: inform the user
    return get_int(prompt) ; // and try again
}
Use the string conversion routines.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <ciso646>
#include <sstream>
#include <stdexcept>
#include <string>

//----------------------------------------------------------------------------
// string_to <T> ()
//----------------------------------------------------------------------------
// Convert the argument string to a typed object.
// Uses the standard streams functionality.
// (So the object type must have an extraction operator.)
//
// bool string_to( s, &result )
//   Attempts conversion. Returns true on success, false otherwise.
//
// result string_to <T> ( s )
//   Attempts conversion. Returns result on success.
//   Throws std::invalid_argument on failure.
//
template <typename T, typename CharT = char, typename Allocator = std::allocator <CharT> >
bool string_to( const std::basic_string <CharT, Allocator> & s, T& result )
{
  // Convert string argument to T
  std::basic_istringstream <CharT> ss( s );
  ss >> result >> std::ws;

  // Stream should be in good standing with nothing left over
  return ss.eof();
}

template <typename T, typename CharT = char, typename Allocator = std::allocator <CharT> >
T string_to( const std::basic_string <CharT, Allocator> & s )
{
  T result;
  if (!string_to( s, result ))
    throw std::invalid_argument( "T string_to <T, CharT, Allocator> ()" );
  return result;
}

template <typename T>
bool string_to( const std::string& s, T& result )
{
  return string_to <T, char> ( s, result );
}

template <typename T>
T string_to( const std::string& s )
{
  return string_to <T, char> ( s );
}

//----------------------------------------------------------------------------
// istream& getline( istream&, &result [,delim] )
//----------------------------------------------------------------------------
// Extract a typed thing (not necessarily a string) from a stream.
//
// On success, the input stream is in a good state and result contains the
// converted value.
//
// On failure, the input stream will be in the fail state and the result
// contains a default-constructed value. (As per the C++11 standard's
// stupid mandate.)
//

template <typename T, typename CharT>
std::basic_istream <CharT> &
getline( std::basic_istream <CharT> & ins, T& result, CharT delim )
{
  std::basic_string <CharT> s;
  if (!std::getline( ins, s, delim ) or !string_to <T> ( s, result ))
  {
    result = T();
    ins.setstate( std::ios::failbit );
  }
  return ins;
}

template <typename T, typename CharT>
std::basic_istream <CharT> &
getline( std::basic_istream <CharT> & ins, T& result )
{
  std::basic_string <CharT> s;
  if (!std::getline( ins, s ) or !string_to <T> ( s, result ))
  {
    result = T();
    ins.setstate( std::ios::failbit );
  }
  return ins;
}

Works with anything (that provides proper stream conversion operators).

Hope this helps.
@Duoas
Why do you think that leaving the value default constructed (lines 60-62) is a stupid requirement? If I remember correctly, before C++11 the value was left unchanged.

You can have the stream throw exceptions as an alternative to not visibly complaining if you configure it.

Regarding getline(), what happens if your T can't be default-constructed? (These will be culled per substitution failure, but what about the standard streams?)

Also shouldn't line 28 be return ss.eof() && ! (ss.fail() || ss.bad ()) to ensure that the stream is in a valid state, or am I missing something?

It's nice to see someone actually use the alternate keywords.
closed account (48T7M4Gy)
1
2
3
4
5
6
7
8
9
10
11
12
while( !(std::cin < 0 )
    {
        std::cout << "You must enter a positive integer\n";
        if(!std::cin.fail())
        {
            // A message could go here about non integers but it is
            // redundant
            std::cin.clear();
            std::cin.ignore(1000,'\n');
        }
    }
}

(eg 7yu is known)
Last edited on
Thanks for every feedback. The main problem i am facing is deal with decimal input. I got if else statement to check for alphabetic, negative and decimal, and each show different error message. But i cant validate for the decimal value. appreciate for any solution, i am new to c++, simple code will do. ty
closed account (48T7M4Gy)
If it doesn't read as an integer then trap a spurious entry like 7yu because the stream will give you integer 7 first and then to give 'yu' if you don't. :)
Last edited on
Topic archived. No new replies allowed.