How to check for input validity? - C++ - c++

srand(time(0));
int rolls, x;
string input;
die *d;
die header1;
cout << "Please enter the number of dies to use (4, 5, or 6) or press enter to default to 6 dies: ";
getline(cin, input);
if (input.empty())
{
// 6 dies by default
x = 6;
}
else if (input != "4" && input != "5" && input != "6" && !(cin.get() == '\n'))
{
while (input != "4" && input != "5" && input != "6") {
cout << "INVALID Input: ";
getline(cin, input);
}
}
else
x = stoi(input);
I don't understand why the loop won't exit. The user should only input 4, 5, 6 and ENTER key for default value of 6. I checked for if they just hit ENTER key on first try but then if they hit something else like 2 or anything else, it'll say INVALID input. Inside the while loop though, as long as they enter 4,5,6 and ENTER key, it should exit right? Not only does it just keep cycling through but when i add the cin.get() condition to the while loop, it seems like it is even expecting user input before it re-iterates through the loop again. Am I using cin.get() wrong to check for user input emptiness?

The input could be rewritten to use an outer while loop that continues to loop until the input is acceptable. Then there is no need to use/misuse cin::get:
#include <iostream>
#include <string>
int main()
{
std::string input;
// loop until the input is good
while (true)
{
std::cout << "Please enter the number of dies to use (4, 5, or 6) or press enter to default to 6 dies: ";
std::getline(std::cin, input);
// something was entered
if (!input.empty())
{
// check for 4, 5, or 6 being entered
if (input == "4" || input == "5" || input == "6")
break; // get out of input loop
else
// input entered is no good
std::cout << "\nINVALID Input: " << input << ". Please try again:\n\n";
}
else // nothing was entered
{
input = "6";
break; // get out of input loop
}
}
std::cout << "\nSuccess: Your input was: " << input;
}
Live Example
Note that something like 4 will not be considered valid, since there is a trailing space. If you need to trim any excess space, that is another issue.

Related

Input validation to filter out chars, strings, and a range of ints

I have looked in several places on the Internet but cannot find what I am looking for. Basically I am trying to understand data validation and filter out all user input except either the number 1 or 2. I have found information for validating ints. Found stuff on filtering out chars and strings. But when I try to put them together it doesn't work. Basically if the user enters something that is not 1 or 2, it does not end a loop asking for correct input.
I have included more details in the comments in the code below.
Any help is appreciated!
#include <iostream>
#include <string>
int main()
{
std::cout << "Please enter 1 or 2. No other numbers or characters."
<< std::endl;
std::string numberString;
//Used a string so if the user enters a char it gets converted to an
//integer value of 0.
getline(std::cin, numberString);
int numberInteger = atoi(numberString.c_str());
//If the user enters the wrong number, char, or string,
//the program goes to this area of code.
//But if a subsequent correct entry is made, the loop does not end.
if (numberInteger < 1 || numberInteger > 2)
{
do
{
//Tried using these two lines of code to clear the input buffer,
//but it doesn't seem to work either:
//std::cin.clear();
//std::cin.ignore(std::numeric_limits <std::streamsize>::max(), '\n');
std::cout << "Invalid input. Please enter 1 or 2. No other numbers or characters."
<< std::endl;
getline(std::cin, numberString);
int numberInteger = atoi(numberString.c_str());
} while (numberInteger < 1 || numberInteger > 2);
}
else
{
std::cout << "You entered either 1 or 2. Great job! "
<< std::endl;
}
return 0;
}
#include <cctype>
#include <limits>
#include <iostream>
std::istream& eat_whitespace(std::istream& is)
{
int ch;
while ((ch = is.peek()) != EOF && ch != '\n' &&
std::isspace(static_cast<char unsigned>(ch))) // 0)
is.get(); // As long as the next character
// is a space, get and discard it.
return is;
}
int main()
{
int choice;
while (std::cout << "Please enter 1 or 2. No other numbers or characters: ",
!(std::cin >> std::skipws >> choice >> eat_whitespace) || // 1)
std::cin.peek() != '\n' || // 2)
choice < 1 || 2 < choice) { // 3)
std::cerr << "I said 1 or 2 ... nothing else ... grrr!\n\n";
std::cin.clear(); // 4)
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 5)
}
std::cout << "Input was " << choice << '\n';
}
0) Don't feed isspace() negative values.
1) Extraction of an int failed. Allow whitespace before and after the int.
2) If the next character in the stream is not a newline character, there is garbage left eat_whitespace() didn't swallow --> complain.
3) choice not in range.
4) clear flags to make sure input functions will work again.
5) ignore up to maximum streamsize characters untill the next newline.

