Infinite while loop happens when asking user for 2 numbers - c++

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;
}

Related

how to make cin only take integer inputs

i new to programming and we are required to create a program that dont exit when the user inputs the wrong input, but i only learned the basics so far.. i already solved when the number is above and below 100 but when the user accidentally inserted a non integer it will go into a error loop. btw this is an average calculator.
#include <iostream>
using namespace std;
int main()
{
int num[100];
int n;
double sum, average;
cout << "how many numbers will you input?: ";
cin >> n;
while ( n > 100 || n <= 0 )
{
cout << "Error! number should in range of (1 to 100) only." << endl;
cout << "Enter the number again: ";
cin >> n;
}
for ( int i = 0; i < n; ++i )
{
cout << i + 1 << ". Enter number: ";
cin >> num[i];
sum += num[i];
}
average = sum / n;
cout << "Average = " << average;
}
If std::istream::operator >> fails, it will set failbit. Therefore, you should check failbit (for example by calling std::cin.fail()) to see whether the conversion was successful, before using the result of the conversion.
If the conversion fails due to bad input, then the next call to std::istream::operator >> will automatically fail due to failbit being set. That is why you are getting stuck in an infinite loop. If you want to attempt input again after a conversion failure, you will first have to clear failbit, by using the function std::cin.clear().
Also, you will have to discard the bad input that caused the conversion to fail, because otherwise, the next time you call std::istream::operator >>, the conversion will fail again for the same reason. In order to clear the bad input, you can use std::cin.ignore(), like this:
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
In order to use std::numeric_limits, you will have to #include <limits>.
After performing these fixes on your code, it should look like this:
#include <iostream>
#include <limits>
using namespace std;
int main()
{
int num[100];
int n;
double sum, average;
bool input_ok;
//repeat until input is valid
do
{
cout << "How many numbers will you input? ";
cin >> n;
if ( cin.fail() )
{
cout << "Error: Conversion to integer failed!\n";
input_ok = false;
}
else if ( n > 100 || n <= 0 )
{
cout << "Error: Number should in range of (1 to 100) only!\n";
input_ok = false;
}
else
{
input_ok = true;
}
//clear failbit
cin.clear();
//discard remainder of line
cin.ignore( numeric_limits<streamsize>::max(), '\n' );
} while ( !input_ok );
for ( int i = 0; i < n; ++i )
{
do
{
cout << i + 1 << ". Enter number: ";
cin >> num[i];
if ( cin.fail() )
{
cout << "Error: Conversion to integer failed!\n";
input_ok = false;
}
else
{
input_ok = true;
}
//clear failbit
cin.clear();
//discard remainder of line
cin.ignore( numeric_limits<streamsize>::max(), '\n' );
} while ( !input_ok );
sum += num[i];
}
average = sum / n;
cout << "Average = " << average;
}
This program has the following behavior:
How many numbers will you input? 200
Error: Number should in range of (1 to 100) only!
How many numbers will you input? -31
Error: Number should in range of (1 to 100) only!
How many numbers will you input? test
Error: Conversion to integer failed!
How many numbers will you input? 4abc
1. Enter number: 1
2. Enter number: 2
3. Enter number: 3
4. Enter number: 4
Average = 2.5
As you can see, the program now works in that it can now handle bad input such as test. It rejects that input and reprompts the user for new input.
However, one problem with this program is that it accepts 4abc as valid input for the number 4. It would probably be appropriate to reject such input instead. One way to fix this would be to inspect the remainder of the line, instead of simply discarding it.
Another issue is that this solution contains a lot of code duplication. Apart from the range check, both do...while loops are nearly identical. Therefore, it would be better to put this loop into a function, which can be called from several places in your code.
However, I generally don't recommend that you use std::istream::operator >>, because its behavior is not always intuitive. For example, as already pointed out above:
It does not always read a whole line of input, so that you must explicitly discard the remainder of the line.
It accepts 4abc as valid input for the number 4.
In my experience, if you want proper input validation of integer input, it is usually better to write your own function that reads a whole line of input using std::getline and converts it with std::stoi. If the input is invalid, then the function should automatically reprompt the user.
In my example below, I am calling this function get_int_from_user.
If you want to additionally ensure that the input is in a certain range, then you can call the function get_int_from_user in an infinite loop, and break out of that loop once you determine that the input is valid.
#include <iostream>
#include <string>
#include <sstream>
#include <cctype>
int get_int_from_user( const std::string& prompt );
int main()
{
int nums[100];
int n;
double sum;
//repeat loop forever, until input is good
for (;;) //equivalent to while(true)
{
n = get_int_from_user( "How many numbers will you input? " );
if ( 1 <= n && n <= 100 )
//input is good
break;
std::cout << "Error! Number should in range of (1 to 100) only.\n";
}
//read one number per loop iteration
for( int i = 0; i < n; i++ )
{
std::ostringstream prompt;
prompt << "Enter number #" << i + 1 << ": ";
nums[i] = get_int_from_user( prompt.str() );
sum += nums[i];
}
std::cout << "Average: " << sum / n << '\n';
}
int get_int_from_user( const std::string& prompt )
{
std::string line;
std::size_t pos;
int i;
//repeat forever, until an explicit return statement or an
//exception is thrown
for (;;) //equivalent to while(true)
{
//prompt user for input
std::cout << prompt;
//attempt to read one line of input from user
if ( !std::getline( std::cin, line ) )
{
throw std::runtime_error( "unexpected input error!\n" );
}
//attempt to convert string to integer
try
{
i = std::stoi( line, &pos );
}
catch ( std::invalid_argument& )
{
std::cout << "Unable to convert input to number, try again!\n";
continue;
}
catch ( std::out_of_range& )
{
std::cout << "Out of range error, try again!\n";
continue;
}
//The remainder of the line is only allowed to contain
//whitespace characters. The presence of any other
//characters should cause the entire input to get rejected.
//That way, input such as "6sdfj23jlj" will get rejected,
//but input with trailing whitespace will still be accepted
//(just like input with leading whitespace is accepted by
//the function std::stoi).
for ( ; pos < line.length(); pos++ )
{
if ( !std::isspace( static_cast<unsigned char>(line[pos]) ) )
{
std::cout << "Invalid character found, try again!\n";
//we cannot use "continue" here, because that would
//continue to the next iteration of the innermost
//loop, but we want to continue to the next iteration
//of the outer loop
goto continue_outer_loop;
}
}
//input is valid
return i;
continue_outer_loop:
continue;
}
}
This program has the following behavior:
How many numbers will you input? 200
Error! Number should in range of (1 to 100) only.
How many numbers will you input? -31
Error! Number should in range of (1 to 100) only.
How many numbers will you input? test
Unable to convert input to number, try again!
How many numbers will you input? 4abc
Invalid character found, try again!
How many numbers will you input? 4
Enter number #1: 1
Enter number #2: 2
Enter number #3: 3
Enter number #4: 4
Average: 2.5
As you can see, it now correctly rejects the input 4abc.
I believe that using the function get_int_from_user makes the code in main much cleaner.
Note that the code above uses one goto statement. Under most circumstances, you should avoid using goto, but for breaking out of nested loops, it is considered appropriate.
#include <iostream>
#include <limits>
using namespace std;
int avg(int sum, int n)
{
int average;
average = sum/n;
cout<<"Avg = "<<average;
}
int main()
{
int n;
cout << "how many numbers will you input?: ";
cin >> n;
int w = n;
int num[w];
int sum;
while(n>100||n<=0)
{
cout << "Error! number should in range of (1 to 100) only." << endl;
cout << "Enter the number again: ";
cin >> n;
}
for(int i = 0; i < n; ++i)
{
cout << i + 1 << "Enter number: ";
cin >> num[i];
if(!cin)
{
cout << "Wrong Choice. " << endl;
cin.clear();
cin.ignore( numeric_limits<std::streamsize>::max(), '\n' );
n++;
continue;
}
else
{
sum += num[i];
}
}
cout<<"Sum = "<<sum<<endl;
avg(sum,w);
}

