Scanf skips every other while loop in C
我正在尝试开发一个简单的基于文本的子手游戏,并且游戏的主要循环从提示输入每个字母的猜测开始,然后继续检查字母是否在单词中,并使其失去生命 不是。 但是,当我运行游戏时,每次都会出现两次提示,并且程序不会等待用户的输入。 它也可以腾出一条生命(如果是正确的输入,则为一条生命,如果不是正确的输入,则为两条生命),因此它所吸收的一切与先前的输入不同。 这是我的游戏循环,简化了一点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| while (!finished )
{
printf("Guess the word '%s'
",covered );
scanf("%c", ¤tGuess );
i =0;
while (i <=wordLength )
{
if (i == wordLength )
{
--numLives ;
printf("Number of lives: %i
", numLives );
break;
} else if (currentGuess == secretWord [i ]) {
covered [i ] = secretWord [i ];
secretWord [i ] = '*';
break;
}
++i ;
}
j =0;
while (j <=wordLength )
{
if (j == (wordLength )) {
finished = 1;
printf("Congratulations! You guessed the word!
");
break;
} else {
if (covered [j ] == '-') {
break;
}
}
++j ;
if (numLives == 0) {
finished = 1;
}
}
} |
我认为问题出在斯堪夫,以为它没有被服用,但是我不知道为什么。 有人有什么主意吗? 我在Mac OS X 10.5上使用gcc 4.0.1。
当您使用scanf()读取键盘输入时,在按enter键之后将读取输入,但是回车键不会占用Enter键生成的换行符。这意味着下次您从标准输入中读取内容时,将会有一个换行符在等待您(这将使下一个scanf()调用立即返回而没有数据)。
为避免这种情况,您可以将代码修改为:
1
| scanf("%c%*c", ¤tGuess ); |
%*c匹配单个字符,但星号表示该字符将不会存储在任何地方。这具有消耗Enter键生成的换行符的效果,以便下次调用scanf()时,将从空的输入缓冲区开始。
警告:如果用户按下两个键,然后按下Enter键,则scanf()将返回第一个击键,吃掉第二个击键,然后将换行符留给下一个输入呼叫。这样的怪癖是许多程序员避免使用scanf()和朋友的原因之一。
-
匿名编辑尝试在此帖子中添加文本:"至少对于我的代码,应为%* c%c,而不是%c%* c",并更改scanf使其匹配。 Ive拒绝了该编辑,因为Im并未说服它的权利,但想提出其意见以供考虑。
-
@Craig Ringer-"%c%* c"将吃掉附加到当前输入字符的换行符。事后,您将使用"%* c%c"来吃掉先前输入中的换行符。从技术上来讲,两者都可能是正确的,但是更好的做法是自己清理,而不是将流浪汉字留在缓冲区中以便其他人去处理。
-
实际上,在其中放置"%* c"的地方考虑这段代码很重要,在其中"%* c%i"解决了无限循环问题,但"%i * c"不会:getagin: printf("Please enter a number:
"); isnumber = scanf("%*c%i", &number); "%*c%i" will eat the newline attached to the current input character. and fix the problem. But not"%i%*c" if(isnumber) { printf("You enterd a number and it was %i
", number); } else { printf("You did not eneter a number.
"); goto getagin; }
-
如果代码要使用结尾的
而不是其他内容,请使用"%*1[
]"而不是"%*c"。
-
@chux尽管从技术上讲更加精确,但是由于在某些情况下您不想跳过空格,因此通用" %c"会更容易。
换行符。
第一次通过循环,scanf()读取字符。
然后,它读取换行符。
然后读取下一个字符;重复。
怎么修?
我很少使用scanf(),但是如果使用格式字符串"%.1s",它应该跳过空格(包括换行符),然后读取非空格字符。但是,将期望使用字符数组而不是单个字符:
1 2 3 4 5 6
| char ibuff [2];
while ((scanf("%.1s", ibuff ) == 1)
{
...
} |
-
我认为我比我更喜欢这种解决方案,因为一旦知道它是什么,它将允许用户只输入其余单词(我们在玩Hangman,还记得吗?)。
-
scanf(" %c", ¤tguess)也可以解决问题,而无需更改变量的类型。 scanf格式字符串中的空格匹配"输入中包含任何数量的空格,包括无"。
将问题分解为较小的部分:
1 2 3 4 5 6 7 8 9
| int main (void) {
char val ;
while (1) {
printf("enter val:");
scanf("%c", &val );
printf("got: %d
", val );
}
} |
输出是:
1 2 3
| enter val: g
got: 103
enter val: got: 10 |
为什么scanf在那里又给您'10'?
由于我们为值打印了ASCII数字,因此ASCII中的'10'是" enter",因此scanf还必须抓住" enter"键作为字符。
果然,看着您的scanf字符串,您每次在循环中都要求输入一个字符。控制字符也被认为是字符,将被拾取。例如,您可以在上面的循环中按" esc"然后按" enter"并获得:
1 2 3
| enter val: ^[
got: 27
enter val: got: 10 |
-
好的答案:将问题精炼为本质,进行展示和解释(在竞赛所有其他海报时,同样如此!)。这个答案比我的单个mod点值得更多。
-
感谢您的投票!在发布之前,我想确定我的回答,并且在我确认时已经回答了。我认为只是记下我的方法可能会有用。
注意%c之前的空格。 这很重要,因为它与所有前面的空格匹配。
只是一个猜测,但是您要使用scanf输入单个字符,但是用户必须键入该猜测加上换行符,该换行符被用作单独的猜测字符。
吉姆和乔纳森说对了。
为了让您的scanf行做您想做的事情(不使用换行符而将其放入缓冲区),我将其更改为
1 2
| scanf("%c
", ¤tGuess ); |
(请注意
)
尽管对此的错误处理是残酷的。至少您应该将scanf的返回值与1进行比较,如果输入没有返回,则忽略该输入(带有警告)。
-
@AnttiHaapala-在这种情况下,那不是不希望的。他所要做的就是在不产生2个输入的情况下接受单字符命令。由于空格不是此方案中的命令,因此他不希望使用空格。这可能就是为什么他接受了更复杂的答案(也跳过了领先的空白)的原因。
-
您的答案是完全不同的。在处理第一个字符之前,它将等待直到输入了另一个非空白字符。因此,它对于解决问题没有用。
-
@AnttiHaapala-刚刚在在线编译器中尝试过。实际上,它确实在等待第二次输入。第二个输入没有丢失,但是此后程序始终是其处理中的一个命令。并非完全不可行,但绝对不是最佳选择。喜欢Leffler的答案更好的另一个原因。
我猜:在您输入数据时,您的代码将换行符视为一种猜测。由于无法控制的错误处理,我一直避免使用* scanf()系列。尝试改用fgets(),然后提取第一个字符/字节。
-
OK,每个人都在一分钟内跳到结尾的换行符字节/字符上。因此,建议先读取一行输入,然后检查所拥有的内容,清理并根据需要检测错误。也许在" get_answer()"函数中?
我注意到了几点:
-
scanf("%c")将读取1个字符并将ENTER保留在输入缓冲区中,以备下次通过循环使用
-
即使从用户读取的字符与secretWord中的字符不匹配,您仍要递增i
-
covered[j]什么时候变成'-'?
输入字符时,必须输入空格字符才能继续。 此空白字符存在于输入缓冲区stdin文件中,并由scanf()函数读取。
可以通过使用此额外字符来解决此问题。 这可以通过使用getchar()函数来完成。
1 2
| scanf("%c",¤tGuess );
getchar(); // To consume the whitespace character. |
我宁愿建议您避免使用scanf(),而是使用getchar()。 scanf()需要大量的存储空间。 getchar()是灯光功能。 因此,您还可以使用-
1 2 3
| char currentGuess ;
currentGuess =getchar();
getchar(); // To consume the whitespace character. |
我在您的代码中看到了几件事:
scanf返回其读取的项目数。您可能要处理返回0或EOF的情况。
我的猜测是用户按字母+ Enter,而您将换行符作为第二个字符。一种简单的检查方法是添加调试printf语句以显示输入的字符。
您的代码将仅匹配匹配字母的第一个匹配项,即,如果单词为" test"且用户输入了" t",则您的代码将仅匹配第一个" t",而不是两个都匹配。您需要调整第一个循环来处理此问题。