Scanf跳入循环(Hangman) [英] Scanf skipped in loop (Hangman)

查看:65
本文介绍了Scanf跳入循环(Hangman)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

该程序本质上要求输入一个秘密字符串,然后要求用户反复猜测该字符串的单个字符,直到他全部猜测为止.但是,它每隔第二次运行while循环时都会工作,它会跳过用户输入的猜测字符.我该如何解决?

This program essentially asks for a secret string, then asks a user to repeatedly guess single chars of that string until he guesses it all. It works however every second time the while loop is run it skips user input for the guessed char. How do I fix this?

int main(){
  char guess;
  char test2 [50];
  char * s = test2;

  char output [50];
  char * t = output;


  printf("Enter the secret string:\n");
  fgets(test2, 50, stdin);
  for (int i=0;i<49;i++){    //fills ouput with _ spaces
    *(output +i)='_';

  while(strcmp(s,t) != 0){
    printf("Enter a guess:");
    scanf("%c",&guess);
    printf("You entered: %c\n", guess);
    showGuess(guess,s, t );           // makes a string "output" with guesses in it
    printf("%s\n",t);
  }
  printf("Well Done!");
}

推荐答案

正如其他答案和评论中指出的那样,您需要在输入中使用"换行符".

As pointed out in some other answers and comments, you need to "consume" the "newline character" in the input.

其原因是从键盘到程序的输入由外壳程序缓冲,因此,在您真正告诉外壳程序将其缓冲区的内容传递给程序之前,该程序将看不到任何东西".此时,程序将能够读取先前缓冲区中包含的数据,例如您的输入,后跟一个用于在外壳中验证您的输入的字符:换行符.如果在执行另一个scanf之前不使用"换行符,则第二个scanf将读取换行符,从而导致您看到跳过的scanf".要消耗输入中多余的字符,最好的方法是读取它们并丢弃所读取的内容(以下代码会做什么,请注意

The reason for that is that the input from your keyboard to the program is buffered by your shell, and so, the program won't see anything until you actually tell your shell to "pass the content of its buffer to the program". At this point, the program will be able to read the data contained in the previous buffer, e.g. your input, followed by one the character(s) used to validate your input in the shell: the newline. If you don't "consume" the newline before you do another scanf, that second scanf will read the newline character, resulting in the "skipped scanf" you've witnessed. To consume the extra character(s) from the input, the best way is to read them and discard what you read (what the code below does, notice the

while(getc(stdin) != '\n');

scanf之后的

行.该行的作用是:当从stdin读取的字符不是'\n'时,什么也不做,然后循环.".

line after your scanf. What this line does is: "while the character read from stdin is not '\n', do nothing and loop.").

作为替代方法,您可以通过 函数,也可以使用诅咒/I/O的 ncurses 库.

As an alternative, you could tell your shell to not buffer the input, via the termios(3) functions, or you could use either of the curses/ncurses libraries for the I/O.

这就是您想要的:

int main(){
  char guess;
  char test2 [50];
  char * s = test2; // 3. Useless

  char output [50];
  char * t = output; // 3. Useless

  int i;  // 8. i shall be declared here.

  printf("Enter the secret string:\n");
  fgets(test2, 50, stdin);
  for (i=0;i<50;i++) if (test2[i] == '\n') test2[i] = '\0'; // 4. Remove the newline char and terminate the string where the newline char is.
  for (int i=0;i<49;i++){ // 5. You should use memset here; 8. You should not declare 'i' here.
    *(output +i)='_';
  } // 1. Either you close the block here, or you don't open one for just one line.
  output[49] = '\0'; // 6. You need to terminate your output string.

  while(strcmp(s,t) != 0){ // 7. That will never work in the current state.
    printf("Enter a guess:");
    scanf("%c",&guess);
    while(getc(stdin) != '\n');
    printf("You entered: %c\n", guess);
    showGuess(guess,s, t );
    printf("%s\n",t);
  }
  printf("Well Done!");
  return 0; // 2. int main requires that.
}

