Trying to validate input in C++ - c++

The idea behind this code in c++ is to calculate the sum of all the entered numbers. When the user enters 0, the program should stop. This part of the code is working as I intended, but I'd like to include a variant which recognizes that a character different than a float number has been entered, ignore it in the calculation and allow the user to continue entering float numbers. At the moment, entering anything else but a float number stops the program.
I know there's a "if (!(cin >> numb))" condition, I've tried parsing it in different places in the code, but I can't figure out how to force the program to ignore these invalid inputs. I would be very grateful for any help.
#include <iostream>
#include <stdlib.h>
using namespace std;
float numb; float sum=0;
int main()
{
cout << "This app calculates the sum of all entered numbers." << endl;
cout << "To stop the program, enter 0." << endl << endl;
cout << "Enter the first number: ";
cin >> numb;
while(true)
{
sum += numb;
if (numb!=0)
{
cout << "Sum equals: " << sum << endl << endl;
cout << "Enter another number: ";
cin >> numb;
}
else
{
cout << "Sum equals: " << sum << endl << endl;
cout << "Entered 0." << endl;
cout << "Press Enter to terminate the app." << endl;
exit(0);
}
}
return 0;
}

You have three options:
trial and error: try to read a float, and in case of error clear the error flag, ignore the bad input and read again. The problem is that you don't know really how many of the input is to be ignored.
read strings: read space delimited strings, try to convert the string using stringstream, and just ignore the full string in case of error. The problem is that if the input starts with a valid float but then contains invalid characters (e.g. 12X4), the invalid part will be ignored (e.g. X4)
control parsing: read space delimited strings, try to convert the string using std::stof(), and check that all characters of the string where successfully read
Here the second approach, with a slightly restructured loop, so that a 0 entry will lead to exiting the loop and not the full program:
string input;
while(cin >> input)
{
stringstream sst(input);
if (sst>>numb) {
sum += numb;
cout << "Sum equals: " << sum << endl << endl;
if (numb==0)
{
cout << "Entered 0." << endl;
break; // exits the while loop
}
cout << "Enter another number: ";
}
else
{
cout << "Ignored entry "<<input<<endl;
}
}
cout << "Press Enter to terminate the app." << endl;
Online demo
If you prefer a more accurate parsing, consider something like:
size_t pos=0;
float xx = stof(input, &pos );
if (pos!=input.size()) {
cout << "error: invalid trailing characters" <<endl;
}

You have to clear the failbit after a failed read. After that, you can read in the invalid stuff into a string (that you just ignore). This function will read in values and add them up until it encounters a 0 or the end of the input stream.
int calc_sum_from_input(std::istream& stream) {
int sum = 0;
// If it couldn't read a value, we just read the thing into here
std::string _ignored;
while(stream) // Checks if the stream has more stuff to read
{
int value;
if(stream >> value)
{
if(value == 0) // Exit if it read the value 0
break;
else
sum += value; // Otherwise update the sum
}
else {
// Clear the failbit
stream.clear();
// Read ignored thing
stream >> _ignored;
}
}
return sum;
}
The logic is basically:
set the initial sum to 0
check if there's stuff to read
if there is, try reading in a value
if successful, check if the value is 0
if it's 0, exit and return the sum
otherwise, add the value to the sum
otherwise, clear the failbit (so that you can read stuff in again) and read the bad value into a string (which gets ignored)
otherwise, return the value

Related

Error checking two separate inputs

