如何使用 scanf 验证用户输入。现在我有这样的东西,但不起作用。
注意:我有 atoi 只是为了验证 scanf 验证是否有效。
scanf("%[0987654321.-]s",buf);
i = atoi(buf);
if(i)
index = i;
对于用户输入,使用scanf()
通常是一个坏主意,因为失败会使FILE
指针处于未知位置。那是因为scanf
代表“扫描格式化”并且没有比用户输入更多的未格式化。
我建议使用fgets()
输入一行,然后sscanf()
在字符串上实际检查和处理它。
这还允许您检查字符串中是否有您想要的字符(通过循环或使用正则表达式),这scanf
是函数系列并不真正适合的。
例如,scanf()
与"%d"
or一起使用"%f"
将在第一个非数字字符处停止,因此不会捕获尾随错误,例如"127hello"
,只会给您 127。而与无界一起使用它%s
只是乞求缓冲区溢出。
如果你真的必须使用[]
格式说明符(in scanf
or 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()
中,指示string
使用格式修饰符“a”(这是 GNU 扩展)自动分配足够大的空间。如果您不在 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 不会为你做这件事。
“buf”需要是一个指针。看起来你是按价值传递的。