Scanf跳过循环(Hangman)

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

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

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

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

为了更好的解决方案,重做代码以使用fgets()然后解析输入。

正如其他一些答案和评论中所指出的,您需要在输入中“使用”“换行符”。

原因是键盘到程序的输入由shell缓冲,因此,程序在您实际告诉shell“将其缓冲区的内容传递给程序”之前不会看到任何内容。 此时,程序将能够读取前一个缓冲区中包含的数据,例如您的输入,后跟一个用于validationshell中输入的字符:换行符。 如果在执行另一次scanf之前没有“消耗”换行符,则第二次scanf将读取换行符,从而导致您看到的“跳过scanf ”。 要从输入中消耗额外的字符,最好的方法是读取它们并丢弃你读的内容(下面的代码是什么,注意

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

scanf后的行。 这一行的作用是:“从stdin读取的字符不是'\n' ,什么也不做,循环。”)。

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

此外,“_ spaces”被称为“下划线”;)


这是一个执行您想要的代码:

 #include  #include  #include  #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; } 

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

scanf正在读取上一次迭代中输入的换行符。 您可以使用getc()接收’\ n’,如下所示:

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

..

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

更改

 scanf("%c",&guess); 

 scanf(" %c",&guess); 

它应该忽略'\n'