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

I am creating a very interesting game for a school project, and I am having problems with re-main menu. I created it using a do-while loop , and the problem I am facing is that the menu selection variable is int , and therefore when I (or the user) a non-int by accident, when you select from the menu }while(condition) at the end of the main loop, it cannot be caught, and the program repeats endlessly. Conversely, if you enter an invalid int when selecting a menu, the program will catch it, display the message "invalid input", and then repeat the main menu.

It is difficult to explain in writing what I mean, so here is the source code with the corresponding lines indicated by an asterisk. I save as .cpp and compile on linux using g++ -ansi -pedantic -Wall -Werror . The teacher forbade hardcoding in conditional statements, therefore, 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 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 a new all time high score!" << endl; } else if (numberOfGuesses <= score2) { score3 = score2; score2 = numberOfGuesses; cout << "That a new high score!" << endl; } else if (numberOfGuesses <= score3) { score3 = numberOfGuesses; cout << "That 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 regarding current response.

Please let me know if you need more information, thanks in advanced condition!

+1
source share
2 answers

Use cin.fail() like this (instead of just cin >> menuChoice; ) (modeled 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! 

See this SO stream for more details.

0
source

Use do-while to ensure that the body of the loop will work at least once.

By using do-while and querying the user outside the loop, you assume that the user wants to play the game as soon as this may not be the case.

A cleaner IMO approach would use a while loop. Display the menu outside the loop and at the end of the loop . The user will have the opportunity to immediately exit.

  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 } 

Incoming Validation - Ideal Time to Use 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 failure flag to cin , so it will not always be false.

cin.fail() excellent. However, some would consider !cin more natural.

0
source

Source: https://habr.com/ru/post/1443849/


All Articles