【问题标题】:getline() function reading in whitespace before input is enteredgetline() 函数在输入输入之前读取空白
【发布时间】:2014-12-21 11:26:27
【问题描述】:

好吧,我写了一个刽子手游戏。游戏运行良好,除非用户完成游戏并输入 Y 的 char 值再次玩。

我已将问题追溯到我的 do-while 循环开始时的 getline() 函数。如果我输入 Y,那么 do-while 循环会成功重复,但 getline 函数似乎已经认为 cin 中有输入,即使我没有输入任何内容。

到目前为止,这是我的代码:

#include<iostream>
#include<string>

using namespace std;

int main() {





    string secretWord;
    string secretWordClean = "";
    string guessedLetters; //to be loaded with _ characters equal to length of secretWord
    string incorrectlyGuessedChars = "";
    char individualCharGuess;
    char playAgain;
    size_t countOfLetters = 0; //begine count at 0
    size_t guessesRemaining;
    int guessedUsed;


    begin_game://label which we can use to bring us back to the start of the do-while loop at any time

    do{//start of the game

    cout << "Please enter a secret word: ";
    getline(cin, secretWord); //y getline is cuaing the issue


     for(int i = 0; i < secretWord.length(); i++){
            if (isalpha(secretWord[i])){ 
                    secretWordClean += secretWord[i];
            }
        }

     secretWord = secretWordClean; //assign all alpha secret word string back to original variable for better readability
     guessesRemaining = secretWord.length() * 2;

     for(int i = 0; i < secretWord.length(); i++){
         guessedLetters += "_"; //fills guessedLetters with blanks equal to the length of the secretWord
     }




         cout << "Please guess a letter, you have " << guessesRemaining << " guesses remaining!" << endl;
         cin >> individualCharGuess;

         for(int i = 0; i < secretWord.length(); i++){ //every complete iteration of this for loop = one single guess
                if(secretWord[i] == individualCharGuess){
                    guessedLetters[i] = individualCharGuess; //will replace the spaces with the correct character, if guessed
                    countOfLetters++; //if any letter is guessed correctly, this indicator will be inrimented above 0
                    continue;
                 }

                if(secretWord.find(individualCharGuess) == string::npos){
                    if(incorrectlyGuessedChars.find(individualCharGuess) == string::npos){
                    incorrectlyGuessedChars += individualCharGuess;
                    }
                }
         }

         if(secretWord.compare(guessedLetters) == 0){
             cout << "You win! The word was: " << secretWord << endl;
             guessedUsed = ((secretWord.length() * 2) - guessesRemaining) + 1 ;
             cout << "You used " << guessedUsed << " guesses." << endl; 
             cout << "Play again? Enter Y for Yes, or anything else to exit: ";
             cin >> playAgain;
             if(playAgain != 'Y'){
             break; //exit the loop if user guesses all the letters and doesn't want to play again
             }
             else {
                 goto begin_game;
             }
         }

         guessesRemaining--; //we decriment our total guesses remaining if the user does not win the game or run out of guesses

         if(countOfLetters > 0){
             cout << "You have correctly guessed a letter!" << endl;
             cout << "Here are the letters you have guessed correctly so far: ";
             cout << guessedLetters << endl;
             cout << "Here are the letters you have guessed incorrectly so far: ";
             cout << incorrectlyGuessedChars << endl;
             countOfLetters = 0; //reset the counter to prepare for next iteration of do-while loop
         }
         else if (guessesRemaining <= 0) {
             cout << "You have run out of guesses!" << endl;
             cout << "Here are the letters that you guessed correctly: ";
             cout << guessedLetters << endl;
             cout << "Here are the letters you guessed incorrectly: ";
             cout << incorrectlyGuessedChars << endl;
             cout << "The secret word was: " << secretWord << endl;
             cout << "Play again? Enter Y for Yes, or anything else to exit: ";
             cin >> playAgain;
             if(playAgain != 'Y'){
             break; //exit the loop if user guesses all the letters and doesn't want to play again
             }
             else goto begin_game;
         }
         else {
             cout << "You guessed wrong! Keep trying, " << guessesRemaining << " guesses to go!" << endl;
             cout << "Here are the letters you have guessed correctly so far: ";
             cout << guessedLetters << endl;
             cout << "Here are the letters you have guessed incorrectly so far: ";
             cout << incorrectlyGuessedChars << endl;
         }



     }while (secretWord.compare(guessedLetters) != 0 || guessesRemaining != 0); //use to repeat the request for a single char guess


    return 0;
}

【问题讨论】:

    标签: c++ visual-studio-2012 c++11


    【解决方案1】:

    您正在混合格式化和未格式化的 I/O:读取字符将在读取字符后立即停止。由于在输入字符后您输入了换行符,因此换行符仍停留在流中,请阅读 getline() 以终止该行。在使用std::getline() 之前,您应该跳过前导空格,例如:

    if (std::getline(std::cin >> std::ws, s)) {
        ...
     }
    

    或者,您可以使用ignore() 忽略所有字符,包括换行符。请注意,仅忽略一个字符不会像'\n' 之间的一系列空格一样可靠地工作。要使用ignore(),您应该使用正确的幻数:

    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    

    顺便说一句,您还应该始终验证输入是否实际成功,否则您很容易在输入失败时出现错误行为。

    【讨论】:

    • 另一方面,ignore 也会跳过非空格。我想说的是,这种情况的合法用例应该很少见,在这种情况下,使用纯基于行的解析几乎总是更好(并单独处理每一行,也许通过字符串流)。
    【解决方案2】:

    不要混合使用&gt;&gt; 提取令牌和使用getline 提取行。前者不会删除换行符,因此令牌提取后的下一个getline 调用可能最终会读取上一行的剩余位,这可能是一个空字符串。

    如果您必须混合两种输入,请在使用getline 之前使用std::cin &gt;&gt; std::ws 来吞噬杂散的空格(包括换行符)。

    【讨论】:

    • 我没有投反对票,但我认为1 不是一个理想的推荐。
    • 没有投票,但在格式化提取后std::getline() 将错误地读取的原因是如果剩余字符是分隔符(可选地由第三个参数指定,'\n' 默认情况下)。此外,ignore(1, '\n') 仅丢弃单个字符(如果第一个参数为 0 或 1,则第二个参数没有任何意义)。也许你的意思是std::cin &gt;&gt; std::wsignore(numeric_limits&lt;streamsize&gt;::max(), '\n')
    • @DietmarKühl:我想...1 是为了防止空字符串。如果您需要的不仅仅是1,那么您至少会得到一个非空字符串。
    • @0x499602D2:嗯,我最关心的是你从getline 错误地得到一个空字符串的情况。我认为std::ws 是更好的选择,不过,我会补充一下。
    • @0x499602D2:我也不会调用getline“不正确”。只是线路和令牌提取之间的交互是不平凡的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-30
    • 1970-01-01
    • 1970-01-01
    • 2018-04-21
    • 2015-06-11
    • 2020-06-22
    • 1970-01-01
    相关资源
    最近更新 更多