您的代码的其他注释:

  1. 您在for循环之后打开了一个块,但从未将其关闭.这可能会引起问题.
  2. 您将main声明为返回整数的函数...因此,至少应至少在return 0;结尾.
  3. 您似乎已经了解到char * t = output;复制output的值,并使用t作为新副本的名称.这是错误的.您确实在复制某些内容,但只复制了toutput的地址(也称为引用).结果,outputt引用相同的数据,并且如果您修改output,则t将被修改;和反之亦然.换句话说,那些ts变量在当前状态下是无用的.
  4. 您还需要从test2缓冲区中的输入中删除换行符.我在fgets之后添加了一行.
  5. 与其考虑手动设置数组的所有字节,还不如考虑使用memset函数.
  6. 在填充"输出字符串之后,您实际上需要终止,因此您应该在最后一个位置分配一个'\0'.
  7. 当test2在有意义的内容之后被终止时,您将永远无法将test2字符串与输出1进行比较,因为输出1包含下划线.
  8. 虽然在循环作用域中的变量根据C99和C11有效,但在ANSI C中不是标准变量;通常最好不要在循环中声明任何变量.
  1. You opened a block after your for loop and never closed it. That might be causing problems.
  2. You declared your main as a function returning an integer... So you should at least return 0; at the end.
  3. You seem to have understood that char * t = output; copies output's value and uses t as a name for the new copy. This is wrong. You are indeed copying something, but you only copy the address (a.k.a reference) of output in t. As a result, output and t refer to the same data, and if you modify output, t will get modified; and vice versa. Otherwise said, those t and s variables are useless in the current state.
  4. You also need to remove the newline character from your input in the test2 buffer. I have added a line after the fgets for that.
  5. Instead of setting all the bytes of an array "by hand", please consider using the memset function instead.
  6. You need to actually terminate the output string after you "fill" it, so you should allocate a '\0' in last position.
  7. You will never be able to compare the test2 string with the output one, since the output one is filled with underscores, when your test2 is NULL terminated after its meaningful content.
  8. While variables at the loop scope are valid according to C99 and C11, they are not standard in ANSI C; and it is usually better to not declare any variable in a loop.

"_空格"也称为下划线";)

Also, "_ spaces" are called "underscores" ;)

这是执行您想要的代码:

Here is a code that does what you want:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define LEN 50

int main()
{
    char phrase[LEN];
    char guessed[LEN];
    char guess;
    int i, tries = 0;

    puts("Please enter the secret string:");
    if(fgets(phrase, LEN, stdin) == NULL)
      return 1;
    for(i = 0; i < LEN && phrase[i] != '\n'; i++); // Detect the end of input data.
    for(; i < LEN; i++)                            // For the rest of the input data,
      phrase[i] = '_';                             // fill with underscores (so it can be compared with 'guessed' in the while loop).
    phrase[LEN - 1] = '\0';                        // NULL terminate 'phrase'

    memset(guessed, '_', LEN);                     // Fill 'guessed' with underscores.
    guessed[LEN - 1] = '\0';                       // NULL terminate 'guessed'

    while(strcmp(phrase, guessed) != 0)            // While 'phrase' and 'guessed' differ
    {
      puts("Enter a guess (one character only):");
      if(scanf("%c", &guess) != 1)
      {
        puts("Error while parsing stdin.");
        continue;
      }
      if(guess == '\n')
      {
        puts("Invalid input.");
        continue;
      }
      while(getc(stdin) != '\n');                  // "Eat" the extra remaining characters in the input.
      printf("You entered: %c\n", guess);
      for(i = 0; i < LEN; i++)                     // For the total size,
        if(phrase[i] == guess)                     // if guess is found in 'phrase'
          guessed[i] = guess;                      // set the same letters in 'guessed'
      printf("Guessed so far: %s\n", guessed);
      tries++;
    }
    printf("Well played! (%d tries)\n", tries);
    return 0;
}

如果您没有得到任何帮助,请随时在评论中提问. :)

Feel free to ask questions in the comments, if you are not getting something. :)

这篇关于Scanf跳入循环(Hangman)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