注意:我使用atoi只是为了验证scanf的验证是否有效。
scanf("%[0987654321.-]s",buf);
i = atoi(buf);
if(i)
index = i;
使用scanf()
通常不是处理用户输入的好方法,因为失败会使FILE
指针处于未知位置。这是因为scanf
代表“扫描格式化”,而用户输入往往是非常非格式化的。
我建议使用fgets()
获取一行输入,然后对字符串进行sscanf()
检查和处理。
这也允许您检查字符串中包含的字符(可以使用循环或正则表达式),而scanf
函数族并不适合这样做。
例如,使用scanf()
与"%d"
或"%f"
将在遇到第一个非数字字符时停止,因此无法捕捉尾随错误,如"127hello"
,它只会给你返回127。而使用非有界限制的%s
则很容易引起缓冲区溢出问题。
如果您真的必须使用[]
格式说明符(在scanf
或sscanf
中),我认为它不应该跟在s
后面。
对于一个使用上述建议的健壮输入解决方案,请参见这里。一旦您将输入行作为字符串,就可以使用sscanf
处理它。
您似乎想要验证一个字符串作为输入。这取决于您想要验证字符串是否包含双精度浮点数或整数。以下是检查双精度浮点数的方法(允许前导和尾随空格)。
bool is_double(char const* s) {
int n;
double d;
return sscanf(s, "%lf %n", &d, &n) == 1 && !s[n];
}
sscanf
会返回转换的项(不包括“%n”)。n
将被设置为处理的输入字符数。如果所有输入都已处理,则s [n]将返回终止0字符。两个格式说明符之间的空格考虑了可选的尾随空格。
以下检查int,使用相同的技术:
bool is_int(char const* s) {
int n;
int i;
return sscanf(s, "%d %n", &i, &n) == 1 && !s[n];
}
这里有一个问题在这里,其中还包括更多C++风格的做法,比如使用字符串流和来自boost的函数,例如lexical_cast等等。它们通常比scanf之类的函数更受欢迎,因为很容易忘记传递一些“%”给scanf或一些地址。scanf不会识别,而是会执行任意操作,而例如lexical_cast将在任何不正确的情况下抛出异常。
我的方法是将用户输入读入字符串,然后使用strtol()
将其转换为长整型。 strtol()
返回指向输入字符串中第一个无法处理的字符的指针,因此通过检查此字符,您可以知道是否解析了完整的字符串,就像这样:
char *string;
char *endptr;
long result;
scanf("%as", string);
errno = 0;
result = strtol(string, &endptr, 10);
if (ERANGE == errno)
printf("Input number doesn't fit into long\n");
else if (*endptr)
printf("%s is not a valid long number - it contains invalid char %c\n",
string, *endptr);
else
printf("Got %ld\n", result);
scanf()
被指示使用格式修饰符 "a"(这是 GNU 扩展)自动分配足够大的空间来存储 string
。如果你不在 GNU 上,需要手动分配 string
并在 scanf()
格式中限制最大大小。在scanf
的第一个参数中指定的是转换说明符。 scanf
将尝试将输入转换为指定的格式,但有时您可能会对其匹配结果感到惊讶 :)
您应该进行的第一项检查是从scanf返回的值(它将给出匹配输入的数量)。 如果您没有得到预期的数字,则知道输入存在问题。 在您的情况下,应该是1。
if( scanf("%[0987654321.-]s", buf) == 1 )
{
if( sanit_check( buf ) )
{
/* good input */
}
else
{
/* invalid input */
}
}
else
{
/* invalid input */
}
除此之外,您需要对您要求 scanf
进行的转换进行自己的合理性检查。
int i;
scanf( "%d", &i );
如果你需要进行更复杂的检查,你就必须自己完成。Scanf不会为你完成。