简体   繁体   English

在do-while循环中输入验证出现C ++错误

[英]C++ error with input validation in a do-while loop

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. 我使用do-while循环创建了它,而我遇到的问题是菜单选择变量是int ,因此当我(或用户)从菜单中选择时偶然输入了一个非整数输入}while(condition)主循环末尾的}while(condition)无法捕获它,并且程序无限重复。 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. 相反,如果您在菜单选择中输入了无效的int ,程序将捕获该错误并显示“ invalid input”消息,然后重复主菜单。

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. 我将另存为.cpp,并使用g++ -ansi -pedantic -Wall -Werror在Linux中进行编译。老师禁止在条件语句中进行硬编码,因此禁止使用全局常量。

#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.fail() (而不只是cin >> menuChoice; )(在此文章之后建模):

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 有关更多详细信息,请参见此SO线程。

Use a do-while to ensure that the loop body will run at least once. 使用do-while来确保循环体至少运行一次。

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. 通过使用do-while并在循环外提示用户,您可以假定用户想玩一次游戏,而事实并非如此。

A cleaner approach IMO would be use a while loop. IMO的一种更清洁的方法是使用while循环。 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-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. 使用numeric_limits<streamsize>::max()完全清除缓冲区。
  • Use cin.clear() to reset the fail flag on cin so it wont always be false. 使用cin.clear()cin上重置失败标志,这样它就不会永远为假。

cin.fail() is fine. cin.fail()很好。 However some would consider !cin more natural. 但是,有些人会认为!cin更自然。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM