C++ error with input validation in a do-while loop - c++

I'm creating a very simple number guessing game for a school project and am having trouble with the repeating main menu. I created it using a do-while loop and the problem I'm having is that the menu selection variable is an int, and so when I (or the user) enters a non-int input by accident when selecting from the menu the }while(condition) at the end of the main loop can't catch it and the program repeats infinitely. Conversely if you enter an invalid int at menu selection the program catches it displays the "invalid input" message and then repeats the main menu.
It's kind of hard to explain in writing exactly what I mean so here is the source code with relevant lines denoted with an asterisk. I'm saving as .cpp and am compiling in linux using g++ -ansi -pedantic -Wall -Werror The teacher has forbidden hardcoding in conditional statements hence the global constants.
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
const int PLAY = 1, HIGH_SCORE = 2, EXIT = 3;
const char YES = 'y', NO = 'n';
int main()
{
// Randomly generated value
int randomNumber;
// User input
int userGuess, menuChoice;
char repeat;
// Calculated value
int numberOfGuesses;
// Place-holder values (to be replaced by calculated values)
int score1 = 1000, score2 = 2000, score3 = 3000;
cout << endl << endl;
cout << "Greetings! This is a number guessing game where I think of" << endl
<< "a whole number between one and ten and you try to guess it!" << endl
<< "You can guess as many times as you like, so don't be afraid" << endl
<< "to use trial and error, but your score is based on the " << endl
<< "number of guesses you make (the lower the better) so don't " << endl
<< "guess too haphazardly. Remember, only guess whole numbers!" << endl
<< endl;
do
{
cout << endl << "Main menu." << endl
<< "1. Play game" << endl
<< "2. Display high scores" << endl
<< "3. Exit game" << endl
<< "Please select an option: ";
cin >> menuChoice;
if (cin.fail()){
cout << "Please enter a valid choice" << endl;
continue;
}
cin.ignore();
switch(menuChoice)
{
case PLAY:
do
{
unsigned seed = time(0);
srand(seed);
randomNumber = 1 + rand() % 10;
cout << endl << "Press enter when you're ready to begin!";
cin.ignore();
cout << "Ok I thought of one!" << endl << endl;
numberOfGuesses = 0;
do
{
numberOfGuesses++;
cout << "Enter your guess: ";
cin >> userGuess;
cin.ignore();
// Check user's guess
if (userGuess == randomNumber)
cout << "Correct! That was impressive!" << endl << endl;
else if (userGuess < randomNumber)
cout << "Not quite, you guessed low." << endl << endl;
else if (userGuess > randomNumber)
cout << "Not quite, you guessed high." << endl << endl;
}while (userGuess != randomNumber);
cout << "Your score for this game was " << numberOfGuesses << endl;
// Determine if a high score was beaten
if (numberOfGuesses <= score1)
{
score3 = score2;
score2 = score1;
score1 = numberOfGuesses;
cout << "That's a new all time high score!" << endl;
}
else if (numberOfGuesses <= score2)
{
score3 = score2;
score2 = numberOfGuesses;
cout << "That's a new high score!" << endl;
}
else if (numberOfGuesses <= score3)
{
score3 = numberOfGuesses;
cout << "That's a new high score!" << endl;
}
else
{
cout << endl;
}
cout << "Would you like to play again? y/n: ";
cin.get(repeat);
cin.ignore();
while (tolower(repeat) != YES && tolower(repeat) != NO)
{
cout << endl;
cout << "Sorry, that is an invalid choice." << endl
<< "Please enter 'y' for yes or 'n' for no: ";
cin.get(repeat);
cin.ignore();
}
}while (tolower(repeat) == YES);
break;
case HIGH_SCORE:
cout << endl << "High Score 1: " << score1 << endl
<< "High Score 2: " << score2 << endl
<< "High Score 3: " << score3 << endl << endl;
cout << "Press enter to continue. ";
cin.ignore();
break;
case EXIT:
cout << endl << "Thanks for playing, I'll see you next time!" << endl << endl;
break;
default:
cout << endl << "That is an invalid selection, please enter '1', '2' or '3'"
<< endl;
break;
}
}while (menuChoice != EXIT);
return 0;
}
Code Edited in regards to current answer.
Please let me know if you need anymore information, thanks in advanced!