I'm trying to check two separate inputs if they are integers or not. I'm able to error check one input but I'm not quite sure how to check two separate ones if I'm using the 'get' function and both inputs are from the 'cin' stream. Using c++.
My code for checking one integer is displayed below.
#include <iostream>
using namespace std;
int main() {
int input;
cout << "Enter an integer: ";
cin >> input;
char next;
int x=0;
int done = 0;
while (!done){
next = cin.get();
if (next == ' ' || next == '\n'){
cout << "The Integer that you have entered is: " << input << "\n";
done = 1;
}
else if (next == '.'){
cerr << "Error: Invalid Input. Not an Integer." << "\n";
done = 1;
}
else{
cerr << "Error: Invalid Input. Not a number." << "\n";
done = 1;
}
}
return 0;
}
Well you could use >> into an int all the way through, drop all that get() stuff and character handling, and check cin.fail(). For example (I'll leave working this into your program and repeating it in a loop as an exercise for you):
int x;
cin >> x;
if (cin.fail())
cout << "Not a valid integer." << endl;
You can handle all subsequent input in exactly the same way. There's no reason to only limit operator >> to the first input.

C++ user enters floating point instead of integer

Im trying to get the program to only accept x as an integer then ask for another integer, y. However when i enter a floating point into x it takes the decimal part of the input and makes that the y value. i am unsure of my mistake here.
#include <iostream>
#include <string>
#include <limits>
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);
}
int toobig()
{
cout << "Your number is too large, please enter something smaller: " << endl;
int x = getInt();
return (x);
}
int toosmall()
{
cout << "your number is negative, please enter a positive number: " << endl;
int x = getInt();
return (x);
}
int main()
{
cout << "your number please:-" << endl;
int x = getInt();
if (x>100000)
{
toobig();
}
else if (x<0)
{
toosmall();
}
int y = 0;
cout << "enter y " << endl;
cin >> y;
cout << "x = " << x << endl;
cout << "y = " << y << endl;
system("PAUSE");
return 0;
}
Most conversions to int stop as soon as they find something that can't be part of an int and only a few conversion functions tell you if they stop before parsing the whole string.
Let's use one of those few, shall we?
int getInt()
{
for ( ; ; ) // loop until user provides something we can use.
// This is dangerous. You probably want to give up after a while.
{
std::string input; // read in as string
if (std::cin >> input)
{
char * endp; // will be updated with pointer to where conversion stopped
errno = 0;
// convert string to int
long rval = std::strtol (input.c_str(), &endp, 10);
if (*endp == '\0') // check whole string was read
{
if (errno != ERANGE) // check converted number did not overflow long
{
if (rval >= std::numeric_limits<int>::min() &&
rval <= std::numeric_limits<int>::max())
// check converted number did not overflow int
// you could replace this min and max with your own passed-in
// min and max values if you want
{
return rval; // return the known-to-be-good int
}
}
}
}
else
{ // note: usually when cin fails to read a string, it's over.
// This is actually a good time to throw an exception because this
// just shouldn't happen.
std::cin.clear(); // but for now we'll just clear the error and
// probably enter an infinite loop of failure
}
// failed for any reason. Blow off all user input and re-prompt
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Please input a proper 'whole' number: " << std::endl;
}
return 0; // to satisfy compiler because a non-void function must always return.
// Never reached because of infinite for loop.
}
since every console input on C++ is treated as a string, then under your getInt() method I would do the following:
int GetInt(istream &stream)
{
char obtainChar; //read a character from input
int x;
stream >> x;
while(stream.fail() || (stream.peek() != '\r' && stream.peek() != '\n'))
{
stream.clear(); //clear the fail state of stream
obtainChar = stream.get(); //read a character from input
while(obtainChar != '\n' && obtainChar != EOF) //while gotten char is not a return key or EOF
obtainChar = stream.get(); //read a character from input iterate up to '\n' or EOF
//displays an error message if there was a bad input (e.g. decimal value)
cerr << endl << "Please input a proper 'whole' number: " << endl;
cout << endl << "Please re-enter x: "; //re-prompt to re-enter a value
x = GetInt(stream); //Try again by calling the function again (recursion)
}
return x; //will return after the user enters ONLY if an integer was inputted
}
the first while is basically saying, if the stream (console input) does fails or the next stream char (.peek()) is not a \r or a \n the clear the stream and get the first character.
while that char is not a \n and not End Of File (EOF) then obtain the next char, so on and so forth.
if a problem occurred then display a error message to the user and re-prompt the user for the value of x.
then call the same function to re-test the input (recursively), if all is well then return the value of x.
you can now call this function to evaluate the value of Y.
NOTE: istream is part of the iostream library is basically cin
NOTE: call the function like so:
int x;
cout << "your number please:-" << endl;
x = GetInt(cin);

fixing an unintentional infinite loop

when i input a random number like 63453462 it responds with "invalid number" but in an infinite loop but if i put a number like 2,000,002 it just says invalid number with no loop. I need help with not making an infinite loop when someone inserts a random number like 2145345665465.
#include <iostream>
using namespace std;
int main ()
{
int sum , input , number;
cout << "Enter any positive integer that is less than or " ;
cout << "equal to 2,000,000 to determine if it is divisible by 11.";
cout << endl;
cout << "If the number is greater than 99, we use Dodgsons's rule";
cout << endl;
cout << "which determines if it is a factor or not.\n";
cout << endl;
cin >> input;
while ((input < 1) || ( input > 2000000 ))
{
cout << "Invalid number detected, please enter a positive integer.\n";
cin >> input;
}
number = input;
while ((input>=100) && (input < 2000000))
{
sum = input % 10;
input = input /10 - sum;
cout << input << endl;
}
if (input % 11 == 0)
cout << "the number is divisible by 11." << endl;
else
cout << "the number is not divisible by 11." << endl;
system ("Pause");
return 0;
}
while ((input < 1) || ( input > 2000000 ))
{
cout << "Invalid number detected, please enter a positive integer.\n";
cin >> input;
cin.clear();
}
cin.clear() will clear any previous state that cause the infinite loop.
You need to properly check whether your input operation succeeded. If you enter something that cannot be parsed as an integer, or some value that is more than INT_MAX or less than INT_MIN, then after
cin >> input
the stream std::cin will enter a failed state, that means the failbit is set. After that, each following input operation will also fail, unless you take care of it.
The usual approach here is to clear the input buffer (with the input that could not be handled) and just try again:
while (not (cin >> input) or not is_valid(input)) {
cout << "Invalid input, try again" << endl;
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
cin.clear();
}
This first does the input operation (cin >> input) and checks whether it not succeeded, and only if that is not true (i.e. the input operation succeeded) checks whether the input is not valid using some is_valid function. In that case an error is printed, all characters up to and including the next newline are removed from the stream, and the failbit is cleared, in order to allow a new take on getting valid input.
Note, that having two variables of the same type and doing
number = input;
is useless here, you can directly read into number (which is more appropriately named) and drop the variable input all together.