C++ input check

I have this piece of code and it makes an input check. It works until some point but when I enter for example "12rc" which is supposed to be invalid the check is skipped. How can I change it? Thank you in advance!
cout << "Enter your choice 1, 2, 3: ";
cin >> choice;
cout << endl;
while (cin.fail() || choice <=0 || choice >=4) { // check input value
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
cout << "Wrong input value! Please enter only 1, 2, 3: ";
cin >> choice;
cout << endl;
I give an assumption that you want to get an integer from the standard input stream. In other cases you may take the same idea and realize how to generalize your problem.
I think that it might be solved somehow like this
#include <iostream>
#include <cctype>
#include <stdexcept>
void skip_to_int() {
if (std::cin.fail()) {
// try to fix up a mess in the input
std::cin.clear();
for (char ch; std::cin >> ch; ) {
if (std::isdigit(ch) || ch == '-') {
std::cin.unget()
return;
}
}
}
// throw an error for example
throw std::invalid_argument{"Not integral input"};
}
int get_int() {
int n;
// try to get the integer number
while (true) {
if (std::cin >> n) {
return n;
}
std::cout << "Sorry, that was not a number. Try again" << std::endl;
// if user inputed not an integral try to search through stream for
// int occurence
skip_to_int();
}
}
int main() {
std::cout << "Enter your choice 1, 2, 3: " << std::endl;
int choice = get_int();
while (choice <= 0 && choice >= 3) {
// continue searching
choice = get_int();
}
// process choice somehow
}
There is nothing wrong with your code. It works fine for inputs like "12rc": http://ideone.com/Ma0j7r
The inputs:
12rc
0
a
11
$
10
2
Yield:
Enter your choice 1, 2, 3:
Wrong input value! Please enter only 1, 2, 3:
Wrong input value! Please enter only 1, 2, 3:
Wrong input value! Please enter only 1, 2, 3:
Wrong input value! Please enter only 1, 2, 3:
Wrong input value! Please enter only 1, 2, 3:
Wrong input value! Please enter only 1, 2, 3:
Is it possible that you had a space before the "2rc"? These inputs would be read as 1:
"1 2rc"
"1rc"
\n1\nrc"

C++ Switch loop error

I'm a C++ beginner. My problem is, if the user accidentally inputs a letter, the program will send the error message and it wont loop back. This is my code:
#include <string>
#include <iostream>
using namespace std;
int main()
{
int q;
A:
cout << "[1] Name";
cout << "\n[2] Address";
cout << "\nEnter your choice: ";
cin >> q;
switch (q)
{
case 1:
cout << "XXXXXXXXXX" << endl;
break;
case 2:
cout << "XXXXXXXXXX" << endl;
break;
default:
cout << "Error! Enter only numbers from 1 - 2" << endl;
goto A;
}
return 0;
}
Output was :
[1] Name
[2] Address
Enter your choice: x
Error! Enter only numbers from 1 - 2
[1] Name
[2] Address
Enter your choice: Error! Enter only numbers from 1 - 2
[1] Name
[2] Address
Enter your choice: Error! Enter only numbers from 1 - 2
...
It should be like this,
[1] Name
[2] Address
Enter your choice: 8
Error! Enter only numbers from 1 - 2
[1] Name
[2] Address
Enter your choice:
If user enters a wrong number, it loops back, and if the user enters a letter, it should loop back like this too.
What is wrong?
The problem is that when you enter a non-integer input, the input is not actually extracted from the input-buffer, so each iteration of the loop you will attempt to read the same input over and over again.
What you need to do is rely on the fact that illegal input (non-integer in your case) will cause the stream to set its failbit, that the input operator >> function returns a reference to the stream, and that the state of a stream can be checked in a simple boolean condition.
Something like
if (std::cin >> q)
{
// Successfully read an integer
}
else
{
// Failed to read an integer, input is probably something else
// Clear the failbit
std::cin.clear();
// Explicitly ignore the rest of the line
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Output error message
}
The above code can be put in a loop that is exited by setting a boolean variable in the switch-cases for valid integers.
References:
std::ios::clear
std::istream::ignore.
std::numeric_limits
Since the input might not be numeric, let's allow for that. I'm assuming the use of System.String -- if it isn't, modifying this snippet is left as an exercise for the student.
using System;
String entry = "";
int entry_val = 0;
bool valid = false;
do
{
//menu goes here
cin >> entry;
if ( entry >= "1" && entry <= "2" )
{
entry_val = entry.ToInt();
valid = true;
}
else
{
cout << "Error! Enter only numbers from 1 - 2" << endl;
}
while (valid == false)
...
continue with the switch() {} block.

Infinite while loop happens when asking user for 2 numbers

I'm trying to implement a simple game where user is asked for 2 valid integer coordinates between 0 and 10. (int row, int column)
An exemple of what I would realize is:
Insert coordinates: 4C
*Error, number of row and column must be integer
Insert coordinates: 44 2
*Error, number of row or column are too high
Insert coordinates: 4 3
The coordinates you entered are (4,3)
I realized all of these with a do-while cycle.
int r,c;
do{
cout<<"Insert coordinates: ";
cin>>r>>c;
if (cin.fail())
{
cout << "ERROR: Number of row and column must be integer." << endl << endl;
}
if ((r<0 || r>10) || (c<0 || c>10)
{
cout << "*Error, number of row or column are too high [0-10]" << endl << endl;
}
cout<<endl;
}
while (((r<0 || r>10)||(c<0 || c>10)) || cin.fail());
This code doesn't work properly. If I enter 2 numbers between 0 and 10, it works. If I enter a number bigger then 10, it also works. But if I entered a character the program goes into an infinite loop, and does not work properly.
How to implement this to handle errors with character input? Is there a way to recognize, and remain inside the while cycle, if user inputs a character?
If you enter a letter instead of a number, then that letter is not extracted from the input buffer, so your code will continue to fail forever.
If the input fails (why not use e.g. if (!(cin >> r >> c))?) then you can skip the line by doing calling the ignore function:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
You also want to clear the failbit as it's not cleared automatically, this is done with the clear function.
You can also bypass this problem by getting the whole line, and using std::istringstream for the parsing:
do
{
std::string line;
if (!std::getline(std::cin, line))
... // Could not read from input
std::istringstream iss(line);
int r, c;
if (!(iss >> r >> c))
... // Failed to parse as numbers
...
} while (...);
You could simply check if characters were entered, for example:
if (x >= 0x41 && x <= 0x7A)
cout<<"error, you entered a letter";
(((r<0 || r>10)||(c<0 || c>10)) || cin.fail());
change to
(((r>0) && (r<10))||((c>0) && (c<10))) //It will work, no need to check cin.fail();
If cin fails then it might produce errors in buffer so better to quit the program..
The program goes into an infinite loop because you never clear the fail state. You can simplify your entire loop:
#include <iostream>
using namespace std;
int main()
{
int r = -1;
int c = -1;
bool valid = false;
do
{
cout<<"Insert coordinates: ";
if (cin >> r >> c)
{
if (r >= 0 && r <= 10 && c >= 0 && c <= 10)
{
valid = true;
}
}
else
{
cin.clear();
cin.ignore();
}
if (!valid)
{
cout << "ERROR: Number of row and column must be an integer between 0 and 10." << endl;
}
} while (!valid);
cout << "You entered (" << r << ", " << c << ")" << endl;
return 0;
}

cin.getline() strange behavior

the following is an exercise from a book for practicing some class inheritance. But the problem is in the client, not with the class design. (BaseCore, baseDMA, lacksDMA and hasDMA are the classes BTW).
// usedma.cpp -- polymorphic example (compile with dma.cpp)
#include <iostream>
#include "dma.h" // includes <iostream>
const int ELEMENTS = 1;
const int LENGTH = 30;
int main()
{
using std::cin;
using std::cout;
BaseCore *pArr[ELEMENTS];
char tempDate[LENGTH];
char kind;
for (int i = 0; i < ELEMENTS; i++)
{
cout << "\nEntering data for element #" << i + 1 << "\n\n";
cout << "Enter the date it was created: ";
cin.getline(tempDate, LENGTH - 1);
cout << "Enter 1 for baseDMA, 2 for lacksDMA, or 3 for hasDMA: ";
while (cin >> kind && kind != '1' && kind != '2' && kind != '3')
cout <<"Wrong data. Please, try again: ";
while (cin.get() != '\n')
continue;
char tempLabel[LENGTH];
int tempRating;
cout << "Enter the label: ";
cin.getline(tempLabel, LENGTH - 1);
cout << "Enter the rating: ";
cin >> tempRating;
if (kind == '1') // baseDMA
pArr[i] = new baseDMA(tempDate, tempLabel, tempRating);
if (kind == '2') // lacksDMA
{
char tempColor[LENGTH];
cout << "Enter the color: ";
cin.getline(tempColor, LENGTH - 1);
pArr[i] = new lacksDMA(tempDate, tempLabel, tempColor, tempRating);
}
if (kind == '3') // hasDMA
{
char tempStyle[LENGTH];
cout << "Enter the style: ";
cin.getline(tempStyle, LENGTH - 1);
pArr[i] = new hasDMA(tempDate, tempLabel, tempStyle, tempRating);
}
while (cin.get() != '\n')
continue;
}
cout << "\n";
for (int i = 0; i < ELEMENTS; i++)
{
pArr[i]->View();
cout << "\n";
}
cout << "Done.\n";
std::cin.get();
return 0;
}
Sample execution:
Entering data for element #1
Enter the date it was created: 2012.01.01
Enter 1 for baseDMA, 2 for lacksDMA, or 3 for hasDMA: 2
Enter the label: lacksDMA
Enter the rating: 15
Enter the color: blue
Date of creation: 2012.01.01
Label: lacksDMA
Rating: 15
Color:
Done.
It seems the Color member gets assigned the null character. This behavior happens inside both the if (kind == '2') and if (kind == '3') statements (with the style member in this case).
If I put a cin.get(); just before cin.getline() it works fine but I have to press an extra key to make the program ask for input.
Why is this happening? If there was a '\n' pending in the input queue, cin.getline() would discard it and put '\0' in the variable, I can understand that. But the program asks me for the input for color and let's me enter it normally. Also, if I put a cin.get(), then the program shouldn't be waiting for an extra key stroke in the execution, it just should get rid of that extra '\n'. What am I missing here?
cout << "Enter the rating: ";
cin >> tempRating;
Unlike, istream::getline(), operator>> leaves the trailing \n in the stream. It causes the next call to getline inside one of your if statements to get empty input.
The stream is empty when control flow reaches while (cin.get() != '\n') statement at the end of for loop - it's waiting for input and it appears as if you're still inputing color.
Call cin.ignore() right after and it'll work.
Note that this kind of bug is immediately obvious if you put a "debugging cout" right after the input statement for color. There's one more issue with the way you're getting tempRating. If you enter invalid input, say "xy", the erros flags will be set on cin and the program will enter an infinite loop. Always check whether input operations suceeded.
If I put a cin.get(); just before cin.getline() it works fine but I have to press an extra key to make the program ask for input.
It seems to me that when you don't put the cin.get(), your getline is getting an empty character. Then, when you put the cin.get, you get that empty character and the your getline works fine..
But you should definitely go in debug to see exactly what's happening!