cin validation function sometimes doesn't run automatically - c++

I have two cin validation functions in a program I'm writing - one to validate int, and the other to validate double, whilst both ensuring that the user cannot enter char values. The problem I'm having is that sometimes the function will begin validation immediately after the user is asked to enter a value, like in this case:
cout << endl << "Enter transaction ID to edit : ";
toEdit = validateIntInput(toEdit, 1, MAX_TRANS);
Or this case:
cout << "How much are you adding? : " << char(156);
tVal = validateDoubleInput(tVal, 0.01, 999999998);
However, in other cases, the program will not tell the user that their input is invalid, and simply create a new line, like in this case:
cout << "What day of the month is the bill normally paid? (1 - 31) (You can change this later) : ";
paymentDay = validateIntInput(paymentDay, 1, 31);
Or this case:
cout << "Annual interest rate (%) : ";
annualInterestRate = validateDoubleInput(annualInterestRate, 0.01, 100);
The code for validateIntInput is:
int validateIntInput(int paramToCheck, int minValue, int maxValue)
{
paramToCheck = 999999999;
string line;
while (getline(cin, line))
{
stringstream linestream(line);
linestream >> paramToCheck;
// if the first if is not included, the program will assume invalid input has been entered as soon as the user is asked for input
if (paramToCheck == 999999999)
{
cout << "";
paramToCheck = 0;
}
// if the input contains a string or is not within bounds, throw an error
else if (!linestream.eof() || paramToCheck < minValue || paramToCheck > maxValue)
{
cout << red << "Invalid input. Try again : " << white;
}
// if the input is valid, stop the loop and accept the input
else
{
break;
}
}
return paramToCheck;
}
And the code for validateDoubleInput is:
double validateDoubleInput(double paramToCheck, double minValue, double maxValue)
{
paramToCheck = 999999999;
string line;
while (getline(cin, line))
{
stringstream linestream(line);
linestream >> paramToCheck;
// if the first if is not included, the program will assume invalid input has been entered as soon as the user is asked for input
if (paramToCheck == 999999999)
{
cout << "";
paramToCheck = 0;
}
// if the input contains a string or is not within bounds, throw an error
else if (!linestream.eof() || paramToCheck < minValue || paramToCheck > maxValue)
{
cout << red << "Invalid input. Try again : " << white;
}
// if the input is valid, stop the loop and accept the input
else
{
break;
}
}
return paramToCheck;
}
NOTE: The only reason why the functions assign a value of 999999999 to the parameter and check for this on startup is because the program sometimes threw an exception even before the user had entered anything.
I really have no idea what could be going wrong here - could anyone help me get to the bottom of the problem?
Thanks in advance to anyone who can!

As I stated in the comment section, I am not getting the situation where it skips input validation. The closest I got was when I entered a char value twice, and had a minimum acceptable value of 0. In which case it would just return 0.
In the circumstance that it isn't telling you the value is invalid is because in your check you are using
if (paramToCheck == 999999999)
{
cout << ""; // Doesn't print out an error like you want it to
paramToCheck = 0;
}
I would rearrange your function to do this instead:
if (!linestream.eof() || paramToCheck < minValue ||
paramToCheck > maxValue || paramToCheck == 999999999)
{
cout << red << "Invalid input. Try again : " << white;
}

Related

How do i throw an exception if user input anything beside string?