Console is being flooded when error checking for things that are not an int

I'm trying to only allow integer values into my program, so I've made the following function. The function is similar to other ones I've seen online, and mine seems to work just fine up until I add an ! in front of it to check if something is not an int.
Function to check if input is an integer:
bool isInteger(std::string s)
{
for (int i = 0; i < s.length(); i++)
{
if (isdigit(s[i]) == false)
{
return false;
}
return true;
}
}
Function being put to use:
int getLevel()
{
int level;
std::cout << "Level One\n";
std::cout << "Level Two\n";
std::cout << "Level Three\n";
std::cout << "Level Four\n";
std::cout << "Level Five\n";
std::cout << "Enter your level (1-5): ";
std::cin >> level;
while (!isInteger(std::to_string(level)) || level < 1 || level > 5)
{
std::cout << "Enter an integer value between 1-5 inclusive: ";
std::cin >> level;
}
clrscr();
return level;;
}
I believe the function works just fine until I put the ! in front of it. I am trying to only allow integer input into my program, and when I enter a double or string, the console becomes flooded with the message "Enter an integer value between 1-5 inclusive: " and doesn't give any time to enter an input. I am fairly new to c++ programming and could use some advice. Thank you!
std::cin >> level;
will try to read an integer and it will never read anything other than an integer. If this fails std::cin's failbit is set and further input operations (like std::cin >> level; inside the loop) are skipped.
You need to check if the reading succeeded and ignore the current input if not. Like this for example:
std::cout << "Enter your level (1-5): ";
while(!(std::cin >> level) || level < 1 || level > 5) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Enter an integer value between 1-5 inclusive: ";
}
As little semi-related hint: level will always be an integer. Converting it to a string will always be the string-representation of an integer, so isInteger(std::to_string(level)) will always be true, unless level is negative, because you don't check for the sign.
Also that return true; in isInteger must be outside the loop, else you only check the first character.
Thanks to all the replies and clarification, I've managed to come up with a solution of my own.
New isInteger function that now checks for everything that is needed including inputs like "0004" that a user suggested above:
bool errorCheck(std::string s)
{
int intLevel;
std::stringstream tempLvl(s);
tempLvl >> intLevel;
for (int i = 0; i < s.length(); i++)
{
if (isdigit(s[i]) == false || s[0] == '0' || intLevel < 1 || intLevel > 5)
{
return false;
}
}
return true;
}
The method in action:
std::cout << "Enter your level (1-5): ";
std::cin >> stringLevel;
while (!errorCheck(stringLevel))
{
std::cout << "Enter an integer value between 1-5 inclusive: ";
std::cin >> stringLevel;
}
std::stringstream lvl(stringLevel);
lvl >> level;
clrscr();
return level;
}
Please let me know if you spot any problems with the code or have any easier solutions. Thanks for all the help!
ok i am gonna tell u the fact that console input extracts the input from console so if u ever tried to do something like that
i.e read string in place of integer the cin is going to be in bad state you can check this fact by putting an if like this
if(!cin>>level) break;
and u will find it working actually stream takes input from the console and convert it to boolean value so u can always check it's state bad state return false else true...... ..
SO,finally the bug is in cin>>level...
I hope u understood.... also check out that return true statement..
i am gonna put u reference link for more answer on this bug...
user enters String instead of Int