Use cin.fail() like this (instead of just cin >> menuChoice;) (modelled after this post):
cin >> menuChoice;
if (cin.fail()) {
cout << "Please enter a valid choice" << endl;
cin.clear();
cin.ignore();
continue;
}
//Remove the cin.ignore() at this place!
For more detailed info, see this SO thread

Use a do-while to ensure that the loop body will run at least once.
By using a do-while and prompting a user outside the loop you assume the user wants to play the game once which may not be the case.
A cleaner approach IMO would be use a while loop. Display the menu outside the loop and at the end of the loop. The user will have the choice to exit immediately.
cout << "Greetings.....
cout << menu
// Get menuChoice input here.
while(menuChoice != EXIT){
...
cout << menu //reprompt at end to continue or exit cleanly
// Get menuChoice input here
}
Input Validation is a perfect time to use a do-while
do{
if(!cin){
cout << "Invalid input"
cin.clear()
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}while(!(cin >> menuChoice)) // This gets console input. If fail, loop.
Use numeric_limits<streamsize>::max() to completely clear the
buffer.
Use cin.clear() to reset the fail flag on cin so it wont
always be false.
cin.fail() is fine. However some would consider !cin more natural.

Related

How can I return user to original switch menu from do-while loop?

how can I get user to go back to original switch menu once the user selects N at the end. When user selects N, would I use another loop to get them back to original menu? Any help is greatly appreciated.
cout << "Total Chips: " << chips << endl;
cout << "1) xxxxx" << endl;
cout << "2) xxx" << endl;
cout << "Please enter an option" << endl;
int option;
cin >> option;
switch(option)
{
case 1:
{
char again;
do
{
/* code
*/
cout << "Would you like to play again? Y/N" << endl;
cin >> again;
}while(towlower(again) == 'y'); // I'm not sure whether to use another do-while loop.
When user selects N, would I use another loop to get them back to original menu?
Yes, one that is put around the original menu, eg:
bool keepRunning = true;
do {
cout << "Total Chips: " << chips << endl;
cout << "1) xxxxx" << endl;
cout << "2) xxx" << endl;
cout << "Please enter an option" << endl;
int option;
cin >> option;
switch (option)
{
case 1:
{
char again;
do
{
/* code
*/
cout << "Would you like to play again? Y/N" << endl;
cin >> again;
}
while (again == 'y' || again == 'Y');
break;
}
...
}
}
while (keepRunning);

Verifying User Input as Integer: User has to enter input twice

I am prompting the user to enter an integer value. When the value is incorrect, the program works. However, when the user enters an integer input, the user needs to enter the input twice.
I looked at other tutorials on how to use the while loop to catch erroneous input, and that part worked for me. However, the integer values need to be entered twice in order for the program to run.
#include <iostream>
using namespace std;
int main() {
cout << "*************************************************" << endl;
cout << "******************|DVD Library|******************" << endl;
cout << "*************************************************" << endl;
cout << "1.\tAdd DVD" << endl;
cout << "2.\tDelete DVD" << endl;
cout << "3.\tSearch DVD" << endl;
cout << "4.\tList All DVDs in the Library" << endl;
cout << "5.\tAdd DVD to Favorites List" << endl;
cout << "6.\tDelete DVD from Favorites List" << endl;
cout << "7.\tSearch DVD in Favorites List" << endl;
cout << "8.\tList All DVDs in Favorites List" << endl;
cout << "9.\tQuit" << endl;
cout << "*************************************************" << endl;
int input;
cin >> input;
while (!(cin >> input)) {
cin.clear();
while (cin.get() != '\n')
continue;
cout << "Please enter an integer --> " << flush;
}
if (input < 1 || input > 9) {
cout << "Invalid input! Please try again!" << endl;
}
return 0;
}
You ask for the input twice:
cin >> input;
while(!(cin >> input )){
Removing the first line might make it work you intended.
'The user has to enter the input twice' Look at your code
int input;
cin >> input;
while(!(cin >> input )){
How many times do you ask the user for input?
You'd have more luck with this
int input;
while(!(cin >> input )){
Your error recovery code looks reasonable, haven't tested it though.
int input;
while (cout << "Your choice: ",
!(cin >> input) || input < 1 || 9 < input)
{
cin.clear();
while (cin.get() != '\n');
cerr << "Invalid input! Please try again!\n";
}
Thanks everyone! The "cin >> input;" line was unnecessary. At first, I left it there because it would actually tell the user the error message if the user entered a numeric input such as a double. So, if the user entered something like 3.3, the program would display an error message that I specified ("Please enter an integer" line). However, the program in this case (when there is a double) asks the user to prompt for the integer input twice and then continues the program. When I delete the said unnecessary line, the program accepts a double input, but what it does, it takes the numeric value before the decimal point and uses it as the integer. So, a value of 1.2 is recorded as 1 when I tested it. I'm unsure why this phenomenon happens, but the program works otherwise. Maybe it accounts for human error?
#include <iostream>
using namespace std;
int main() {
cout << "*************************************************" << endl;
cout << "******************|DVD Library|******************" << endl;
cout << "*************************************************" << endl;
cout << "1.\tAdd DVD" << endl;
cout << "2.\tDelete DVD" << endl;
cout << "3.\tSearch DVD" << endl;
cout << "4.\tList All DVDs in the Library" << endl;
cout << "5.\tAdd DVD to Favorites List" << endl;
cout << "6.\tDelete DVD from Favorites List" << endl;
cout << "7.\tSearch DVD in Favorites List" << endl;
cout << "8.\tList All DVDs in Favorites List" << endl;
cout << "9.\tQuit" << endl;
cout << "*************************************************" << endl;
int input;
while (!(cin >> input)) {
cin.clear();
while (cin.get() != '\n')
continue;
cout << "Please enter an integer --> " << flush;
}
if (input < 1 || input > 9) {
cout << "Invalid input! Please try again!" << endl;
}
return 0;
}

C++ Do while loop condition not working

#include<iostream>
#include<ctime>
#include<cstdlib>
using namespace std;
int main(){
int gnumber, rnumber;
char choice;
int tries;
do {
cout << "Welcome to the Number Guessing Game!" << endl;
cout << endl; // breakline
cout << "How many tries: ";
cin >> tries;
cout << endl;
while (tries > 0){
srand(time(NULL));
rnumber = rand() % 99;
cout <<"Enter an integer greater than or equal to 0 and less than 100:";
cin >> gnumber;
system("cls");
if (tries != 1){
if (gnumber < 100 && gnumber >= 0){
if (gnumber == rnumber){
cout << "Congratulations! You've guessed the number." << endl;
tries--;
cout << "Remaining tries: " << tries << endl;
}
else if (gnumber > rnumber){
cout << "Your guess is higher than the number." << endl;
tries--;
cout << " Guess Again!" << endl;
cout << "Remaining tries: " << tries << endl;
}
else{
cout << "Your guess is lower than the number." << endl;
tries--;
cout << " Guess Again!" << endl;
cout << "Remaining tries: " << tries << endl;
}
}
else
cout << "Must greater or equal to 0 and lesser than 100!" << endl;
}
else
{
cout << "Game over!" <<" The number is: " << rnumber << endl;
cout << "Play Again? (Y/N)" << endl;
cin >> choice;
system("cls");
}
}
}while(choice == 'Y' || choice == 'y'); //
system("pause");
return 0;
}
EVEN IF I ENTER CHOICE AS 'N' OR 'n' IT WONT STOP THE LOOP.
And even if I enter 'Y' or 'y', it does not ask how many tries i wanted.
Instead it just asks directly what integer I would want to enter.
Please try to copy and compile the code to further understand what the problem is. Please help.
P.S.: This is a guessing program I'm making by the way...
the bug in your inner loop if the use enters a value other than one in else you don't decrement tries so it gets stuck:
else
{
cout << "Game over!" <<" The number is: " << rnumber << endl;
cout << "Play Again? (Y/N)" << endl;
cin >> choice;
system("cls");
tries--; // add this
}

Switch/Case nonstop looping

I have a menu created where the user has to input a number between 1-5, anytime the user inputs a numeric value it works perfect, it will either go to the specified case or in case of an invalid digit, it will go to default and an error message will appear.
Now my problem is when the user inputs an alphabet letter, the program keeps looping and looping, it won't stop, each time going through the default.
I've tried many things! Using an if statement to check whether the number is 1 <= value <= 5, doesn't work. I tried hard-coding in a number if the input is not between those values, it still loops forever. I tried doing cim.good(), not sure if I did it right, but the way I did it doesn't work. I also tried to use the isdigit() function, but same problem, it doesn't work... I really don't know what I gotta do. Here is what I have (simplified).
int menu()
{
int key;
cout << endl << "--------- Main Menu ----------" << endl;
cout << "1: Sort" << endl << "2: Add" << endl;
cout << "3: Search" << endl << "4: History" << endl << "5: Exit" << endl;
cout << "Please pick one: ";
cin >> key;
return(key);
}`
void main()
{
Menu:
key = menu();
switch(key)
{
case 1:
goto Menu;
case 2:
goto Menu;
case 3:
goto Menu;
case 4:
goto Menu;
case 5:
break;
default:
cout << endl << "Invalid entry, please try again" << endl;
goto Menu;
}
}
I deleted what's inside the cases to make it look nicer. When I type in a key, I keep getting the "Invalid entry, please try again" message, so that's where it is going through.
EDIT: Well I apologize for the 'goto', didn't know it was frown upon, still learning! Thank you everyone for all the help though. I will start removing them for sure.
Rather then using goto, I suggest you use a simple do {} while loop like
#include <iostream>
using namespace std;
int menu() {
int key;
cout << endl << "--------- Main Menu ----------" << endl;
cout << "1: Sort" << endl << "2: Add" << endl;
cout << "3: Search" << endl << "4: History" << endl << "5: Exit" << endl;
cout << "Please pick one: ";
cin >> key;
return(key);
}
int main(int argc, char *argv[]) {
int key;
do {
key = menu();
} while (key < 1 || key > 5);
cout << key << endl;
}
Which loops while the key < 1 or the key > 5.
Have a look at this posting from the C++ FAQ lite and this posting.
Checking with cin.good() is the first part of the solution. If a non integer is entered cin.good() will return false. However, the incorrect input will be left in the buffer. So if you encounter the cin >> key again, it will again fail to read anything.
You have to clear the state using cin.clear() and then ignore the rest of the buffer (until end of line) using cin.ignore(INT_MAX, '\n')
So your method would become:
int menu() {
int key;
cout << endl << "--------- Main Menu ----------" << endl;
cout << "1: Sort" << endl << "2: Add" << endl;
cout << "3: Search" << endl << "4: History" << endl << "5: Exit" << endl;
cout << "Please pick one: ";
while(cin >> key) { // same as querying cin.good()
cout << "Not a number" << endl;
cin.clear();
cin.ignore(INT_MAX, '\n');
}
return(key);
}

Is there a simpler way to loop for error checking and quitting? (C-strings/Character Arrays) [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
I've been writing an assignment where we're tasked with making a shopping cart program that tracks the customer's cumulative price.
I'm not allowed to use strings, global variables, or user defined functions
I'm strictly instructed to use only Character arrays and loops.
While my shopping cart program works fine, I was wondering if there is any way to simplify my code? I feel like I would be penalized for making the code overly complicated. I feel like my quit feature in particular is overly complicated. Is there a better, simpler way of implementing it without using strings or functions?
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
int main()
{
char continueOrQuit;
char productName[900];
float productPrice;
float totalCost = 0;
int productQuantity = 0;
bool validResponse;
cout << "Welcome to SmartCart" << endl;
cout << "Simply enter the name of your product when prompted" << endl;
cout << "After you enter your product, enter the price when prompted \n\n";
//while ((productName[900] != 'D', 'o', 'n', 'e') || (productName[900] != 'd', 'o', 'n', 'e'))
//While im not done shopping
do
{
cout << "Name of Product: "; // Prompt for product
cin.getline(productName, 900); // Get the name
cout << endl;
cout << "Cost of Product: "; // Prompt for product cost
cin >> productPrice; // Get the cost
while ((!cin) || (productPrice < 0))
{
cout << "Invalid Input!! Try again!!" << endl << endl;
cout << "Cost of Product: "; // Prompt again for product cost
cin.clear();
cin.ignore(100, '\n');
cin >> productPrice;
}
cin.ignore(250, '\n'); // Ignore the rest of the garbage
cout << endl;
// if everything is correct, we set up the display and give the results.
cout.setf(ios::fixed, ios::floatfield);
cout.setf(ios::showpoint);
cout.precision(2);
cout << "The item(s) \"" << productName << "\" has/have been added to your cart for $"
<< productPrice << endl;
totalCost = totalCost + productPrice; // Calculating the cumulative sum total
cout << "Your shopping total so far is: $" << totalCost << endl; // Display the sum total
productQuantity++; // Count the number of items in cart
cout << "You have " << productQuantity << " item(s) in your cart." << endl;
// Display the amount of characters in the cart
cout << "To quit shopping, type \"Q\". Otherwise, type \"C\" (Without quotation marks)"
<< endl;
cout << "Would you like to continue shopping? (C/Q) : ";
cin >> continueOrQuit;
cin.ignore(100, '\n');
continueOrQuit = tolower(continueOrQuit);
if (continueOrQuit == 'q')
{
cout << "You have chosen to finish and check out." << endl;
validResponse = true;
}
else if (continueOrQuit == 'c')
validResponse = true;
else
cout << "You have to type either C or Q!" << endl;
validResponse = false;
while (!validResponse)
{
cout << "Would you like to continue shopping? (C/Q) : ";
cin >> continueOrQuit;
cin.ignore(100, '\n');
continueOrQuit = tolower(continueOrQuit);
if (continueOrQuit == 'q')
{
cout << "You have chosen to finish and check out." << endl;
validResponse = true;
}
else if (continueOrQuit == 'c')
validResponse = true;
}
} while (continueOrQuit == 'c');
cout << "Your checkout total is $" << totalCost << endl;
cout << "You are purchasing a total of " << productQuantity << endl;
system("PAUSE");
return 0;
}`
Here a shorter version of your code.
mainly I removed extra code when you check input by putting a do while so the case of wrong input the re-input go back to the first try.
You also have a missing bracket in the last else, it cause you to re-enter q or c in case you already enter it correctly.
Here is the code, you can compare to the original.
int main()
{
char continueOrQuit;
char productName[900];
float productPrice;
float totalCost = 0;
int productQuantity = 0;
bool validResponse;
cout << "Welcome to SmartCart" << endl;
cout << "Simply enter the name of your product when prompted" << endl;
cout << "After you enter your product, enter the price when prompted \n\n";
do
{
cout << "Name of Product: "; // Prompt for product
cin.getline(productName, 900); // Get the name
cout << endl;
do{
cout << "Cost of Product: "; // Prompt for product cost
cin >> productPrice; // Get the cost
if(!cin || productPrice < 0){
cout << "Invalid Input!! Try again!!" << endl << endl;
cin.clear();
cin.ignore(100, '\n');
}
}while ((!cin) || (productPrice < 0));
cin.ignore(250, '\n'); // Ignore the rest of the garbage
cout << endl;
// if everything is correct, we set up the display and give the results.
cout.setf(ios::fixed, ios::floatfield);
cout.setf(ios::showpoint);
cout.precision(2);
cout << "The item(s) \"" << productName << "\" has/have been added to your cart for $"
<< productPrice << endl;
totalCost = totalCost + productPrice; // Calculating the cumulative sum total
cout << "Your shopping total so far is: $" << totalCost << endl; // Display the sum total
productQuantity++; // Count the number of items in cart
cout << "You have " << productQuantity << " item(s) in your cart." << endl;
// Display the amount of characters in the cart
do{
cout << "To quit shopping, type \"Q\". Otherwise, type \"C\" (Without quotation marks)"
<< endl;
cout << "Would you like to continue shopping? (C/Q) : ";
cin >> continueOrQuit;
cin.ignore(100, '\n');
continueOrQuit = tolower(continueOrQuit);
if(continueOrQuit == 'q' || continueOrQuit == 'c')
validResponse = true;
else
{
cout << "You have to type either C or Q!" << endl;
validResponse = false;
}
}while(!validResponse);
if (continueOrQuit == 'q')
{
cout << "You have chosen to finish and check out." << endl;
}
} while (continueOrQuit == 'c');
cout << "Your checkout total is $" << totalCost << endl;
cout << "You are purchasing a total of " << productQuantity << endl;
system("PAUSE");
return 0;
}