Stuck in an infinite loop when validating user input as an int - c++

So I'm displaying a menu using a do while loop as shown below, and I want the user to be prompted with the menu until they make a valid selection- by entering the digits 1, 2, 3 or 4. I then want to use a switch case statement for identifying the users choice and executing the relevant block of code. When it comes to input validation though, how can I account for the user entering a letter instead of a numerical digit? The below code successfully continues to the next iteration to reprompt the user when they enter a letter, except that it enters a continuous loop.
int selection;
do{
cout << "Which option would you like to select? (select 1, 2, or 3)";
cout << "1: Option 1" << endl;
cout << "2: Option 2" << endl;
cout << "3: Option 2" << endl;
if(!(cin >> selection)){
cout << "Please select an integer from 1-4." << endl;
cin.clear()
}
}while(selection != (1) or (2) or (3) or (4));
I've tried inserting the code below using istringstream to stream the users response from a string into an int inside the while loop as an alternative method to try solving the problem but to no avail.
string temp;
cin >> temp;
clearInputBuffer();
istringstream is(temp);
is >> selection;
UPDATED CODE - still getting an infinite loop (only when the user enters an alphabetic
character; integers behaveas expected)
int selection;
do{
cout << "Which option would you like to select? (select 1, 2, or 3)";
cout << "1: Option 1" << endl;
cout << "2: Option 2" << endl;
cout << "3: Option 2" << endl;
if(std::cin >> selection){
cout << "Enter the new price: ";
}
else if(!std::cin.eof()){
cout << "Please select an integer from 1-4." << endl;
cin.clear();
}
}while(selection != 1 && selection != 2 && selection != 3 && selection != 4);

while(selection != (1) or (2) or (3) or (4));
is syntactically valid although you most probably wanted
while(selection != 1 && selection != 2 && selection != 3 && selection != 4);
Your original expression is equivalent to
while((selection != 1) || (2) || (3) || (4))
(2), (3), and (4) are evaluated to true, which makes your loop infinite, because anything || true is true.
If anyone should be wondering, yes, C++ allows writing and instead of && and or instead of ||, and not instead of !, etc. You have to "Disable Language Extensions" to see this on MSVC.
[update]
Another problem is that in case of a non-integer input, the variable selection stays uninitialized. In the else clase, give it a value of -1, for example.

The obvious approach is to actually check that the input was successful and if that is not the case deal with the error, e.g., write an error message, clear the stream, ignore the character or line, and try again:
if (std::cin >> selection) {
// do something with the good selection
}
else if (!std::cin.eof()) {
std::cin.clear();
std::cout << "invalid character ('" << char(std::cin.get()) << "') ignored\n";
}
Your code checks the stream and clears it but it doesn't extract the offending character. By the time you get to the check whether the selection is in range things are already bad and will stay that way.
You'd than go on and check the range. Your approach doesn't quite work as the logic or operator evaluates each individual element. One way is to check if the entered value is member of a specific rnage, e.g., using
int const valid[] = { 1, 2, 3, 4 };
if (std::end() == std::find(std::begin(valid), std::end(valid), selection)) {
std::cout << "chosen invalid selection (" << selection << ")\n";
}
The alternative of checking each selection individually may be viable for a small number of selection but isn't really viable when the range of options grows bigger. Admittedly, once you have a bigger range of options you'd actually put the key and the operation together anyway:
std::unordered_map<int, std::function<void()>> actions;
bool done = false;
// set up different operations for the respective actions, e.g.:
actions.insert(std::make_pair(1, [](){ std::cout << "hello, world\n"; }));
actions.insert(std::make_pair(2, [&](){ done = true; std::cout << "goodbye\n"; }))
int selection;
if (std::cin >> selection) {
auto it = actions.find(selection);
if (it != actions.end()) {
(it->second)();
}
else {
std::cout << "unknown action selection " << selection << '\n';
}
}

Try this
while(selection != (1) and selection != (2) and selection != (3) and selection != (4));