I am stuck at where I want the user to enter a string only if the user enters a number is considered an invalid input.
Here is part of my code:
try {
cout << "What is the model of your car? ";
cin >> model;
//Error checking
// if user enter anything beside string excute this block
if (model ) {
throw runtime_error("INVALID INPUT");
}
cout << "what year is your " << model << "? ";
cin >> year;
if (cin.fail()) {
throw runtime_error("Not a number");
}
if (year < 0) {
throw runtime_error("Year can't be negative");
}
Well, model will always be a string, even if you put numbers in it. Because "1" is a string, and 65 is 'A', etc. But I think you mean how do you check if a string doesn't contain numbers.
bool contains_num(const std::string & str)
{
bool ret = false;
for(int i = 0; i < str.length(); i++)
if(isdigit(str[i]))
ret = true;
return ret;
}
This function will catch edge cases like an empty string, too.

C++ How do I compare a 'int' or 'double' to a char using ASCII code? Is it possible? [duplicate]

I am trying to get input from the user and need to know a way to have the program recognize that the input was or was not a double/char this is what i have right now... but when you type an incorrect type of input
1) the double test one just loops infinatly
2) the char one won't stop looping even with the correct imput
int main () {
double _double = 0;
bool done = true;
while ( done ) {
cout << "Please enter a DOUBLE:\n" << endl;
cin >> _double;
if ( _double > 0 ) { done = false; }
if ( _double < 0 ) { cout << "\nthe number you entered was less than zero\nplease enter a valad number..." << endl; }
if(cin.fail()) { cin.clear(); }
}
done = false;
char _char = ' ';
while ( !done ) {
cout << "Please enter a CHAR" << "\n";
cout << "\t'y' = yes\n\t'n' = no" << endl;
cin >> _char;
if ( _char == 'y' || _char == 'n' ) { done = true; }
if ( ! (_char == 'y' || _char == 'n') ) { cout << "\nyou have entered an invald symbol... \n" << endl; }
if(cin.fail()) { cin.clear(); }
}
The best bet is always to read your input as strings. You can then use functions like std::strtod() to test and convert to doubles. Checking if streams have failed and then resetting them is error prone at best, and doesn't give you the possibility of producing good error messages.
For example:
string s;
cin >> s;
char * p;
double d = strtod( s.c_str(), & p );
if ( * p == 0 ) {
cout << "Read double: " << d << endl;
}
else {
cout << "Read string: " << s << endl;
}
The pointer 'p' will point to the first character that cannot be converted to a double. How exactly you handle that really depends on your app's logic.
The problem is that when you read something and cin sees the input can never be a double, it stops reading, leaving the stuff in the buffer that it didn't consume. It will signal failure, which you clear but you won't eat the remaining input that cin didn't eat up. So, the next time the same wrong input is tried to read again, and again...
The problem with the char one is that you have to press the return key to make it process any characters on most terminals (this does not happen if you make your program read from a file, for instance). So if you press y then it won't go out of the read call, until you hit the return key. However, then it will normally proceed and exit the loop.
As others mentioned you are better off with reading a whole line, and then decide what to do. You can also check the number with C++ streams instead of C functions:
bool checkForDouble(std::string const& s) {
std::istringstream ss(s);
double d;
return (ss >> d) && (ss >> std::ws).eof();
}
This reads any initial double number and then any remaining whitespace. If it then hit eof (end of the file/stream), it means the string contained only a double.
std::string line;
while(!getline(std::cin, line) || !checkForDouble(line))
std::cout << "Please enter a double instead" << std::endl;
For the char, you can just test for length 1
std::string line;
while(!getline(std::cin, line) || line.size() != 1)
std::cout << "Please enter a double instead" << std::endl;
If you want to read only 1 char and continue as soon as that char was typed, then you will have to use platform dependent functions (C++ won't provide them as standard functions). Look out for the conio.h file for windows for instance, which has the _getch function for this. On unix systems, ncurses provides such functionality.
cin >> _double will always get you a double, whether they typed in "42", "0" or "mary had a little lamb". You need to read the user input as a string, then test that string to see if it is a double. sscanf will return 0 if it can't convert the input string to the desired type:
cout << "Please enter a DOUBLE:\n" << endl;
string s;
cin >> s;
if( !sscanf(s.c_str(), "%lf", &_double) )
{
done = false;
cout << "Not a number, sparky. Try again." << endl;
continue;
}
Also, identifiers with leading underscores like you have are reserved by the language. Don't get in the habit of naming things like _double -- someday, they may not work.

C++ - cin to only take one integer

This code works fine if I enter something that isn't a number in, e.g. F: it will print the error message. However, if I enter e.g. 2F2 or , it will take the 2 and pass the check, continue in my code and on the next cin >> statement it will put the F in, and then it loops back and puts the 2 in.
How do I make it so it only accepts a single number e.g. 2 and not e.g. 2F2 or 2.2?
int bet = 0;
// User input for bet
cout << " Place your bet: ";
cin >> bet;
cout <<
// Check if the bet is a number
if (!cin.good())
{
cin.clear();
cin.ignore();
cout << endl << "Please enter a valid number" << endl;
return;
}
bool Checknum(std::string line) {
bool isnum = true;
int decimalpoint = 0;
for (unsigned int i = 0; i < line.length(); ++i) {
if (isdigit(line[i]) == false) {
if (line[i] == '.') {
++decimalpoint; // Checks if the input has a decimal point that is causing the error.
}
else {
isnum = false;
break;
}
}
}
if (decimalpoint > 1) // If it has more than one decimal point.
isnum = false;
return isnum;
}
If you take a string from the user, this should work. You can convert the string to an integer or a float(stoi or stof, respectively). It may not be the best solution there is, but this is what I have. Excuse the indentation.
Do getline to read one whole line of input from cin.
Create a stringstream to parse the string you got.
In this parser, read the number; if it fails - error
Read whitespace; if it doesn't arrive to the end of string - error
#include <sstream>
...
int bet = 0;
std::cout << " Place your bet: ";
while (true)
{
std::string temp_str;
std::getline(cin, temp_str);
std::stringstream parser(temp_str);
if (parser >> bet && (parser >> std::ws).eof())
break; // success
cout << endl << "Please enter a valid number" << endl;
}
This code keeps printing the error message until it receives valid input. Not sure this is exactly what you want, but it's pretty customary UI.
Here >> ws means "read all the whitespace". And eof ("end of file") means "end of the input string".

CIN validation using cin.fail

I am developing a small program that asks for 4 integers one after the other using std::cin. I am using a function to request the integers, and passing in the maximum value allowed as an argument. To check if the the value is an integer i use std::cin.fail. The code which calls the functions is shown below.
cout << "Specify source number (1 - 1024)\n";
source = validate(1024);
cout << "Specify destination number (1 - 1024)\n"; // For all except data, the value is equal to the value returned by the validate function
destination = validate(1024); // The maximum possible value is passed in as an argument in each of the cases.
cout << "Specify type number (1 - 10)\n"; // User is prompted to enter the desired values.
type = validate(10);
cout << "Source port number (1 - 1024)\n";
port = validate(1024);
and the validate function code is shown below.
int validate(int max) {
int value; // Initialise variable to hold the value.
for (;;) { // Loop forever until correct input is entered.
cin >> value;
if (cin.fail()) { // If cin fails to receive a value matching the declared data type.
cout << "Characters are not permitted.\n"; // Notify the user of error.
cin.clear(); // Clear the error flag within cin.
cin.ignore(10000,'\n'); // Ignore the newline character in the buffer to prevent an infinite loop.
}
else if (value > max || value == 0) {
cout << "The value you have entered is not valid, please enter a number between 1 and " << max << "\n";
cin.clear(); // Clear the error flag within cin.
cin.ignore(10000, '\n'); // Ignore the newline character in the buffer to prevent an infinite loop.
}
else
break;
}
return value; // Return the validated value.
}
This works fine if the user enters just an integer, or just a letter, it validates as it should, the problem i am having is if a user enters for instance 34d or 22p. I get the error saying characters are not permitted but then it exits the function and moves onto the next request.
Tried rearranging and all sorts cant seem to solve it.
Any help greatly appreciated
What you want to do is to ignore the rest of the line even if you are successful:
int validate(int max) {
int value; // Initialise variable to hold the value.
for (;;) { // Loop forever until correct input is entered.
cin >> value;
if (cin.fail()) { // If cin fails to receive a value matching the declared data type.
cout << "Characters are not permitted.\n"; // Notify the user of error.
cin.clear(); // Clear the error flag within cin.
cin.ignore(10000,'\n'); // Ignore the newline character in the buffer to prevent an infinite loop.
}
else if (value > max || value == 0) {
cout << "The value you have entered is not valid, please enter a number between 1 and " << max << "\n";
cin.clear(); // Clear the error flag within cin.
cin.ignore(10000, '\n'); // Ignore the newline character in the buffer to prevent an infinite loop.
}
else {
cin.ignore(10000, '\n'); // Ignore the newline character in
break;
}
}
return value; // Return the validated value.
}
If you think this is too repetitive, you can do something like:
struct ignore_till_eol {
ignore_till_eol(std::istream& cin): input(cin) {}
~ignore_till_eol() { input.clear(); input.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); }
std::istream& input;
};
int validate(int max_value) {
for(;;) {
ignore_till_eol ignore(cin);
int v;
if( cin >> v && 0 < v && v <= max_value ) return v;
if( cin )
cout << "Value is invalid, must be between 1 and " << max_value << "\n";
else
cout << "Invalid characters in input\n";
}
}
or
int validate(int max_value) {
for(;;) {
ignore_till_eol ignore(cin);
int v;
if( !(cin >> v) )
cout << "Invalid characters in input\n";
else if( 0 < v && v <= max_value )
return v;
else
cout << "Value is invalid, must be between 1 and " << max_value << "\n";
}
}

C++ test if input is an double/char

I am trying to get input from the user and need to know a way to have the program recognize that the input was or was not a double/char this is what i have right now... but when you type an incorrect type of input
1) the double test one just loops infinatly
2) the char one won't stop looping even with the correct imput
int main () {
double _double = 0;
bool done = true;
while ( done ) {
cout << "Please enter a DOUBLE:\n" << endl;
cin >> _double;
if ( _double > 0 ) { done = false; }
if ( _double < 0 ) { cout << "\nthe number you entered was less than zero\nplease enter a valad number..." << endl; }
if(cin.fail()) { cin.clear(); }
}
done = false;
char _char = ' ';
while ( !done ) {
cout << "Please enter a CHAR" << "\n";
cout << "\t'y' = yes\n\t'n' = no" << endl;
cin >> _char;
if ( _char == 'y' || _char == 'n' ) { done = true; }
if ( ! (_char == 'y' || _char == 'n') ) { cout << "\nyou have entered an invald symbol... \n" << endl; }
if(cin.fail()) { cin.clear(); }
}
The best bet is always to read your input as strings. You can then use functions like std::strtod() to test and convert to doubles. Checking if streams have failed and then resetting them is error prone at best, and doesn't give you the possibility of producing good error messages.
For example:
string s;
cin >> s;
char * p;
double d = strtod( s.c_str(), & p );
if ( * p == 0 ) {
cout << "Read double: " << d << endl;
}
else {
cout << "Read string: " << s << endl;
}
The pointer 'p' will point to the first character that cannot be converted to a double. How exactly you handle that really depends on your app's logic.
The problem is that when you read something and cin sees the input can never be a double, it stops reading, leaving the stuff in the buffer that it didn't consume. It will signal failure, which you clear but you won't eat the remaining input that cin didn't eat up. So, the next time the same wrong input is tried to read again, and again...
The problem with the char one is that you have to press the return key to make it process any characters on most terminals (this does not happen if you make your program read from a file, for instance). So if you press y then it won't go out of the read call, until you hit the return key. However, then it will normally proceed and exit the loop.
As others mentioned you are better off with reading a whole line, and then decide what to do. You can also check the number with C++ streams instead of C functions:
bool checkForDouble(std::string const& s) {
std::istringstream ss(s);
double d;
return (ss >> d) && (ss >> std::ws).eof();
}
This reads any initial double number and then any remaining whitespace. If it then hit eof (end of the file/stream), it means the string contained only a double.
std::string line;
while(!getline(std::cin, line) || !checkForDouble(line))
std::cout << "Please enter a double instead" << std::endl;
For the char, you can just test for length 1
std::string line;
while(!getline(std::cin, line) || line.size() != 1)
std::cout << "Please enter a double instead" << std::endl;
If you want to read only 1 char and continue as soon as that char was typed, then you will have to use platform dependent functions (C++ won't provide them as standard functions). Look out for the conio.h file for windows for instance, which has the _getch function for this. On unix systems, ncurses provides such functionality.
cin >> _double will always get you a double, whether they typed in "42", "0" or "mary had a little lamb". You need to read the user input as a string, then test that string to see if it is a double. sscanf will return 0 if it can't convert the input string to the desired type:
cout << "Please enter a DOUBLE:\n" << endl;
string s;
cin >> s;
if( !sscanf(s.c_str(), "%lf", &_double) )
{
done = false;
cout << "Not a number, sparky. Try again." << endl;
continue;
}
Also, identifiers with leading underscores like you have are reserved by the language. Don't get in the habit of naming things like _double -- someday, they may not work.