我是C编程的新手,我发现提示用户输入对于像我这样的初学者来说是一个相当大的挑战。
我只是在写一个简单的C代码,持续提示用户输入,直到用户输入一个负数,程序停止。在某种程度上,我希望提示用户输入的格式类似于我们在python中使用的格式,其中:
Enter a number: (userinput a number here and press enter)
并且输出将是:
The number you entered is 10 (for example)
这还没有停止循环并提示输入另一个数字,因为没有输入负数。
Enter a number: (userinput another number which is negative)
输出:
The number you entered is -10 (for example)
并且程序停止。
我试着用C写:
#include <stdio.h>
int value = 0;
while (value >= 0) {
do {
printf("Enter a number: ");
scanf("%d",&value);
printf("The number you entered is %d", &value);
}
但我似乎不能得到"输入一个数字:"语句显示第一次当我运行的程序,因为它立即要求用户输入在开始时没有提示消息显示,直到当我输入一个整数,提示消息显示这是相反的我想要的。
1条答案
按热度按时间thigvfpy1#
新的C程序员面临的最大问题之一是正确处理用户输入,尤其是在使用
scanf
系列函数时。为什么?在使用scanf
* 时,必须考虑到输入缓冲区中剩下的所有字符(此处为stdin
)。为什么?当发生 * 匹配失败 * 时,scanf
在失败点停止处理字符,而导致失败的字符仍保留在输入缓冲区中未读,等待下次尝试输入时咬你一口。更复杂的问题是
scanf
* 转换说明符 * 如何处理空格,您的数字输入说明符和%s
将消耗前导空格,而其余的转换说明符则不需要。这意味着如果你使用的不是数字或%s
转换说明符--在尝试下一个字符或 * 字符类 * 转换之前,必须考虑并删除尾随的'\n'
。也就是说,无论何时使用
scanf
,都要由您来检查返回,以便您可以确定用户是否使用手动生成的EOF
取消了输入,从而确定是否发生了 * 匹配 * 或 * 输入 * 失败。最起码,您必须检查返回值并处理任何指示发生的转换数少于预期转换数的返回值。在您的示例中,对于一个到
int
的转换,在使用value
之前,您必须检查返回值是否为1
。否则,您可以轻松调用 * Undefined Behavior *。现在,仅仅检查是否所有转换都发生了,并不允许您区分EOF
或 * matching * failure-使您没有继续进行所需的信息,您所能做的最好的事情是在无效输入时退出,例如(**注:**在输入无效整数时,程序只能结束,您不知道输入是否被取消,或者是否发生了 * matching * 故障,如果故障是 * matching * 故障,则允许您采取适当的操作,通过清空输入缓冲区来继续。
正确处理
scanf
输入的方法是覆盖所有潜在的错误条件,并通过清除输入缓冲区中的违规字符来优雅地响应 * matching * 失败,从而允许您继续输入。使用一个小的helper-function来清除stdin
很有帮助,而不必在代码中每次使用scanf
时都重复包含一个清除循环。一个简短的例子是:它只读取
stdin
中的所有字符,直到遇到'\n'
或EOF
。将其与scanf
返回的扩展检查结合起来,将允许您优雅地处理 * matching * 失败,例如:在这里,如果输入了
foo
这样的非整数,则会捕获它,从stdin
中删除字符,然后循环再次提示输入。仔细想想。C不是Python。Python隐藏了很多实现细节,从本质上保护你不受示例的影响,但它也有它的缺点。使用C,没有什么是隐藏的。你可以自由地写你不拥有的内存,在转换失败后重复尝试从输入缓冲区读取,等等。你要对细节负责。
最后,所有这些都是推荐新用户使用
fgets
或POSIXgetline
进行输入的主要原因。(不要吝啬大小),fgets
将从输入缓冲区中一次读取一行,防止令人不快的字符继续等待再次咬你。getline
将分配足够大小的缓冲区,无论行有多长-- 但您需要在使用完后释放内存。请研究这两种方法,作为使用scanf
的替代方法。您可以始终在读取该行后对保存该行的缓冲区调用sscanf
,以从中解析数值。