selection != (1) or (2) or (3) or (4)
Non-zero integers will evaluate to true so this is the equivalent of:
(selection != (1)) or true or true or true
which will always evaluate to true.
The way to fix this is to compare each individually
while(selection != 1 && selection != 2 && selection != 3 && selection != 4)

(2), (3, (4) are always true, that's why you are stuck in an infinite cicle. try:
while(selection != 1 && selection != 2 && selection != 3 and selection != 4);

A Shorter version:
while (selection <= 4 && selection >= 1)

I got it to work, the update provided in the original post was missing one extra line of code which I identified from sifting through other questions regarding validating input in a while loop. I think #Dietmar Kühl tried to illustrate something similar in his suggestion, however my compiler didn't like the code and I didn't quite understand it so I wasn't sure how to make it work. I'll be playing around with your suggestion regarding validating against a range though Dietmar so thank you for your input.
Thanks also to everyone who contributed to this thread, especially the 99% of you that did so without sounding condescending :-) There's always one though. The thread from which I identified my missing statement can be found here, and the line added to the code is identified with a comment in the code below. Thanks again!
int selection;
do{
cout << "Which option would you like to select? (select 1, 2, or 3)";
cout << "1: Option 1" << endl;
cout << "2: Option 2" << endl;
cout << "3: Option 2" << endl;
if(std::cin >> selection){
cout << "Enter the new price: ";
}
else if(!std::cin.eof()){
cout << "Please select an integer from 1-4." << endl;
cin.clear();
cin.ignore(10000,'\n'); // this line eliminated the infinite loop issue
}
}while(selection != 1 && selection != 2 && selection != 3 && selection != 4);

Related

How to limit user input in C++ for strings & characters?

I'm trying to create a small restaurant program in which I'll be practicing everything I learned in C++ so far. However I jumped into a small issue. At the beginning of the program, I prompt the user whether they want to enter the program, or leave it by choosing Y or N. If the input is anything other than that the program will tell the user is invalid.
The issue is lets say the user input one invalid character a.
The invalid output will be displayed normally and everything seems perfect.
But if the user inputs two characters, or more, the invalid output case will be printed as many as the characters input by the user. Sample below:
Output image
#include <iostream>
int main()
{
char ContinueAnswer;
std::string Employee {"Lara"};
std::cout << "\n\t\t\t---------------------------------------"
<< "\n\t\t\t| |"
<< "\n\t\t\t| Welcome to OP |"
<< "\n\t\t\t|Home to the best fast food in Orlando|"
<< "\n\t\t\t| |"
<< "\n\t\t\t--------------------------------------|" << std::endl;
do
{
std::cout << "\n\t\t\t Would you like to enter? (Y/N)"
<< "\n\t\t\t "; std::cin >> ContinueAnswer;
if(ContinueAnswer == 'y' || ContinueAnswer == 'Y')
{
system("cls");
std::cout << "\n\t\t\t My name is " << Employee << "."
<< "\n\t\t\tI will assist you as we go through the menu." << std::endl;
}
else if(ContinueAnswer == 'n' || ContinueAnswer == 'N')
{
std::cout << "\t\t\t\tGoodbye and come again!" << std::endl;
return 0;
}
else
std::cout << "\n\t\t\t\t Invalid Response" << std::endl;
}
while(ContinueAnswer != 'y' && ContinueAnswer != 'Y')
Thank you for taking time to read and for anyone who answers :)
You could simply make the user input a string:
std::string ContinueAnswer;
and compare like this:
if(ContinueAnswer == "y" || ContinueAnswer == "Y")
which will handle multi-character inputs.
If you want to handle spaces in the input as well, change the:
std::cin >> ContinueAnswer;
to:
std::getline(std::cin, ContinueAnswer);
Before addressing your question I need to point out that you should always verify that the input was successful before doing anything with it. Processing variables which were not set due to the inout failing is a rather common source of errors. For example:
if (std::cin >> ContinueAnswer) {
// do something with successfully read data
}
else {
// deal with the input failing, e.g., bail out
}
I assume you consider everything on the same line to be invalid if nine of the expected characters was read. You could read a line into an std::string. However, that could be abused to provide an extremely long line of input which would eventually crash your program. Also, reading data into a std::string just to throw it away seems ill-advised. I’d recommend ignoring all characters up to and including a newline which could be done using (you need to include <limits> for this approach):
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), ‘\n’);
The first argument is a special value indicating that there may be an arbitrary amount of character before the newline. In practice you could probably use a value like 1000 and it would be fine but it can be gamed. Of course, in a real application a dedicated limit may be used to prevent an adversary to keep the program busy for long. I tend to assume my programs are under attack to make sure I deal with unusual cases.
A quick refactor produces this:
#include <iostream>
#include <cstring>
#include <stdio.h>
int main()
{
char ContinueAnswer[256];
std::string Employee {"Lara"};
std::cout << "\n\t\t\t---------------------------------------"
<< "\n\t\t\t| |"
<< "\n\t\t\t| Welcome to OP |"
<< "\n\t\t\t|Home to the best fast food in Orlando|"
<< "\n\t\t\t| |"
<< "\n\t\t\t--------------------------------------|" << std::endl;
do
{
std::cout << "\n\t\t\t Would you like to enter? (Y/N)"
<< "\n\t\t\t "; std::cin.getline(ContinueAnswer,sizeof(ContinueAnswer));
if(strcmp(ContinueAnswer, "Y") == 0 || strcmp(ContinueAnswer, "y") == 0)
{
system("cls");
std::cout << "\n\t\t\t My name is " << Employee << "."
<< "\n\t\t\tI will assist you as we go through the menu." << std::endl;
}
else if(strcmp(ContinueAnswer, "N") == 0 || strcmp(ContinueAnswer, "n") == 0)
{
std::cout << "\t\t\t\tGoodbye and come again!" << std::endl;
return 0;
}
else
std::cout << "\n\t\t\t\t Invalid Response" << std::endl;
}
while(true);
}
The cin.getline will get all characters until a delimiter. Then, you can check for equivalence using strcmp and reject anything other than what you want. Lastly, it seems like you are wanting this to be in an infinite loop, so don't worry about checking the input at the end and just loop back.

