在C中,为什么从递归函数检测字符输入会导致它运行多次超过必要次数?

huangapple go评论62阅读模式
英文:

In C, why does detecting char input from a recursive function cause it to run multiple times more than necessary?

问题

I have a recursive function that uses printf() and scanf() to deal with user input. If the user accidentally presses a wrong key (not 'y'), it loops back. However, if the user enters multiple characters, the function asks the user for input multiple times at once. The printf() lines are repeated as many times as characters there are in the input.

Why does having excessive characters in the terminal buffer result in this type of behavior rather than the whole thing crashing or the terminal just ignoring the following characters?

int testDetectorWhite(){
	char userConfirmation;
	
	printf("Please place a WHITE disk directly below the detector\n");
	printf("Press 'y' when ready:\n");
	scanf("%c", &userConfirmation);
	printf("\n");
	
	if(userConfirmation != 'y'){
		testDetectorWhite();
	}
	
	//more code
}

I tried rewriting the code so that the recursive if() is substituted for a while() loop, like the following:

while(userConfirmation != 'y') {
        printf("Please place a WHITE disk directly below the detector\n");
	printf("Press 'y' when ready:\n");
	scanf("%c", &userConfirmation);
}

However, I still got the exact same bug.

I tried solving the issue by making userConfirmation a string, which solved the issue of multiple printf() functions running but resulted in more issues that are outside the scope of my question.

英文:

I have a recursive function that uses printf() and scanf() to deal with user input. If the user accidentally presses a wrong key (not 'y'), it loops back. However, if the user enters multiple characters, the function asks the user for input multiple times at once. The printf() lines are repeated as many times as characters there are in the input.

Why does having excessive characters in the terminal buffer result in this type of behavior rather than the whole thing crashing or the terminal just ignoring the following characters?

int testDetectorWhite(){
	char userConfirmation;
	
	printf("Please place a WHITE disk directly below the detector\n");
	printf("Press 'y' when ready:\n");
	scanf("%c", &userConfirmation);
	printf("\n");
	
	if(userConfirmation != 'y'){
		testDetectorWhite();
	}
	
	//more code
}

I tried rewriting the code so that the recursive if() is substituted for a while() loop, like the following:

while(userConfirmation != 'y') {
        printf("Please place a WHITE disk directly below the detector\n");
	printf("Press 'y' when ready:\n");
	scanf("%c", &userConfirmation);
}

However, I still got the exact same bug.

I tried solving the issue by making userConfirmation a string, which solved the issue of multiple printf() functions running but resulted in more issues that are outside the scope of my question.

答案1

得分: 0

你有两个问题,都与 scanf 函数及其许多不足之处有关。

  1. 要读取单个非空白字符,如你在这里尝试的那样,格式 "%c" 不会按你的预期工作。 你需要使用 " %c",其中有一个额外的空格。请参见 https://stackoverflow.com/questions/5240789
  2. 如果你想编写能够优雅处理用户错误的代码,并在发生错误时要求用户重试,scanf 不是一个好选择。 总的来说,问题在于“不良”输入往往会保留在输入流中,未读取,这意味着你可能必须尝试以某种方式“清除”它。另请参阅 https://stackoverflow.com/questions/34219549https://stackoverflow.com/questions/2979209

总的来说,如果你希望用户输入形式为 A,但担心用户可能会输入形式 B,你必须允许用户输入,并且你必须读取输入形式 B。 你不能只是编写试图读取形式 A 输入的代码,希望形式 B 输入会被自动丢弃。
例如,正如你在这里看到的,如果你编写使用 %c 在循环中读取单个字符的代码,而用户错误地输入了三个字符,你的循环将运行三次。

所以在一般情况下,如果你想处理用户可能错误输入的情况,无论以任何随机形式 B,这不是你想要的形式,你最终必须将用户的输入读取为字符串,使用 scanf %s 或者可能是 fgets。然后你必须检测输入是否符合你想要的形式(“形式 A”)。然后你可能必须将输入转换为你想要的形式(例如,从字符串转换为单个字符或从字符串转换为整数)。但如果你发现输入不是你想要的,你至少会读取(并丢弃)所有输入,这样在打印“请重试”提示后,你和用户将以空白状态开始。

这,不可否认,是需要做的更多工作,而且有些让人讨厌。 如果你刚开始学习,我建议集中精力处理正确的输入,也就是说,编写假定用户永远不会输入错误的代码。 显然,从人因因素来看,检测到不良输入并打印一个漂亮的提示要求用户重试是很好的,但编写正确的代码却令人意外地困难! 这可能是你在学习更多关于解决此问题所需的其他 C 工具时,可能想推迟几周的问题。

英文:

You have two problems, both related to the scanf function and its many deficiencies.

  1. To read a single non-whitespace character, as you're trying to do here, the format "%c" does not work as you expect. You need to use " %c", with an extra space in there. See https://stackoverflow.com/questions/5240789 .
  2. If you want to write code that deals gracefully with a user's mistakes, asking the user to try again if that happens, scanf is not a good choice. The problem, in general, is that "bad" input tends to stay on the input stream, unread, meaning that you may have to try to "flush" it somehow. See also https://stackoverflow.com/questions/34219549 and https://stackoverflow.com/questions/2979209 .

In general, if you want the user to type input of the form A, but you're afraid the user might type input of the form B instead, you have to let the user type, and you have to read in, that input of the form B. You can't just write code that tries to read input of the form A, hoping that input of the form B will be magically discarded.
For example, and as you've seen here, if you write code that reads single characters using %c in a loop, and the user wrongly types three characters, your loop will run three times.

So in the general case, if you want to handle the case where the user might wrongly type input in any random form B that wasn't what you wanted, you end up having to read the user's input as a string, using scanf %s, or maybe fgets. Then you have to detect whether the input was in the form you wanted ("form A"). Then you may have to convert the input into the form you wanted (like, converting from a string to a single character, or from a string to an integer). But if you detect that the input wasn't what you wanted, you'll have at least read (and discarded) it all, so that after you print your "please try again" prompt, you and the user will be starting from a blank slate.

This is, admittedly, more work to do, and somewhat of a nuisance. If you're just starting out, I recommend concentrating on correct input, that is, writing code that quietly assumes the user never types anything wrong. Obviously it's nice from a human factors standpoint to detect bad input, to print a nice prompt asking the user to try again, but it's surprisingly difficult to code that correctly! It's a problem you might want to defer for a few weeks, while you learn more abut the other C tools you'd need in order to solve it.

huangapple
  • 本文由 发表于 2023年5月10日 16:49:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/76216526.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定