简体   繁体   English

在C中-for循环中的scanf()导致printf()运行多次

[英]In C - scanf() in a for loop is causing printf() to run multiple times

I'm completing an assignment and after completing it, I have 1 bug, and 1 bug fix I made that I don't fully understand. 我正在完成一个作业,完成后,我有1个错误和1个我不完全了解的错误修复。 Currently, as long as the user does what is asked, everything works fine. 当前,只要用户按照要求执行操作,一切就可以正常进行。 But I know that doesn't happen often, so I'd love to know how to stop these issues. 但是我知道这种情况很少发生,所以我很想知道如何阻止这些问题。 Would love any advice - I am a complete beginner with C. 希望得到任何建议-我是C的完整入门者。

I found many different pieces of advice here: C: Multiple scanf's, when I enter in a value for one scanf it skips the second scanf 我在这里找到许多不同的建议: C:多个scanf,当我为一个scanf输入值时,它会跳过第二个scanf

I added a space to my scanf() statements which solved some of the bugs - and I understand that \\n is added onto the end of the entered strings / chars, I'm just not sure how to check for it / handle it, and I tried using getchar() in place of the scanf() but I still get double print / loop problems. 我在我的scanf()语句中添加了一个空格,以解决一些错误-并且我知道\\ n被添加到输入的字符串/字符的末尾,我只是不确定如何检查/处理它,我尝试使用getchar()代替scanf(),但仍然遇到双重打印/循环问题。

Bug Issue 错误问题

When the user is running through the game loop, if they enter more than 1 character (for example: 'oo', when prompted with the scanf() to enter 'y' or 'n') my printf statements run 1x per character entered, and connect to each other: 当用户在游戏循环中运行时,如果他们输入多个字符(例如:“ oo”,则当scanf()提示输入“ y”或“ n”时),则我的printf语句对输入的每个字符运行1x ,并相互连接:

Example would be: 例如:

Welcome to Two doors. 欢迎来到两扇门。

Would you like to play? 你想玩? (y/n):Welcome to Two doors. (y / n):欢迎来到两扇门。

Would you like to play? 你想玩? (y/n): (是/否):

This issue also shows up if the user enters 'y' to play the game but then enters a character other than 1,2 or 3 in the second section. 如果用户输入“ y”来玩游戏,然后在第二部分中输入了1,2或3以外的字符,也会出现此问题。

How can I limit the length of their response? 我如何限制他们的回复时间? Or is the best way to monitor the length of the play and choice variables prior to entering the if statements? 还是在输入if语句之前监视播放和选择变量的长度的最佳方法? Maybe checking to see if they are longer than 1 character and if so, only taking the first character? 也许要检查它们是否长于1个字符,如果长于1个字符,那么仅检查第一个字符?

Second issue - bug fix that I don't understand In the scanf() functions I ran into a very similar problem to what I described above, but it happened when the user entered any character. 第二个问题-我不了解的错误修复在scanf()函数中,我遇到了一个与上面所述非常相似的问题,但是当用户输入任何字符时都会发生。 The solution I found was to add a space before the character -> 我发现的解决方案是在字符前添加一个空格->

scanf(" %c", &play);

vs

scanf("%c", &play);

Is this issue only a problem when using loops? 使用循环时,这个问题只是一个问题吗? Since I never found these bugs prior to looping back through the code. 由于我在遍历代码之前从未发现这些错误。

Updated Code with 'while (getchar() != '\\n');' 更新代码为'while(getchar()!='\\ n');' suggestion from Sourav Ghosh Sourav Ghosh的建议

#include <stdio.h>

int main(void) {

    char play;
    int choice;
    char answer[] = "No matter which one you choose the guards both tell you which door leads to death, and therefore you can pick the other door.\n";
    int gameLoop = 1;
    int timesPlayed = 0;

    while (gameLoop == 1){

        if (timesPlayed == 0) {
            printf("Welcome to Two doors.\n");
            printf("Would you like to play? (y/n):");
        } else {
            printf("Would you like to play again? (y/n):");
        }
        scanf(" %c", &play);
        while (getchar() != '\n');

        if (play == 'y') {
            // == instead of =
            printf("\nYou are a prisoner in a room with 2 doors and 2 guards.\n");
            printf("One of the doors will guide you to freedom and behind the other is a hangman --you don't know which is which.\n");
            printf("One of the guards always tells the truth and the other always lies. You don't know which one is the truth-teller or the liar either.\n");
            printf("You have to choose and open one of these doors, but you can only ask a single question to one of the guards.\n");
            printf("What do you ask so you can pick the door to freedom?\n\n");
            printf("\t1.Ask the truth-guard to point to the door of doom.\n");
            printf("\t2.Ask the liar-guard to point to the door of doom.\n");
            printf("\t3.Doesn't matter which one you pick.\n");
            scanf(" %d", &choice);
            while (getchar() != '\n');

            switch (choice) {

                case 1:
                printf("%s", answer);
                timesPlayed++;
                break;

                case 2:
                printf("%s", answer);
                timesPlayed++;
                break;

                case 3:
                printf("%s", answer);
                timesPlayed++;
                break;

                default:
                printf("The Troll Smasher comes out from the shadows and squeezes the stupid out of you until you pop. GAME OVER!\n");
                break;
            }
        } else if(play == 'n') {
            printf("Sorry to hear that, we at Two Doors hope you have a super duper day!\n");
            gameLoop = 0;
            break;
        } else {
            printf("That is not a valid input, please try again by entering either 'y' to start the game or 'n' to quit the game.\n");
        }
    }
    return 0;

}