Safe [Y/N]; [1/2/3/etc.] function

I tried to make a an introduction to a "game", and in its functions I made some Yes/No, 1/2/3, situations.
Im new to this however it wasn't that difficult, worked perfectly. The problem appeared when handling with invalid inputs. So this is what the code looks like by now:
#include "Introduction.h"
#include "GameConstants.h"
#include "PlayerCharacter.h"
#include <iostream>
#include <windows.h>
using namespace std;
Introduction::Introduction()
{
}
/////////Function N.1///////////
void Introduction::presentation()
{
char confirm;
string enteredName;
cout << constants.line() << "Welcome traveler! What is the name?" << endl;
getline(cin,enteredName);// Gets the WHOLE LINE as the name.
while (confirm != 'Y') //If the player doesn't confirm the name with 'Y' in will run again until it does.
{
cout << constants.xline() << "Your name is " << enteredName << " right? (Y/N)" << endl;
cin >> confirm; //The player's answer
cin.sync(); //Only takes the first character
confirm = toupper(confirm); //Turns player message into CAPS for easier detection in the "if" statements
if (confirm == 'N'){ //If not the correct name, gives another chance
cout << constants.xline() << "Please, tell me your name again..." << endl;
cin >> enteredName;
cin.sync();}
if ((confirm != 'Y')&&(confirm != 'N')){ //If an invalid input is entered, gives another chance. And insults you.
cout << constants.xline() << "Fool Go ahead, just enter your name again." << endl;
cin >> enteredName;
cin.sync();}
}
if (confirm == 'Y'){ //When the answer is yes ('Y') /* Uneeded line */
PC.setName(enteredName); //Saves the name
cout << constants.xline() << "Excellent! I have a few more questions for you " << PC.name() << "..." << endl;
}
}
//////////Function N.2///////////
void Introduction::difSelection(){
int selectedDif = 0; //Variable to store selected difficulty whitin this function.
Sleep(2500);
cout << constants.xline() << "What kind of adventure do you want to take part in?" << endl;
Sleep(2500); //Wait 2,5 s
cout << "\n1= Easy\n2= Normal\n3= Hard" << endl;
while(selectedDif != 1&&2&&3){ //Selected option must be 1/2/3 or will run again
cin >> selectedDif; //Sets the user selected difficulty
cin.sync(); //Gets only first character
if((selectedDif != 1||2||3)&&(!(selectedDif))){ //If the input isn't 1/2/3 AND is an invalid character, this will run. And it'll start again
cout << constants.xline() << "Criminal scum. Go again." << endl;
cin.clear();
cin.ignore();
}
if(selectedDif != 1&&2&&3){ //If selected option isn't 1/2/3, this will run and will loop again. However I know this conflicts with the previous statement since this will run anyways.
cout << constants.xline() << "Wrong input, please try again." << endl;
}
else if(selectedDif == 1){
constants.setDiff(1);
constants.setStatPoints(15);
} else if(selectedDif == 2){
constants.setDiff(2);
constants.setStatPoints(10);
} else if (selectedDif == 3){
constants.setDiff(3);
constants.setStatPoints(5);}
}
}
The first function works perfectly you can type "aaa" or "a a a" and will work. However I'd like to know if there's a simpler way to do it. (Understandable for a beginner, just started 3 days ago lol; if it includes some advanced or less known code prefer to stay like this by now).
Now, the second one, I really have no idea how to fix it. I need something that if the user's input was an invalid character type, throw certain message, and if it's an int type, but out of the range, another message. And of course, run again if it fails. Did a lot of search and couldn't find anything that meet this requirements.
To check if the user input is an int, you could use the good() function.
int val;
cin >> val;
if( cin.good() ) {
// user input was a valid int
} else {
// otherwise
}
As for the range check, the syntax is a bit different.
This returns true if the number is not equal to 1 nor 2 nor 3:
selectedDif != 1 && selectedDif != 2 && selectedDif != 3
Another shorter way would be to use:
selectedDif < 1 || selectedDif > 3
Another thing, in c++, there are two keywords break and continue which will allow to reduce the code in the loops.

