Scanf跳过循环(Hangman)

时间:2014-04-12 09:42:01

标签: c loops scanf

这个程序本质上要求一个秘密字符串,然后要求用户反复猜测该字符串的单个字符,直到他猜到这一切。然而,它每隔一次运行while循环就会工作,它会跳过猜测的char的用户输入。我该如何解决这个问题?

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!");
}

4 个答案:

答案 0 :(得分:1)

要快速而肮脏的解决方案,请尝试

// the space in the format string consumes optional spaces, tabs, enters
if (scanf(" %c", &guess) != 1) /* error */;

要获得更好的解决方案,请重新使用代码fgets(),然后解析输入。

答案 1 :(得分:1)

正如其他一些答案和评论所指出的那样,你需要&#34;消费&#34; &#34;换行符&#34;在输入中。

原因是键盘到程序的输入由shell缓存,因此,程序不会看到任何内容,直到您实际告诉shell传递内容为止。它的缓冲程序&#34;。此时,程序将能够读取先前缓冲区中包含的数据,例如,您的输入,后跟一个用于验证shell中输入的字符:换行符。如果你不消费&#34;在执行另一个scanf之前的新行,第二个scanf将读取换行符,从而导致&#34;跳过scanf&#34;你目睹了。要从输入中消耗额外的字符,最好的方法是阅读它们并丢弃你读的内容(下面的代码是什么,注意

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

scanf之后排成一行。这一行的作用是:&#34;当从stdin读取的字符不是'\n'时,不做任何事情并循环。&#34;)。

作为替代方案,您可以通过termios(3)函数告诉shell不缓冲输入,或者您可以使用curses / ncurses库中的任意一个/ 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作为新副本的名称。这是错的。您确实在复制某些内容,但只复制outputt的地址(a.k.a参考)。因此,outputt引用相同的数据,如果您修改outputt将被修改;而反之亦然。否则说,那些ts变量在当前状态下是无用的。
  4. 您还需要从test2缓冲区中的输入中删除换行符。我在fgets之后添加了一行。
  5. 请考虑使用memset功能而不是设置阵列的所有字节&#34;#34;而不是设置'\0'功能。
  6. 在&#34; fill&#34;之后,你需要实际终止输出字符串。它,所以你应该在最后一个位置分配一个NULL
  7. 你永远无法将test2字符串与输出字符串进行比较,因为当test2在其有意义的内容之后被#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; } 终止时,输出字符串会被下划线填充。
  8. 虽然循环范围内的变量根据C99和C11有效,但它们在ANSI C中不是标准的;通常最好不要在循环中声明任何变量。
  9. 此外,&#34; _空格&#34;被称为&#34;下划线&#34; ;)


    这是一个可以满足您需求的代码:

    {{1}}

    如果你没有得到什么,请随意在评论中提问。 :)

答案 2 :(得分:0)

scanf正在读取上一次迭代中输入的换行符。你可以接受&#39; \ n&#39;通过使用getc()如下:

scanf("%c",&guess);
getc(stdin);

...

这改变了对我有用。虽然正确的解释和更精简的代码是@ 7heo.tk给出的代码

答案 3 :(得分:0)

更改

scanf("%c",&guess);

scanf(" %c",&guess);

它应该忽略'\n'