The problem with %c format specifier is that, it will read only one byte from the input buffer and if the input buffer has more in store and the call in encountered next time, it will not ask for user input , it will simply read the next byte from the available input stream. %c格式说明符的问题在于,它将仅从输入缓冲区读取一个字节,并且如果输入缓冲区中有更多的存储空间,并且下次遇到调用,它将不要求用户输入 ,它只会读取可用输入流中的下一个字节。

So, to answer 所以,要回答

How can I limit the length of their response? 我如何限制他们的回复时间?

well, there's no straightway approach that you can stop the user from entering only X characters/ digits, instead, swipe off the excess, ( if any ) and for the next call, start with an empty buffer is an easy approach. 嗯,没有一种简单的方法可以阻止用户仅输入X字符/数字,而是划掉多余的字符( 如果有的话 ),对于下一个呼叫,从缓冲区开始是一种简单的方法。

So, the quick way out of this would be, to clean off the standard input of remaining inputs. 因此,解决此问题的快捷方法是清除其余输入的标准输入。 You can do something like 你可以做类似的事情

  int retval = scanf(" %c", &play);

  //some code

  while (getchar() != '\n');   //eat up the input buffer

  //next call to scanf(), input buffer is empty now....

to stop scanf() from reading already existing unwanted inputs and force it to ask the input from user. 停止scanf()读取已经存在的不需要的输入,并强制它询问用户的输入。

Also, don't forget to check the return value of scanf() to ensure the success of the call. 另外,不要忘记检查scanf()的返回值以确保调用成功。

For the first issue the problem is caused because the execution of the program enters the loop again for example if the user types oo that means that after reading with scanf it is going all the way to the last else. 对于第一个问题,是由于程序的执行再次进入循环而引起的,例如,如果用户键入oo,则意味着使用scanf读取后,它将一直进行到最后一个循环。 Inside that else none of the variables is modified so when it reenters the loop gameLoop is still 1 and timesPlayed is still 0 so it will print the statements in the first if, then scanf will read the second o and repeat the process. 在其他变量中,没有任何变量被修改,因此当它重新进入循环gameLoop时仍为1,timesPlayed仍为0,因此它将在第一个if中打印语句,然后scanf将读取第二个o并重复该过程。 The problem is that scanf reads one character at the time. 问题是scanf一次读取一个字符。

Actually for entering one character you can use getchar() but in any case after char input you should clean standard input stream. 实际上,对于输入一个字符,您可以使用getchar()但是在char输入之后的任何情况下,您都应该清除标准输入流。 Consider the following example, that forces the user to the correct input: 考虑以下示例,该示例强制用户输入正确的内容:

    char name[11];
    char answer = 0;
    printf("Would you like to play again? (y/n): ");
    while ((answer = getchar()) != 'y' && answer != 'n')
    {
        printf("You should answer 'y' or 'n'\n");
        // clean the buffer from mess
        while (getchar() != '\n');
    }
    // clean the buffer from mess
    while (getchar() != '\n');
    // next input
    printf("Enter your name: ");
    scanf("%10s", name);
    // clean the buffer from mess
    while (getchar() != '\n');

UPDATE: 更新:

Just for clarification, the code 只是为了澄清,代码

while ((answer = getchar()) != 'y' && answer != 'n')
{
    printf("You should answer 'y' or 'n'\n");
    // clean the buffer from mess
    while (getchar() != '\n');
}

can be be easier to understand while rewritten as 改写为

char name[11];
char answer = 0;
printf("Would you like to play again? (y/n): ");
while (1) // infinit loop 
{
    answer = getchar();
    // clean the buffer from mess (immideatly after reading) 
    while (getchar() != '\n');
    if (answer == 'y' || answer == 'n') // check the input
        break; // stop the loop if condition is true
    // or ask again
    printf("You should answer 'y' or 'n'\n");
}
// next input
printf("Enter your name: ");
scanf("%10s", name);
// clean the buffer from mess
while (getchar() != '\n');

in my first example I just optimize the code combining reading and checking the data in parentheses after while : (answer = getchar()) != 'y' is like two actions - answer = getchar() and then answer != 'y' 在我的第一个示例中,我只是优化了将while后面的括号中的数据读取和检查结合起来的代码: (answer = getchar()) != 'y'就像两个动作answer = getchar()然后answer != 'y'

In the last snippet condition answer != 'y' && answer != 'n' was intentionally replaced with answer == 'y' || answer == 'n' 在最后一个片段中, answer != 'y' && answer != 'n'被替换为answer == 'y' || answer == 'n' answer == 'y' || answer == 'n' to show difference between "do while data is incorrect" and "stop when correct data get" answer == 'y' || answer == 'n'以显示“数据不正确时执行”和“数据正确时停止”之间的差异

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

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