C++ Checking Against Particular Numbers

Hello Dear Programmers,
I've been working on a piece of code for a while, but I don't seem to figure this out, i'm trying so hard to check an input with a specific number, but so far it ends up not working and even when number 2,3, or 4 is pressed the error message pops up, and I go to my if else condition. here are the codes, number_of_bedrooms is an integer.
out << "Number Of Bedrooms: (Limited To 2,3, and 4 Only)" << endl;
if (isNumber(number_of_bedrooms) == false ) {
cout << "Please Do Enter Numbers Only" << endl;
cin.clear();
}
else if (number_of_bedrooms != '2' || number_of_bedrooms != '3' || number_of_bedrooms != '4') {
cout << "Numbers Are Only Limited To 2,3, And 4" << endl;
cin.clear();
}
and the function :
bool isNumber(int a)
{
if (std::cin >> a)
{
return true;
}
else
{
return false;
}
}
the first validation which checks for numbers works fine, but the second validation no, my guess is the system is not capturing inputted data after that boolean function. And if that's the reason, what's the solution ?!!
Change your || to &&, also you need to compare to int not char
else if (number_of_bedrooms != 2 && number_of_bedrooms != 3 && number_of_bedrooms != 4)
Note that a more general way to solve such a problem (for example if your list got much longer) would be to do something like
std::set<int> const allowableBedrooms = {2,3,4};
else if (allowableBedrooms.find(number_of_bedrooms) == allowableBedrooms.end())
{
// Warn user here
}
As your goal conditions are sequential, I'd use something like this:
else if ( number_of_bedrooms < 2 || number_of_bedrooms > 4 ) {
cout << "Numbers Are Only Limited To 2,3, And 4" << endl;
cin.clear();
}
This is very clear and easy to manage if you want to change it. If you want to enumerate everything you'll need to use && instead of || since your want it to both be not 2 and not 3 and not 4 to trigger the issue.
Another problem in your code is that you're comparing against characters by putting the numbers in single quotes. Since these are integers you should not have them in quotations.
You have to change your function to make the change out of the local function like this:
bool isNumber(int * a)
{
if (std::cin >> * a)
{
return true;
}
else
{
return false;
}
}
And then call the function with the address of number_of_bedrooms like this:
out << "Number Of Bedrooms: (Limited To 2,3, and 4 Only)" << endl;
if (isNumber(&number_of_bedrooms) == false ) {
cout << "Please Do Enter Numbers Only" << endl;
cin.clear();
}
else if (number_of_bedrooms < 2 || number_of_bedrooms > 4) {
cout << "Numbers Are Only Limited To 2,3, And 4" << endl;
cin.clear();
}
Check the code above becouse i took off the '' that means you are comparing number_of_bedrooms (int) with '2' (char) so it will be always true.
The condition i wrote would be better then becouse you are considering an interval of numbers, if you are considering the specific numbers you can leave your condition but you should change the logical operator in && and chain with the other != conditions

