所有scanf() 转换说明符 除了 "%c"、"%[..]" 和"%n" 忽略前导空格。 '\n' 是空格。使用scanf(),您可以按Enter,直到您的手指使用"%d" 转换说明符脱落,并且永远不会被读取。 scanf() 将简单地丢弃所有空格并继续阻塞等待有效输入或EOF。
这只是scanf() 给新 C 程序员带来的众多陷阱中的一个。这就是为什么强烈建议您对所有用户输入使用fgets()。有了足够大小的缓冲区(字符数组),fgets() 将一次消耗一整行(包括尾随的'\n')。这大大简化了输入,因为在用户按下 Enter 后,stdin 中剩余的内容并不取决于是否发生了 scanf() matching-failure。
要从fgets() 填充的缓冲区末尾删除尾随'\n',只需使用strcspn(),如下所示:
iFile[strcspn (iFile, "\n")] = 0; /* trim \n from end of iFile */
如果您确实需要转换缓冲区的内容,只需使用 sscanf() 提供缓冲区作为第一个参数,其余的就像使用 scanf() 一样——但在任何失败时,@ 中都没有留下任何内容987654342@,因为您已经完全阅读了fgets() 的用户输入。
如果您尝试读取带有scanf() 的int,并且用户滑倒并点击'r' 到达'4',则会发生匹配失败并从@ 提取字符987654348@ 在stdin 未读 中停止离开'r'。如果你在一个循环中接受输入——你刚刚创建了一个无限循环......
在您在这里要求用户输入0 或1 的情况下,不需要从数字转换开始。只需使用fgets() 将输入读入缓冲区,然后检查缓冲区中的第一个字符是'0' 还是'1'(ASCII 数字)。无需转换。
不要在代码中使用 MagicNumbers(例如 50)。如果你需要一个常量,#define 一个,或者使用一个全局的enum 来完成同样的事情,例如
#define MAXFN 50 /* if you need a constant, #define one (or more) */
#define MAXC 1024
int main (void)
{
char buf[MAXC], /* oFile[MAXFN] ,*/ iFile[MAXFN];
(注意:如果在微控制器上编程,请相应减少读取缓冲区 (MAXC) 的最大字符数,否则,对于一般 PC,使用 1K 缓冲区即可)
把它放在一起,并添加一个"print to another file - not implemented",来处理用户按要求输入1,你可以这样做:
#include <stdio.h>
#include <string.h>
#define MAXFN 50 /* if you need a constant, #define one (or more) */
#define MAXC 1024
int main (void)
{
char buf[MAXC], /* oFile[MAXFN] ,*/ iFile[MAXFN];
fputs ("Please enter the name of the input file: ", stdout);
if (!fgets (iFile, MAXFN, stdin)) { /* read ALL user input with fgets() */
puts ("(user cancled input)"); /* validate, if manual EOF return */
return 0;
}
iFile[strcspn (iFile, "\n")] = 0; /* trim \n from end of iFile */
for (;;) { /* loop continually until valid input from user or EOF */
fputs ("\nPlease enter 0 to print to console, "
"1 to print to another file: ", stdout);
if (!fgets (buf, MAXC, stdin)) { /* read ALL user input with fgets() */
puts ("(user cancled input)"); /* validate, if manual EOF return */
return 0;
}
if (*buf == '0') { /* no need to covert to int, just check if ASCII '0' */
puts (iFile);
break;
}
else if (*buf == '1') { /* ditto -- just check if ASCII '1' */
puts ("print to another file - not implemented");
break;
}
fputs (" error: invalid input, not 0 or 1\n", stderr); /* handle error */
}
}
(注意:当你需要用户提供特定的输入时,不断循环直到你得到你需要的,或者直到用户通过按 Ctrl + d 生成手动EOF (或 Ctrl + z 在 Windows 上))
使用/输出示例
故意为第一个输入单独按 Enter 并为接下来的两个输入提供无效输入,您将:
$ ./bin/console_or_file
Please enter the name of the input file: myInputFilename.txt
Please enter 0 to print to console, 1 to print to another file:
error: invalid input, not 0 or 1
Please enter 0 to print to console, 1 to print to another file: bananas
error: invalid input, not 0 or 1
Please enter 0 to print to console, 1 to print to another file: 2
error: invalid input, not 0 or 1
Please enter 0 to print to console, 1 to print to another file: 0
myInputFilename.txt
检查一下,如果您还有其他问题,请告诉我。