How do I stop this from infinitely repeating, but still keep the loop?

On line 33, there is a break to stop the code from repeating indefinitely, but I would like it to take part in the while loop.
The Code:
#include <iostream>
using namespace std;
int main()
{
while (true){
{
cout << "This program counts by twos to any number that is inputted by the user." << endl;
cout << "Input an even number to start counting." << endl;
int input;
cin >> input;
if (!cin.fail())//fails if input is not an integer
{
if (input < 0)//makes sure all numbers are positive
{
cout << "That is not a positive number. Try again?" << endl;
}
else if (input % 2 != 0) // makes sure all numbers are even
{
cout << "That is not an even number. Try again?" << endl;
}
else{
for (int i = 0; i <= input; i += 2) //uses a for loop to actually do the counting once you know that the number is even.
{
cout << i << endl;
}
}
}
if (cin.fail())//returns this when you input anything other than an integer.
{
cout << "That is not a digit, try again." << endl;
break;
}
}
}
return 0;
}
If you guys could help me find why this repeats, that would really help.
You need to add a break statement after the for loop in order to exit the loop. Without the break the for loop will execute and print your output and then control will fall to the end of the while loop where it will start back at the top of the loop.
I would also suggest changing if (cin.fail()) to just else as you are already checking if (!cin.fail()). You also need to ignore the rest of the input and clear the error flags if you want to loop again.
You also had a extra set of brackets in the while loop. With those changes your code would be:
#include <iostream>
#include <limits>
using namespace std;
int main()
{
while (true)
{
cout << "This program counts by twos to any number that is inputted by the user." << endl;
cout << "Input an even number to start counting." << endl;
int input;
cin >> input;
if (!cin.fail())//fails if input is not an integer
{
if (input < 0)//makes sure all numbers are positive
{
cout << "That is not a positive number. Try again?" << endl;
}
else if (input % 2 != 0) // makes sure all numbers are even
{
cout << "That is not an even number. Try again?" << endl;
}
else{
for (int i = 0; i <= input; i += 2) //uses a for loop to actually do the counting once you know that the number is even.
{
cout << i << endl;
}
break; // exit the while loop
}
}
else //else when you input anything other than an integer.
{
cout << "That is not a digit, try again." << endl;
cin.clear(); // reset the error flags
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // clear any extra input
}
}
return 0;
}
Based on the error message you print, I'm guessing your problem is that you want to give the user a chance to try again to enter a number, but after one failure, it continuously fails no matter what you enter. If that's the case, replace your break with cin.clear(). That will tell the stream that you've recovered from the error and are ready to receive more input.
If you're going to do that, though, your program now has no exit condition, so you'll want to add a break (or return 0) just after the for-loop.

While Loop with LCV of cin won't exit in C++

This is hw. I have asked my professor why the following code won't exit the while loop, and he/she couldn't tell me. My understanding is that once the input stream has no more values to read, the cin will return a value of false, and should cause the while loop to exit. Mine does not. It seems to keep read the input values (a set of integers) process through the loop, then wait for more input. Can anyone tell me why? Below is the code.
# include <iostream>
using namespace std;
int main()
{
int iEvenSum = 0;
int iOddSum = 0;
int iNum;
// prompt user
cout << "Input any set of integers, separated by a space:\n";
cin >> iNum;
cout << "You input: ";
while (cin)
{
cout << iNum << " ";
if (iNum % 2 == 0)
iEvenSum = iEvenSum + iNum;
else
iOddSum = iOddSum + iNum;
cin >> iNum;
}
cout << "\n\nThe sum of Even numbers is " << iEvenSum << "." << endl;
cout << "The sum of Odd numbers is " << iOddSum << "." << endl;
return 0;
}
while(cin) remains true as long as the cin stream is ok and becomes false if cin encounters an end of file character or an error.
In your case, while(cin) will keep on reading the numbers until it encounters an EOF character or an error. Type Ctrl-D when you don't have any more input numbers and it should quit the while loop