虽然用户输入通常可以通过使用fgets 读取输入,然后使用sscanf 从结果缓冲区中解析您需要的内容来更好地处理,但只需使用一对指针和“英寸蠕虫向下”(a/k/ a "walking") 测试每个字符并根据需要进行处理的字符串——总是值得一看 scanf 以详细说明成功将其用于用户输入所需的操作。
虽然fgets 并非没有必要的验证,但scanf 所需验证的数量和类型以及在输入失败 或匹配失败为新的(不是那么新的)C 程序员创造了许多额外的陷阱。
scanf 的两个主要问题是 (1) 读取到任何缓冲区的字符数没有默认限制(可能会溢出您的数组); (2) 它不会从输入缓冲区中删除尾随'\n'(或输入或匹配失败后的任何字符) (例如stdin)。 由您自己决定考虑输入缓冲区中的所有字符并根据需要清空缓冲区。
更复杂的是不同的scanf 格式说明符处理前导空白的方式(数字转换通常会跳过前导空白,而字符转换不会) 另一个问题是处理 included 空格。 "%s" 格式说明符只会读取遇到的第一个空格,因此无法使用单个 %s 说明符读取 "My dog has fleas"。 (您可以使用字符类来读取包含的空格——如下例所示)
scanf 还有许多其他微妙之处,因此值得花时间阅读和理解man scanf。
从 cmets 中,您现在知道,如果您请求一串 100 字符,则至少需要 101 字符的存储空间——我们假设这是学会的。
当使用scanf 进行任何输入时,您必须始终验证返回以确保预期的转换次数确实发生了。例如,如果您使用转换说明符"%d %s" 读取"5 dogs",则返回2 表示成功转换为整数和字符串。但是,您也知道,至少有一个 '\n' 保留在输入缓冲区中(并且可能还有更多字符,如果输入了 "5 dogs and cats"。您可以删除 '\n' 和任何其他剩余的字符, 在尝试使用 scanf 读取更多输入之前。
以下示例捕获了您的示例中的大部分缺陷,并提供了一些您可以在处理用户输入时使用的工具。底线是学会使用fgets,但也要知道如何使用scanf。您的目标是提供尽可能健壮和防弹的输入例程。想想用户在提示输入时可能会做的所有愚蠢的事情(或者天堂禁止,一只猫从键盘上走过)总是有更多的验证可以添加。查看每个包含的验证,如果您有任何问题,请告诉我:
#include <stdio.h>
#include <string.h>
#define MAXC 100 /* if you need a constant, declare one */
/* helper function to remove any chars left in input buffer */
void empty_stdin()
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
int main (void) {
char str1[MAXC+1] = ""; /* initialize to all zero */
int index, rtn, len; /* index, return, length */
for (;;) { /* loop until valid input obtained */
printf ("Enter text of max 100 characters: ");
rtn = scanf ("%100[^\n]", str1); /* read at most MAXC char */
if (rtn != 1) { /* validate scanf return */
if (rtn == EOF) { /* check if EOF, ctrl+d, ctrl+z (windoze) */
printf ("input canceled.\n");
return 0;
}
if (!str1[0]) /* was a character entered? */
fprintf (stderr, "error: string is empty.\n");
/* remove '\n' and any chars that remain in stdin */
empty_stdin();
}
else { /* all conditions met, good entry, empty stdin and break */
empty_stdin();
break;
}
}
len = (int)strlen (str1); /* get string length */
for (;;) { /* now do the same thing for integer */
printf ("Enter the index to search (0-%d): ", len - 1);
if ((rtn = scanf ("%d", &index)) != 1) {
if (rtn == EOF) {
printf ("input canceled.\n");
return 0;
}
fprintf (stderr, "error: invalid input - not integer.\n");
/* only need to strip if non-integer entered, because %d
* will skip leading whitespace, including '\n'.
*/
empty_stdin();
}
else if (index < 0 || len < index + 1) /* validate index value */
fprintf (stderr, "error: invalid index - out of range.\n");
else
break;
}
printf ("your char is: %c\n", str1[index]);
return 0;
}
使用/输出示例
$ ./bin/scanfstr1
Enter text of max 100 characters: 12345678901234567890
Enter the index to search (0-19): -1
error: invalid index - out of range.
Enter the index to search (0-19): 0
your char is: 1
$ ./bin/scanfstr1
Enter text of max 100 characters: 12345678901234567890
Enter the index to search (0-19): foo
error: invalid input - not integer.
Enter the index to search (0-19): 6
your char is: 7
$ ./bin/scanfstr1
Enter text of max 100 characters: My dog has fleas.
Enter the index to search (0-16): d
error: invalid input - not integer.
Enter the index to search (0-16): 3
your char is: d
$ ./bin/scanfstr1
Enter text of max 100 characters:
error: string is empty.
Enter text of max 100 characters: My cats are fine.
Enter the index to search (0-16): meow
error: invalid input - not integer.
Enter the index to search (0-16): input canceled.