How do i stop a while loop and go to my other statements?

I want to make a program that tracks the number of CDs sold. And i want to know which is the best seller. The CD's are categorized as Alternative music classical, country, dance, pop, rock and R&B
I made a menu driven program that will display the music genres but
here's my problem: I don't know how can the user could continue on inputting the number of the genres of music sold until he wants to stop it. And after he stops how can he report on how many CDs were sold for each genre? Basically the user will continue on counting the number of CD's sold until he wants to stop the sales.
#include<iostream>
using namespace std;
int main ()
{
int counter = 1;
int result, Alternative = 0, Classical = 0, Country = 0, Dance = 0, Pop = 0, Rock = 0, RnB = 0;
cout << "Choose the music genre sold (Only choose the numbers): \n1. Alternative\n";
cout << "2. Classical\n3. Country\n4. Dance\n5. Pop\n6. Rock\n7. R&B\n\t\t\t\t\t\t\t";
while (counter <= 100)
{
cin>>result;
if(result == 1)
{
Alternative = Alternative + 1;
}
else if(result == 2)
{
Classical = Classical + 1;
counter++;
}
else if(result == 3)
{
Country = Country + 1;
counter++;
}
else if(result == 4)
{
Dance = Dance + 1;
counter++;
}
else if(result == 5)
{
Pop = Pop + 1;
counter++;
}
else if (result == 6)
{
Rock = Rock + 1;
counter++;
}
else if (result == 7)
{
RnB = RnB + 1;
counter++;
}
cout<<"\nAlternative:"<<Alternative;
cout<<"\tClassical:"<<Classical;
cout<<"\tCountry: "<<Country<<"\n";
cout<<"Dance: "<<Dance;
cout<<"\tPop: "<<Pop;
cout<<"\tRock: "<<Rock;
cout<<"\tR&B: "<<RnB<<"\t\t\t";
}
}
EDIT:
Thanks #timrau and #sfjac for the break, switch and variable++ suggestions.
Instead of making the while loop stop after a fixed number (100) of iterations[1], you could ask the user to enter a specific character or number when he is done.
Consider the following code, for example:
// assume you have already declared and initialized all the required variables, as in your example.
// for now we will say that this is -1, so that it doesn't count as a valid option, and so it passes our while's condition.
int result = -1;
while (result) // condition evaluates to FALSE if user enters zero.
{
// print out the menu.
cout << "The menu goes here... " << endl
<< "Press 0 (zero) when you are done.";
// get the input.
cin >> result;
// use switch to check against constant values. Its cleaner.
switch (result)
{
case 1: Alternative++; // For incrementing variables, use the ++ operator.
break;
case 2: Classical++;
break;
// and so on, for all your choices.
// And then,
default: cout << "Oops! That wasn\'t a valid choice. Try again..." << endl;
}
}
// now the user is done, and has entered 0.
cout << "\nAlternative: " << Alternative
<< "\tClassical: " << Classical
<< "\tCountry: " << Country << "\n"
<< "Dance: " << Dance
<< "\tPop: " << Pop
<< "\tRock: " << Rock
<< "\tR&B: " << RnB << "\t\t\t";
// and yes, you can fold your cout like that, so you don't have to type "cout" every time.
Hope that was of some help :-)
[1] An iteration is each time a loop repeats (Iteration on Wikipedia).
So add quit option to your cout:
cout << "2. Classical\n3. Country\n4. Dance\n5. Pop\n6. Rock\n7. R&B\n8. quit
Add new condition (switch is better option here) in your while loop:
else if(result == 8) {
break;
}
Also in your first if, you should increment choice i.e. in case of alternative. Best would be incrementing choice after you read the value just once instead of duplicating in every conditions.
And your cout that prints genre's within while loop should be post end of while loop i.e. before last brace i.e. end of main.
while (counter <= 100 || result == -1)
{...}
you can prompt the user to type -1, if they're finished.
Or else, you may use a switch, for example:
bool stop = false;
while (counter <= 100 || stop)
{
switch(result)
{
case 1: ...;
case 2: ...;
.
.
.
default:
stop = true;
}
}
if the user enters a value other than [1, 7], it will exit the loop.
Allow the user to thell you that he's finished with the input:
//...
cout << "...7. R&B\n999.End input \t\t\t\t\t\t\t";
do {
// all your statements
} while (result!= 999);
Personally, I'd start the numbering with 0 for end of input and then the rest of the possible choices. The user could quickly see how to stop and then you could write while (result). But that's matter of taste.
Some other suggestions:
Consider switch instead of your long if...else ... chain. Or better here, consider using an array to avoid repetitive code:
int genre[8]={}; // create ainitalised array
//... as above
do {
cin>>result;
if (result>=0 && result<8) {
genre[result]++;
counter++;
}
else if (result!=999)
cout <<"Wrong value entered!\n";
} while (result!= 999);

