C++ - Sanitize Integer Whole Number Input - c++

I currently am using a function I found in another StackOverflow post(I can't find it), that I am using before, named "GetInt". My issue with it is that if the user inputs something like "2 2 2" it puts it into my next two Cin's. I have tried getLine, but it requires a string and I am looking for an int value. How would I structure a check to sanitize for an integer value greater than 2 and throw an error to the 2 2 2 answer.
#include <iostream>
#include <string>
#include <sstream>
#include "Board.cpp"
#include "Player.cpp"
using namespace std;
int getInt()
{
int x = 0;
while (!( cin >> x))
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Please input a proper 'whole' number: " << endl;
}
return (x);
}
and my call
do
{
//do
//{
cout << "How many players are there? \n";
numberOfPlayers = getInt();
//} while (isdigit(numberOfPlayers) == false);
} while (numberOfPlayers < 2);
EDIT:
I chose Justin's answer because it was the closest to my original code and solved the issue without major changes.

Integers are delimited by spaces and the input 2 2 2 is just multiple integers. If you want to make sure that just one integer is entered per line you could skip whitespace characters until a newline is found. If a non-whitespace is found prior to a newline you could issue an error:
numberOfPlayers = getInt();
int c;
while (std::isspace(c = std::cin.peek()) && c != '\n') {
std::cin.ignore();
}
if (c != std::char_traits<char>::eof() && c != '\n') {
// deal with additional input on the same line here
}

You were on the right track with std::getline. You read the whole line as a string, then put it into a std::istringstream and read the integer out.
std::string line;
if( std::getline(cin, line) ) {
std::istringstream iss(line);
int x;
if( iss >> x ) return x;
}
// Error
This will have the effect of discarding any fluff that comes after the integer. It will only error if there is no input or no integer could be read.
If you want to have an error when stuff appears after the integer, you could take advantage of the way strings are read from a stream. Any whitespace is okay, but anything else is an error:
std::istringstream iss(line);
int x;
if( iss >> x ) {
std::string fluff;
if( iss >> fluff ) {
// Error
} else {
return x;
}
}

Change your code to this:
int getInt()
{
int x = 0;
while (!( cin >> x))
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Please input a proper 'whole' number: " << endl;
}
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
return (x);
}
Your code to ignore the rest of the line after receiving the integer is only called if the integer collection fails (for example, you type "h" as the number of players).

Related

Ending an input stream with a specified character, such as '|'?

Currently learning C++, newbie.
I have an issue when ending the input with the '|' character, my program skips to the end/ends and does not allow for further input. I believe it is because std::cin is in an error state due to inputting a char when expecting an int, so i have tried to use std::cin.clear() and std::cin.ignore() to clear the issue and allow the remainder of the programme to run but I still cannot seem to crack it, any advice appreciated.
int main()
{
std::vector<int> numbers{};
int input{};
char endWith{ '|' };
std::cout << "please enter some integers and press " << endWith << " to stop!\n";
while (std::cin >> input)
{
if (std::cin >> input)
{
numbers.push_back(input);
}
else
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max());
}
}
And then pass the vector to a function to iterate through x amount of times and add each element to a total, but the program always skips past the user input:
std::cout << "Enter the amount of integers you want to sum!\n";
int x{};
int total{};
std::cin >> x;
for (int i{ 0 }; i < x; ++i)
{
total += print[i];
}
std::cout << "The total of the first " << x << " numbers is " << total;
Please help!
When the use enters a "|" (or anything that is not an int), the loop ends and the error handling that is inside the loop does not execute. Just move the error code to outside the loop. Also, you read from stdin twice which will skip every other int.
while (std::cin >> input) {
numbers.push_back(input);
}
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Note: If you want to specifically check for "|" can change to something like this:
while (true) {
if (std::cin >> input) {
numbers.push_back(input);
}
else {
// Clear error state
std::cin.clear();
char c;
// Read single char
std::cin >> c;
if (c == '|') break;
// else what to do if it is not an int or "|"??
}
}
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

Input validation for certain test not working as expected

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
}

How to Differentiate Number 10 from '\n' in a Loop-Continuation Condition?

I have the following portion of code:
cout << "Enter a series of integers: ";
cin >> integer;
while (integer != '\n')
{
cout << ...
cin >> integer;
} // end while
If the user enters 10, my loop is breaking because number 10 = '\n' value in decimal.
How can I get around this issue?
Thanks,
Your attempted code does not work because the operation cin >> integer extracts digits and converts them to an int. It cannot distinguish where the end of the line was.
Instead you should read a complete line, and then extract integers out of that line, e.g.:
std::string s;
std::getline(std::cin, s);
std::istringstream iss(s);
int integer;
while ( iss >> integer )
{
// do something with integer
}
Consider reading the user's input into a std::string first.
If it's not the newline, convert to an int and do your work.
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
int main(){
std::string integer;
cout << "Enter a series of integers: ";
cin >> integer;
while (integer != "x") //<- can't be whitespace
{
cout << atoi(integer.c_str()) << std::endl;
cin >> integer;
}
}
By default, input streams will skip any whitespace, including newlines. In other words, you will never have a ten in the input value unless someone entered "10". The general way to handle input is to read until reading fails (e.g. due to EOF):
while(cin >> value)
{
// use value here
}
// failure, EOF or garbage on input
Note that you will have to cin.clear() the stream before reading anything else afterwards, and that you still have the garbage in there that you have to cin.ignore(..). Maybe you want to use line-based input using getline() instead, and then simply check if the resulting string is empty or (try to) parse it as an integer otherwise.
#include <iostream>
int main(void)
{
int integer = 0;
std::cout << "Enter a series of integers: ";
std::cin >> integer;
while (integer != '\n' || integer == 10) {// **this will not work, it's wrong!**
std::cout << integer << std::endl;
std::cin >> integer;
}//end while
return 0;
}