C++ mystical infinite loop

I just started learning C++ after previously coding with Java. The code below takes input from the user and validates the input. The first piece asks for the number of voters, which must be a positive number. If I enter a negative number the program behaves as I expected. It prints out the error message and asks for the input again. However, if I enter any other character, such as any alphabet letter I get an infinite loop in the console, asking for input and printing the error message. What am I doing wrong?
my code:
#include <iostream>
using namespace std;
struct dataT {
int numOfVoters = -1;
float preSpread = -1;
float votingError = -1;
};
void getUserInfo() {
dataT data;
while (data.numOfVoters == -1) {
cout << "enter the number of voters" << endl;
cin >> data.numOfVoters;
if (data.numOfVoters <= 0) {
data.numOfVoters = -1;
cout << "Invalid entry, please enter a number larger than zero." << endl;
}
}
while (data.votingError == -1) {
cout << "enter the percentage spread between candidates" << endl;
cin >> data.votingError;
if (data.votingError <= 0 || data.votingError >= 1) {
data.votingError = -1;
cout << "Invalid entry. Enter a number between 0 to 1." << endl;
}
}
while (data.preSpread == -1) {
cout << "Enter the precentage spread between the two candidates." << endl;
cin >> data.preSpread;
if (data.preSpread <= 0 || data.preSpread >= 1) {
data.preSpread = -1;
cout << "Invalid input. Enter a number between 0 and 1." << endl;
}
}
}
int main() {
getUserInfo();
return 0;
}
Console:
enter the number of voters
f
Invalid entry, please enter a number larger than zero.
enter the number of voters
Invalid entry, please enter a number larger than zero.
enter the number of voters
Invalid entry, please enter a number larger than zero.
...
...
...
If you write cin >> integervariable but in cin there are character that cannot represent an integer, the input fails, !cin becomes true, and the character remain there until you don't reset the input state from the error and consume the wrong characters.
a proper check can be
while(integervariable has not good value)
{
cout << "prompt the user: ";
cin >> integervariable;
if(!cin) //something wrong in the input format
{
cin.clear(); //clear the error flag
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discard the rubbish
cout << "prompt error message \n";
}
}
Your if statements are always true, you want something more like:
if (data.votingError < 0 || data.votingError > 1) {
...
then data.votingError can take on a value different from -1 and exit your loop.
The std::cin object will check whether or not it is in a valid state every time it reads. If you enter a char where your program expects an int, then you'll "break" the input stream. All subsequent calls to std::cin will then be effectively skipped until you manually reset the input stream. When this happens, you'll never be able to set your values to anything other than -1, and your if statement always evaluates to true, causing an infinite loop.
As an aside, you can check for failure state by including && cin in all of your tests. Input objects implicitly evaluate to true if the stream is in a valid state and to false if the stream is in a failure state instead.

How can I check if the user has entered valid value?

I'm writing a project and I have to check if the user has entered a valid value for specific things. For example, first case is to check whether he inputted an integer, which is no longer than 6 length and >0. I am working with struct, so my code is this:
#include <iostream>
using namespace std;
int dolzina_int(int vlez);
int main()
{
struct pole{
int sifra; // sifra na artiklot
string opis; // opis na artiklot
float cena; // edinecna cena
int vlez_kol; // vlezna kolicina
int izlez_kol; // izlezna kolicina
float dan_stapka; // danocna stapka
float iznos; // iznos
int datum; // datum na vlez i izlez (GGMMDD)
}artikli[100]; // maksimalen broj na artikli e 100
for (int i = 0; i < 5; i++){
cin >> artikli[i].sifra;
while(!(cin >> artikli[i].sifra) ||
(artikli[i].sifra < 0 || (dolzina_int(artikli[i].sifra) > 6)))
{
cout << "Error" << endl;
cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
return 0;
}
// funkcija za dolzina na integer
int dolzina_int(int vlez){
int dolzina = 1;
while(vlez > 0){
dolzina++;
vlez /= 10;
}
return dolzina;
}
So, my code seems to work, the first part, it does check if it's >6 or <0, but the second else if, it doesn't work properly to check if it's an integer or not. So my question is the following, how can i make sure that it's an integer value that the user enters and how can I make sure the length of integer is not >6 or the value is <0 and meanwhile, if it is, to make him re-enter it, and also check the newly entered value, as my code doesn't do that currently.
for (int i = 0; i < 5; i++){
artikli[i].sifra = 1;
do{
cout << "Enter a code: ";
while(!(cin >> artikli[i].sifra)){
cin.clear();
cin.ignore();
cout << "Invalid entry. Enter a new value: ";
}
}while(artikli[i].sifra > 0 && dolzina_int(artikli[i].sifra) > 6);
}
You should note that the extraction will only succeed if the contents read from the file can be used as a correct value of the type of the object (in this case the integer sifra). If it doesn't work, ios_base::failbit will be set in the stream state.
So what needs to be done is that when an incorrect value is given, we discard the wrong text, clear the stream state, and re-try the extaction. For example:
#include <iostream>
#include <string>
#include <limits>
int main()
{
for (int i = 0; i < 5; ++i)
{
while (!(std::cin >> artikli[i].sifra) ||
((artikli[i].sifra < 0) || (artikli[i].sifra > 6)))
{
std::cout << "Entered an incorrect value, try again.\n";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
// ...
}
}
First you should check this out:
http://www.cplusplus.com/reference/cctype/
Second, I think your over complicating it...
1) Read in int
2) check value of int
3) repeat
So I would do this
for (i = 0 to i < 5 add one to i)
while (entered value is not digit)
get digit until value is valid
Something like this:
for(i = 0; i < 5; i++) {
cout << "Enter the code" << endl;
cin >> artikli[i].sifra;
while(!is_digit) {
cout << "Invalid, please repeat" << endl;
cin >> artikli[i].sifra;
}
}
Assuming you want to restrict your input to integers and have them in a specific [min, max] range, you would do it like this:
int input = -1;
do
{
std::cout << "Enter a value in the range [min, max]: ";
while (!(std::cin >> input)) // while the input is invalid
{
std::cin.clear(); // clear the fail bit
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // ignore the invalid entry
std::cout << "Invalid Entry! Please Enter a valid value: ";
}
} while (min > input || max < input);
Where min and max are whatever values you are looking to keep the value between.

go back to first instruction when there is an error

I am creating a simple console application that obtain user input which is an integer.
I want the condition so that it should only be an integer and it should be not more than 3 and not less than 0.
The code i came up so far is:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main()
{
int uinval;
while (true) {
string tempoval;
cout << "Please enter a value between 0-3:\n>";
cin >> tempoval;
stringstream ss(tempoval);
if (ss >> uinval)
{
break;
cout << "Entered an invalid value";
}
while (true)
{
if (uinval < 0 || uinval > 3)
break;
cout << "Value must be between 0-3";
}
cout << "You have entered:" << uinval;
return 0;
}
This works when I input a non-integer value like a,b,c,d. But it does not work when i input -1 or 4 as value.
I am not sure, maybe I confused myself with the while loops.
This is incorrect:
while(true){
if(uinval < 0 || uinval > 3)
break;
cout <<"Value must be between 0-3";
}
You check the condition on uinval repeatedly, without giving user a chance to enter a new value.
To fix the problem, remove the second loop, and replace
if(ss >> uinval) {
break;
}
inside the first loop with
if(ss >> uinval && uinval >= 0 && uinval < 4) {
break;
}
You have your if statement holding the opposite of what you want it to.
Right now if the value is under 0 or over 3, it'll break and continue. You want it to continue if it's over 0 and under 3.
if(uinval > 0 && uinval < 3)