While statement won't stop

I have a while statement that keeps repeating the text without giving the user a chance to input another value for action. What am I doing wrong? It still doesn't ask for input. I need for the code to display the text once, then ask for input. Presumably, if you typed anything but 1 it would repeat the sequence. But as it stands it simply kicks you out of the loop without the chance to correct the action (As of the last edit, see below.)
int action = 0;
while (action != 1)
{
cout << " No you must look it might be dangerous" << endl;
cin >> action;
}
One suggestion was:
while (action != 1)
{
cout << " No you must look it might be dangerous" << endl;
cin >> action;
cin.ignore();
}
That still produces text over and over.
while (action != 1)
{
cout << " No you must look it might be dangerous" << endl;
if (!(cin >> action))
// ...problems in the I/O stream...
break;
}
This one kicks you out without a chance to input a new action.
If you type a character that is not white space and can't be part of an integer, then you have an infinite loop. Each attempt to input to action fails on the invalid character without changing the value stored in action.
You could write:
int action = 0;
while (action != 1)
{
cout << " No you must look it might be dangerous" << endl;
if (!(cin >> action))
// ...problems in the I/O stream...
break;
}
This will handle EOF and alphabetic characters more gracefully than a continuous loop. You might need to set a flag or return an error condition from the function or do something else other than break out of the loop. Always check your inputs for success.
You might also consider outputting the value you're getting stored in action in the loop, so you can see what is happening:
int action = 0;
while (action != 1)
{
cout << " No you must look it might be dangerous" << endl;
if (!(cin >> action))
// ...problems in the I/O stream...
break;
cerr << "Action: " << action << endl;
}
This might tell you something useful too.
Please show a complete little program that illustrates your problem — an SSCCE (Short, Self-Contained, Correct Example).
For example, I'm testing with:
#include <iostream>
using namespace std;
int main()
{
int action = 0;
while (action != 1)
{
cout << " No you must look it might be dangerous" << endl;
if (!(cin >> action))
{
// ...problems in the I/O stream...
break;
}
cout << "Action: " << action << endl;
}
cout << "After loop" << endl;
if (!cin)
cout << "cin is bust" << endl;
else
cout << "Action: " << action << endl;
}
That's no longer minimal code — the material after the loop is merely telling me what is happening. But it does help me ensure that my code is doing what I expect.
What does your equivalent code look like, and what are you typing in response to the prompts — and especially, what are you typing before you get to this code fragment (and what other input activity is going on before you get here)?