Currently having issues creating an integer validation loop in my code.
Trying to validate for an integer, however this code fails to work if you input, for example the string '22a' it sets trial_no as 22. Is there any way to check that every charachter input is indeed a string, such that '22a' or '2a2' would be considered erroneous and the loop would continue until a valid integer was input?
int trial_no;
bool valid = false;
while(!valid)
{
valid = true; //assume trial_no will be an integer
cout << "Enter the number of die throws to simulate" << endl;
cin >> trial_no;
if(cin.fail()) // exit loop condition is dependent on trail_no being a valid integer
{
cin.clear(); //corrects stream
cin.ignore(numeric_limits<streamsize>::max(), '\n'); //skips left over stream data (numeric_limit
// is in case user enters more than one letter))
cout << "Please enter an integer value" << endl;
valid = false; //cin not an integer so loop goes round to try again
}
}
Arguably the best way is to read the entire line as a string and utilize the std::stoi function:
#include <iostream>
#include <string>
int main() {
std::cout << "Enter an integer: ";
std::string tempstr;
bool valid = false;
std::getline(std::cin, tempstr);
try {
int result = std::stoi(tempstr);
std::cout << "The result is: " << result;
valid = true;
}
catch (std::invalid_argument) {
std::cout << "Could not convert to integer.";
valid = false;
}
}
As pointed out in the comments, this function can also throw a std::out_of_range exception. This assumes your compiler is C++11 (+) capable. If not, go down the std::stringstream route:
std::string tempstr;
std::getline(std::cin, tempstr);
std::stringstream ss(tempstr);
int result;
bool valid = false;
if (ss >> result) {
valid = true;
}
else {
valid = false;
}
Related
Currently having issues creating an integer validation loop in my code.
Trying to validate for an integer, however this code fails to work if you input, for example the string '22a' it sets trial_no as 22. Is there any way to check that every charachter input is indeed a string, such that '22a' or '2a2' would be considered erroneous and the loop would continue until a valid integer was input?
int trial_no;
bool valid = false;
while(!valid)
{
valid = true; //assume trial_no will be an integer
cout << "Enter the number of die throws to simulate" << endl;
cin >> trial_no;
if(cin.fail()) // exit loop condition is dependent on trail_no being a valid integer
{
cin.clear(); //corrects stream
cin.ignore(numeric_limits<streamsize>::max(), '\n'); //skips left over stream data (numeric_limit
// is in case user enters more than one letter))
cout << "Please enter an integer value" << endl;
valid = false; //cin not an integer so loop goes round to try again
}
}
Arguably the best way is to read the entire line as a string and utilize the std::stoi function:
#include <iostream>
#include <string>
int main() {
std::cout << "Enter an integer: ";
std::string tempstr;
bool valid = false;
std::getline(std::cin, tempstr);
try {
int result = std::stoi(tempstr);
std::cout << "The result is: " << result;
valid = true;
}
catch (std::invalid_argument) {
std::cout << "Could not convert to integer.";
valid = false;
}
}
As pointed out in the comments, this function can also throw a std::out_of_range exception. This assumes your compiler is C++11 (+) capable. If not, go down the std::stringstream route:
std::string tempstr;
std::getline(std::cin, tempstr);
std::stringstream ss(tempstr);
int result;
bool valid = false;
if (ss >> result) {
valid = true;
}
else {
valid = false;
}
I have a program that does three things. Asks you how many variables you wan't, ask you to input each variable, then stores it in a vector. I have put some code that checks if your input is correct, and if it isn't, re-loops the code asking for your variable. The problem I am having is that when you type anything in around the second variable, it asks you to try again infinitely.
For instance, if I typed these values into the input:
Variable amount: 5
Please input variable 1: 8
Please input variable 2: 8
ERROR, PLEASE ENTER ONLY VALID SYMBOLS
---------------------
Please input variable 2:
It would keep outputting ERROR, PLEASE ENTER ONLY VALID SYMBOLS over and over again no matter what you typed. The code is down below, and if you have a better name for this question please let me know. (I'm not really sure what to call this)
#include <iostream>
#include <cmath>
#include <string>
#include <algorithm>
#include <vector>
#include <sstream>
using namespace std;
int inputErrorMessage()
{
cout << "\n ERROR, PLEASE ENTER ONLY VALID SYMBOLS \n";
cout << "--------------------- \n";
return 0;
}
int main()
{
// Declare the variables, vectors, etc.
int varNum = 1;
int totVar = 0;
int choice = 0;
vector<int> userNums;
double input = 0;
string checktotVar = "";
string checkInput = "";
string sym = "";
bool valid = false;
stringstream sstotVar;
stringstream ssinput;
if (choice != 6) {
while (!valid) {
valid = true;
// Ask user for how many variables they want then record it
cout << "Variable amount: ";
getline(cin, checktotVar);
sstotVar << checktotVar;
sstotVar >> totVar;
if (sstotVar.fail() || totVar <= 0) {
inputErrorMessage();
valid = false;
sstotVar.clear();
sstotVar.ignore();
}
}
valid = false;
while (!valid) {
valid = true;
// Ask the user for each variable, then record it into the array
for (int i = 0; i < totVar; ++i) {
cout << "Please input variable " << varNum << ": ";
getline(cin, checkInput);
ssinput << checkInput;
ssinput >> input;
if (ssinput.fail()) {
inputErrorMessage();
valid = false;
ssinput.clear();
ssinput.ignore();
}
if (valid == true) {
userNums.push_back(input);
varNum++;
}
}
}
}
}
ssinput >> input;
reads the one thing in ssinput right to the end of the stream while leaving the read valid. The next time around
ssinput << checkInput;
can't write into the stream because the stream hit the stream's end. That means the read also fails and
if (ssinput.fail()) {
enters the body of the if where the program clears the error
ssinput.clear();
and then promptly reads off the end of the stream with
ssinput.ignore();
causing the error all over again.
Quickest solution:
Recreate
stringstream ssinput;
on each loop iteration. So
stringstream sstotVar;
//stringstream ssinput; gone from here
and
getline(cin, checkInput);
stringstream ssinput(checkInput); // and now tighter scope recreated each loop.
ssinput >> input;
Also by keeping the stream around without emptying it out it can get very., very big.
You can also simplify your logic around
while (!valid) {
and eliminate some repeated code by moving the read validation into it's own function
int getMeANumber(const std::string & message, int min)
that loops until it gets a number and then returns that number. For example:
int getMeANumber(const std::string & message, int min)
{
while (true)
{
cout << message;
string checktotVar;
getline(cin, checktotVar);
stringstream sstotVar(checktotVar);
int totVar;
sstotVar >> totVar;
if (!sstotVar || totVar <= min)
{
inputErrorMessage();
}
else
{
return totVar;
}
}
}
Now main is this itty-bitty tiny lil' thing.
int main()
{
int choice = 0;
vector<int> userNums;
if (choice != 6)
{
int totVar = getMeANumber("Variable amount: ", 0);
for (int i = 0; i < totVar; ++i)
{
stringstream varname;
varname << "Please input variable " << i+1 << ": ";
userNums.push_back(getMeANumber(varname.str(), numeric_limits<int>::min()));
// numeric_limits<int>::min requires #include <limits>
}
}
}
Here are the issues with this code.
In this part:
if (valid == true) {
userNums.push_back(input);
varNum++;
}
you forgot to add an ssinput.clear(). This will reset the stream state (clear the error flags), otherwise you cannot use it again. That is why it stops working at the second input.
In addition, even though this works, you are pushing back a variable that you declared as double into a vector of ints. That is bound to cause issues if this was intended to store double variables, instead of truncating them and storing them as ints.
It should be:
#include <iostream>
#include <cmath>
#include <string>
#include <algorithm>
#include <vector>
#include <sstream>
using namespace std;
int inputErrorMessage()
{
cout << "\n ERROR, PLEASE ENTER ONLY VALID SYMBOLS \n";
cout << "--------------------- \n";
return 0;
}
int main()
{
// Declare the variables, vectors, etc.
int varNum = 1;
int totVar = 0;
int choice = 0;
vector<int> userNums;
double input = 0;
string checktotVar = "";
string checkInput = "";
string sym = "";
bool valid = false;
stringstream sstotVar;
stringstream ssinput;
if (choice != 6) {
while (!valid) {
valid = true;
// Ask user for how many variables they want then record it
cout << "Variable amount: ";
getline(cin, checktotVar);
sstotVar << checktotVar;
sstotVar >> totVar;
if (sstotVar.fail() || totVar <= 0) {
inputErrorMessage();
valid = false;
sstotVar.clear();
sstotVar.ignore();
}
}
valid = false;
while (!valid) {
valid = true;
// Ask the user for each variable, then record it into the array
for (int i = 0; i < totVar; ++i) {
cout << "Please input variable " << varNum << ": ";
getline(cin, checkInput);
ssinput << checkInput;
ssinput >> input;
if (ssinput.fail()) {
inputErrorMessage();
valid = false;
}
if (valid == true) {
userNums.push_back(input);
varNum++;
}
ssinput.clear();
}
}
}
}
EDIT: You need to clear the stringstream on each iteration of the loop, otherwise you're not writing to an empty stream when you grab the next input from the user, which is what's causing the .fail() method to return true after the first iteration of the loop.
double checkInput() {
double add;
cout << "\n" << endl;
cin >> add;
if (cin.fail()==true)
{
cin.clear();
cin.ignore(INT_MAX, '\n');
cout << "Incorrect input"<<endl;
}
else
{
return add;
}
}
I use this bit of code to filter out character inputs eg "Blarg","bat12cat" and similar inputs where the character/letter come first but when i test with "1gold" ,"0.05cake" etc where number comes first then letters,the program accepts the all numbers up to the first instance of a letter.
My understanding is that it is the cin.ignore() that is causing the issue and is allowing the numbers through.
What would let inputs like"0.05Cats" be ignored/skipped altogether?.
Searching online,people suggest using getline() and stringstream.
Thank you.
When you input something like 1.5dog and then use cin >> some_double; >> is going to extract out a double until it can't read any more. So some_double gets the 1.5 and dog is still in the stream. This is not a failure and as such the failbit is not set. Since it is not set you skip your if statement and return the double value while the rest of the input stays in the stream and will cause you issues the next time you try to read from the stream. My suggestion is to change how you read your inputs. You can take in the input via a std::string and then convert it to the desired type. Then if the conversion fails you you can signal that you had a failure. I would use something like:
bool read_double(std::istream & is, double & number)
{
std::string line;
getline(is, line);
std::size_t pos = 0;
double temp = stod(line, &pos);
if (pos != line.size()) // there is extra content in the streams
return false;
number = temp;
return true;
}
And you can see it working with this Live Example
Usually there is more than one way to do the right thing. Using "c++(11) regex class object" would help you. You can edit regex for your needs (for example to include hex numbers by adding -a,b,c,d,e,f).
#include <iostream>
using namespace std;
#include <string>
using std::string;
#include <regex>
void main()
{
string input;
std::regex reg("[-+]?([0-9]*\.[0-9]+|[0-9]+)");
cout << "Please enter a double type\n";
while (cin >> input)
{
if (std::regex_match(input, reg))
{
std::cout << "Valid input\n";
break;
}
else
{
cout << "Invalid input\n";
cout << "Please enter a double type\n";
}
}
double do_with = std::stod(input,NULL);
cout << "the double is : " << do_with << endl;
cin >> input; // to hold the shell
}
I just want the user to avoid Input a String in an Integer value using Try Catch because using a while loop does not work at all. I know how to use Try Catch in Java but I do not in C++. I have been trying something like this:
#include <iostream>
using namespace std;
main(){
int opc;
bool aux=true;
do{
try{
cout<<"PLEASE INSERT VALUE:"<<endl;
cin>>opc;
aux=true;
}
catch(int e){
aux=false;
throw e;
cout<<"PLEASE INSERT A VALID OPTION."<<endl;
}
}while(aux==false);
system("PAUSE");
}//main
There are easier and better ways to do it, but if you really want exceptions, you could enable them and catch std::ios_base::failure. Something like this:
int main() {
int opc;
bool aux = true;
cin.exceptions(std::istream::failbit);
do {
try {
cout << "PLEASE INSERT VALUE:" << endl;
cin >> opc;
aux = true;
}
catch (std::ios_base::failure &fail) {
aux = false;
cout << "PLEASE INSERT A VALID OPTION." << endl;
cin.clear();
std::string tmp;
getline(cin, tmp);
}
} while (aux == false);
system("PAUSE");
}
Under normal circumstances the std::cin as all istreams does not throw an exception when the data provided does not fit. The stream changes its internal state to false. So you may simply do something like:
int n;
std::cin >>n;
if(!std::cin) {
// last read failed either due to I/O error
// EOF. Or the last stream of chars wasn't
// a valid number
std::cout << "This wasn't a number" << std::endl;
}
int opc;
cin >> opc;
The bad bit of the stream will be set when you try to read a non-numeric value. You can check if the stream is in a good state or not. If not, reset the state flags and try the reading again if you want. Note that when the bad bit is set, any following read is ignored. So what you should do before another trial is to first clear the bad bit of the input stream and ignore the rest of the bad input.
// If the input stream is in good state
if (cin >> opc)
{
cout << opc << endl;
}
else
{
// Clear the bad state
cin.clear();
// Ignore the rest of the line
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
// Now if the user enters an integer, it'll be read
cin >> opc;
cout << opc << endl;
I have 3 cin for ints.
int input1;
cin >> input;
int input2;
cin >> input2;
int input3
cin >> input3;
The problem is if i type 2 3 4 in console, it will input all 3 in one shot. How can i prevent this? And possibly give them a warning if they do this. basically error input validating.
One possible solution:
int strict_stoi(const string& s)
{
size_t end_pos;
int num = stoi(s, &end_pos);
for (size_t i=end_pos; i<s.length(); ++i)
{
if (!isspace(s[i]))
throw invalid_argument("You have entered some garbage after the number!");
}
return num;
}
int read_number()
{
string s;
getline(cin, s);
return strict_stoi(s);
}
int read_number_with_retry(const char* prompt)
{
for (;;)
{
try
{
cout << prompt;
return read_number();
}
catch (invalid_argument& ex)
{
cout << ex.what() << endl;
}
}
}
int test()
{
int input1 = read_number_with_retry("Enter input #1: ");
int input2 = read_number_with_retry("Enter input #2: ");
int input3 = read_number_with_retry("Enter input #3: ");
return 0;
}
If you enter a totally invalid argument (for example "a") then it will show you a not too user friendly "invalid stoi argument" message but if you enter "5 6" then it shows "You have entered some garbage after the number!". If you want to replace the "invalid stoi argument" message with something user friendly then instead of throwing an invalid_argument exception when you find "garbage after the number" you should throw you own garbage_after_the_number exception and in this case you could make the distinction between two different errors: invalid_argument would be thrown only in case of invalid inputs (like "a") and garbage_after_the_number would be thrown only in case of the other kind of error so you would be able to catch two different exceptions and you could print totally customized message in these two cases. I leave the implementation of this to you as an extra exercise.
You may do:
#include <iostream>
#include <sstream>
int main() {
while(true) {
std::cout << "Enter a number [Enter to quit]: ";
std::string line;
getline(std::cin, line);
if(line.empty()) break;
else {
std::stringstream input(line);
int number;
// Preceding white space number trailing white space:
input >> number >> std::ws;
if(input && input.eof()) {
std::cout
<< "The number surronded by possible white space is: "
<< number
<< '\n';
}
else {
std::cout
<< "The input line is invalid: "
<< line
<< '\n';
}
}
}
}
And if you want to be strict:
#include <iostream>
#include <iomanip>
#include <sstream>
...
// Number without preceding and trailing white space:
input >> std::noskipws >> number;
...