Ignoring a line beginning with a '#' in command prompt

I am writing a code which requires me to ignore comment lines (i.e, lines beginning with a # sign) till the end of the line. I'm using linux to code in c++. For e.g: in case of adding two numbers.
xxx#ubuntu:~ $ ./add
Enter the two numbers to be added
1 #this is the first number
2 #this is the second number
result: 3
So the comment line can be anywhere. It just has to ignore the entire line and take the next value as input.
#include <iostream>
using namespace std;
int main()
{
int a,b;
cout<< "Enter the two numbers to be added:\n";
while(cin >>a >>b)
{
if (a == '#'|| b == '#')
continue;
cout << "Result: "<<a+b;
}
return 0;
}
From what you have shown, I think this might be what you want.
int main()
{
string comment;
int nr1,nr2;
// Read the first number. It should be the first one always. No comment before number!
cin >> nr1;
// See if we can read the second number Successfully. Which means it is an integer.
if(cin >> nr2) {
}
// Otherwise clear cin and read the rest of the comment line
else {
cin.clear();
getline(cin,comment);
// Now read the second number from the second line
cin >> nr2;
}
// Read the rest of second the line.
getline(cin,comment);
cout << "result: " << nr1 + nr2 << endl;
return 0;
}
Will any number of numbers based on the value you give reqd.
Will also work if the first character in a line itself is # - will ask again for that line. Will also read another line if there is no number before the `#.
#include <iostream>
#include <sstream>
#include <ctype.h>
using namespace std;
int main ()
{
const int reqd = 2;
string sno[reqd];
int no[reqd];
int got = 0;
size_t pos;
istringstream is;
cout<< "Enter "<<reqd<<" numbers to be added:\n";
while(got < reqd)
{
getline(cin, sno[got]);
if((pos = sno[got].find('#')) && isdigit(sno[got][0]))
{
is.str(sno[got]);
is>>no[got];
++got;
}
}
int sum = 0;
for(int i = 0; i < reqd; ++i)
sum+=no[i];
cout<<"Result : "<<sum;
return 0;
}

C++ insert numbers until certain symbol

I tried to write a code that asked me to input numbers one by one and when a certain char was inserted ( in this case 'x' ) it would stop the loop. But when I insert that char it starts spamming me with "Insert Number" . I think that the fault is that I'm trying to insert a char in an int array, but I can't think a way around it.
long int numbers[100]={0};
char h='y';
int index=0;
do
{
cout << "Insert Number : ";
cin >> numbers[index];
h=(char)numbers[index];
index++;
}
while(h!='x');
This happens because 'x' is not a number and cin >> numbers[index]; operation fails, without consuming that data. So the loop continues, gets the same x, fails again and everything starts all over again. You can check for result of input operation, something like this:
#include <iostream>
using namespace std;
int main ()
{
long int numbers[100]={0};
char h='y';
int index=0;
do
{
cout << "Insert Number : ";
if (cin >> numbers[index])
{
h=(char)numbers[index];
index++;
}
else
{
cout << "Hey, that was not a number! Bye." << endl;
break;
}
}
while(h!='x');
}
You should write a loop as:
while(cin >> numbers[index])
index++;
It will read all the integers, untill you enter some invalid input, be it 'x' or any other character. Now if you want to skip all invalid inputs and continue reading integers (which might be after invalid inputs), and want to consider only 'x' to exit from the loop, then wrap the above loop with another loop as:
char ch;
do
{
while(cin >> numbers[index])
index++;
cin.clear(); //clear the error flags, so you can use cin to continue reading
cin >> ch; //read the invalid character
} while(ch != 'x');
One piece of advice: prefer using std::vector<long int> over long int numbers[100]. What if user entered more than 100 integers, then your program will be corrupted.
Because you're trying to read in an integer, any character that isn't a digit can't be converted to a number and will jam up the input - you'll get an error and the bad character will not be removed from the stream. The next time you try to read you'll get the same error.
If you expect a number or a string, always read the input as a string, and try converting it to a number afterwards if the string isn't "x":
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
int main(int argc, char *argv[])
{
std::vector<long int> numbers;
std::string line;
while(std::getline(std::cin, line) && line != "x") {
std::istringstream input(line);
long int value;
// Check that there is only a number with nothing else after
if((input >> value) && input.get() == std::char_traits<char>::eof()) {
numbers.push_back(value);
} else {
std::cout << "Invalid Entry, please retry" << std::endl;
}
}
//...
return 0;
}