C++ 如何使用 scanf 验证输入
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/456303/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to validate input using scanf
提问by Raúl Roa
How can I validate the user input by using scanf. Right now I have something like this, but doesn't work.
如何使用 scanf 验证用户输入。现在我有这样的东西,但不起作用。
NOTE: I have the atoi just to validate that the scanf validation works.
注意:我有 atoi 只是为了验证 scanf 验证是否有效。
scanf("%[0987654321.-]s",buf);
i = atoi(buf);
if(i)
index = i;
回答by paxdiablo
Using scanf()
is usually a bad idea for user input since failure leaves the FILE
pointer at an unknown position. That's because scanf
stands for "scan formatted" and there is little more unformattedthan user input.
使用scanf()
对于用户输入通常是一个坏主意,因为失败会使FILE
指针处于未知位置。那是因为scanf
代表“扫描格式化”并且没有比用户输入更多的未格式化。
I would suggest using fgets()
to get a line in, followed by sscanf()
on the string to actually check and process it.
我建议使用fgets()
输入一行,然后sscanf()
在字符串上实际检查和处理它。
This also allows you to check the string for those characters you desire (either via a loop or with a regular expression), something which the scanf
family of functions is not really suited for.
这还允许您检查字符串中是否有您想要的字符(通过循环或使用正则表达式),但scanf
函数系列并不真正适合这种情况。
By way of example, using scanf()
with a "%d"
or "%f"
will stop at the first non-number character so won't catch trailing errors like "127hello"
, which will just give you 127. And using it with a non-bounded %s
is just beggingfor a buffer overflow.
举例来说,使用scanf()
a"%d"
或"%f"
将在第一个非数字字符处停止,因此不会捕获像 那样的尾随错误"127hello"
,它只会给您 127。将它与无界一起使用%s
只是乞求缓冲区溢出。
If you really must use the []
format specifier (in scanf
orsscanf
), I don't think it's meant to be followed by s
.
如果您确实必须使用[]
格式说明符(inscanf
或sscanf
),我认为后面不应该跟s
.
And, for a robust input solution using that advice, see here. Once you have an input line as a string, you can sscanf
to your hearts content.
而且,有关使用该建议的强大输入解决方案,请参阅此处。一旦你有一个输入行作为字符串,你就sscanf
可以满足你的心了。
回答by Johannes Schaub - litb
You seem to want to validate a string as input. It depends on whether you want to validate that your string contains a double or a int. The following checks for a double (leading and trailing whitespace is allowed).
您似乎想验证一个字符串作为输入。这取决于您是否要验证您的字符串是否包含双精度或整数。以下检查双精度(允许前导和尾随空格)。
bool is_double(char const* s) {
int n;
double d;
return sscanf(s, "%lf %n", &d, &n) == 1 && !s[n];
}
sscanf
will return the items converted (without '%n'). n
will be set to the amount of the processed input characters. If all input was processed, s[n] will return the terminating 0 character. The space between the two format specifiers accounts for optional trailing whitespace.
sscanf
将返回转换后的项目(不带 '%n')。n
将设置为处理的输入字符的数量。如果处理了所有输入,则 s[n] 将返回终止字符 0。两个格式说明符之间的空格是可选的尾随空格。
The following checks for an int, same techniques used:
以下检查 int,使用相同的技术:
bool is_int(char const* s) {
int n;
int i;
return sscanf(s, "%d %n", &i, &n) == 1 && !s[n];
}
There was a question on that here, which include also more C++'ish ways for doing this, like using string streams and functions from boost, like lexical_cast and so on. They should generally be preferred over functions like scanf, since it's very easy to forget to pass some '%' to scanf, or some address. scanf won't recognize that, but instead will do arbitrary things, while lexical_cast, for instance, will throw an exception if anything isn't right .
有对一个问题在这里,这也更包括C ++这样做,就像使用字符串流和功能从提升,喜欢的lexical_cast等ISH方式。它们通常比 scanf 之类的函数更受欢迎,因为很容易忘记将某些“%”或某些地址传递给 scanf。scanf 不会认识到这一点,而是会做任意的事情,而 lexical_cast,例如,如果有任何不正确的地方会抛出异常。
回答by qrdl
My approach would be to read user input into string and then convert it to long using strtol()
. strtol()
returns pointer to the first character in input string it failed to process so by checking this character you'd know whether complete string was parsed, like this:
我的方法是将用户输入读入字符串,然后使用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);
In this snippet scanf()
is instructed to automatically allocate string
big enough using format modifier "a" (this is GNU extension). If you are not on GNU, allocate string
manually and limit the max size in scanf()
format.
在此代码段scanf()
中,指示string
使用格式修饰符“a”(这是 GNU 扩展)自动分配足够大的空间。如果您不在 GNU 上,请string
手动分配并限制scanf()
格式的最大大小。
This approach allows better error handling.
这种方法允许更好的错误处理。
回答by hhafez
What you specified in the first argument to scanf
are conversion specifiers. scanf
will try to convert the input to the format but sometimes you might be surprised what it will match against :)
您在第一个参数scanf
中指定的是转换说明符。scanf
将尝试将输入转换为格式,但有时您可能会对它匹配的内容感到惊讶:)
The first check you should do is on the return value from scanf (it will give you the number of matching inputs). If you don't get the number you are expecting then you know that something is wrong with the input. In your case it should be 1.
您应该做的第一项检查是对 scanf 的返回值(它将为您提供匹配输入的数量)。如果您没有得到您期望的数字,那么您就知道输入有问题。在您的情况下,它应该是 1。
if( scanf("%[0987654321.-]s", buf) == 1 )
{
if( sanit_check( buf ) )
{
/* good input */
}
else
{
/* invalid input */
}
}
else
{
/* invalid input */
}
Beyond that you will need to do you own sanity checks on the conversion that you asked scanf
to do.
除此之外,您还需要对您要求scanf
进行的转换进行自己的健全性检查。
回答by SoapBox
If you're trying to read a number only, use:
如果您只想读取数字,请使用:
int i;
scanf( "%d", &i );
If you need to do more complicated checking, you'll have to do it yourself. Scanf won't do it for you.
如果您需要进行更复杂的检查,则必须自己进行。Scanf 不会为你做这件事。
回答by prestomation
"buf" needs to be a pointer. It looks like you are passing by value.
“buf”需要是一个指针。看起来您是按值传递的。