Input validation

So it has come to my understanding that cin.fail() has some drawbacks, namely
if, say, 1ssssss is entered, the input will be accepted. So I am trying to find a work around but I am having trouble.
The simplest solution I can think of is if that program detects something that isn't an integer it will prompt the user to retry with only an int.

I want to make it so the user can only input numerical values.
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
  void inputValidation(string &choice) 
{
	bool charRead = false;
	cout << "charRead" << charRead << endl;
	getline(cin, choice);
	int index = 0;

	for (int i = 0; i < choice.length(); i++)
	{
		if (isalpha(choice[i]))
		{
			charRead = true;
			cout << "charRead" << charRead << endl;
		}
	}

	while (charRead== true)
	{
		for (int i = 0; i < choice.length(); i++)
		{
			if (isalpha(choice[i]))
			{
				cout << "That was an invalid input. Please omit characters." << endl;
				//cin.clear();
				//cin.ignore(25);
				getline(cin, choice);
			}
			else charRead = false;
		}
	}//end loop
		 
	
	
	

}


The code will deny inputs like "2s" for awhile but will then go accept them eventually. I've tried cin.clear and cin.ignore but they don't seem to be helping :(
Last edited on
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
#include <iostream>

int get_int( const char* prompt, int min_value, int max_value )
{
    std::cout << prompt << " [" << min_value << ',' << max_value << "]: " ;

    int number ;
    // if the user entered an int and the next character in the input stream is a white space
    if( std::cin >> number && std::isspace( std::cin.peek() ) )
    {
        // in the entered number is within valid range, return it
        if( number >= min_value && number <= max_value ) return number ;

        else std::cout << "input error: the value is out of range." ;
    }

    else std::cout << "input error: not an integer." ;

    // if we reached here, there was an input error. clean up and try again
    std::cin.clear() ;
    std::cin.ignore( 1000, '\n' ) ;
    std::cout << " try again.\n" ;
    return get_int( prompt, min_value, max_value ) ;
}

int main()
{
    const int n = get_int( "enter a number", 10, 99 ) ;
    std::cout << n << '\n' ;
}
In a while loop, can you read the user input into a string and use one of the string-to-X functions here:

http://www.cplusplus.com/reference/string/

To perform a string-to-numeric type cast. Catch the Invalid_Argument exception if it is thrown (when a string can't be converted to numeric) and break out of the while loop when the exception isn't thrown?

The general rule with user input is:

    The user will ALWAYS press ENTER at the end of EVERY input.

Hence, get input as a string, then parse. If all you want is a number, and nothing else, it becomes as easy as ElusiveTau said: attempt a string→whatever conversion.

I have a function that I use regularly, called “string_to”:

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
#include <iostream>
#include <optional>
#include <sstream>
#include <string>

template <typename T>
std::optional <T>
string_to( const std::string& s )
{
  T result;
  std::istringstream ss{ s };
  ss >> result >> std::ws;
  if (!ss.eof()) return {};
  return result;
}

int main()
{
  std::string strings[] =
  {
    "-7", "3.141592", "12 quarks", "abc", "x4y", "3"
  };

  for (auto s : strings)
  {
    auto x = string_to <int> ( s );
    if (x)
    {
      std::cout << "An integer: " << *x << "\n";
      continue;
    }

    auto f = string_to <double> ( s );
    if (f)
    {
      std::cout << "A float: " << *f << "\n";
      continue;
    }

    std::cout << "Neither float nor int: " << s << "\n";
  }
}

As JLBorges suggests, it is often a very good idea to simply write a small function to get a specific input.

Hope this helps.
Topic archived. No new replies allowed.