我想从标准输入读取一个 int,但我想验证用户是否超过了 int 最大值。我该怎么做?
int n;
scanf("%d", &n);
scanf 读取十进制输入并存储在 int 中,导致溢出。我该如何检查和避免这种情况?
将数字的字符串表示形式转换为实际值并观察溢出的唯一方法是使用strto..
group 中的函数。在您的情况下,您需要读取数字的字符串表示形式,然后使用strtol
函数对其进行转换。
请注意建议使用atoi
或sscanf
执行最终转换的响应。这些函数都不能防止溢出。
另一种方法是设置要解析的最大位数。
例如:
int n;
scanf("%5d", &n); // read at most 5 digits
printf("%i\n", n);
Two methods come to mind.
The first is useful if you know the input is integer-like only input, but suffers from "slightly" exceeding integer range:
long x;
if (1 != scanf("%ld", &x))
error "not a number or other i/o error"
else
if (x < -MAXINT || x > MAXINT)
error "exceeds integer range"
else printf "it is an integer";
This has a lot of dependency on the compiler and platform. Note that the C language guarantees only that long
is greater than or equal to the size of int
. If this is run on a platform where long
and int
are the same size, it is a useless approach.
The second approach is to read the input as a string and parse straightforwardly:
char buf [1000];
if (1 != scanf ("%1000s", buf))
error "i/o error";
size_t len = strspn (buf, "0123456789+-");
if (len != strlen (buf))
error "contains invalid characters";
long number = 0;
int sign = 1;
for (char *bp = buf; *bp; ++bp)
{
if (*bp == '-')
{
sign = -sign;
continue;
}
if (*bp == '+')
continue;
number = number * 10 + *bp - '0';
if (number > MAXINT)
error "number too large";
}
if (sign < 0)
number = -number;
This code has several weaknesses: it depends on long
being larger than int
; it allows plus and minus to appear anywhere in the string. It could be easily extended to allow other than base ten numbers.
A possible third approach might be to input a string check the character set and use a double
conversion to range check.
根据ISO C11 标准的§7.21.6.2 ¶10scanf
,如果无法表示函数执行的转换结果,则行为未定义。因此,这个函数不能可靠地用于输入验证的目的。
但是,当使用函数将字符串转换为整数时strtol
,如果发生范围错误,则行为是明确定义的。在这种情况下errno
将设置为ERANGE
。这将告诉您用户输入的数字是否超出long
. 如果要确定它是否超出 的范围int
,则必须另外验证该数字是否大于或等于INT_MIN
且小于或等于INT_MAX
。请注意,您必须#include <limits.h>
使用这些常量。
因此,我建议使用以下代码从用户那里读取一个数字并对其进行验证:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
int main( void )
{
char buffer[1024], *p;
long num_long;
int num_int;
//prompt user for input
printf( "Enter a number: " );
//get one line of input from input stream
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "Unrecoverable error reading from input!\n" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, '\n' ) == NULL )
{
printf( "Line input was too long!\n" );
exit( EXIT_FAILURE );
}
//attempt to convert string to number
errno = 0;
num_long = strtol( buffer, &p, 10 );
if ( p == buffer )
{
printf( "Error converting string to number\n" );
exit( EXIT_FAILURE );
}
//make sure that no range error occurred
if ( errno == ERANGE || num_long < INT_MIN || num_long > INT_MAX )
{
printf( "Range error!\n" );
exit( EXIT_FAILURE );
}
//range is ok, so we can convert to int
num_int = (int)num_long;
//make sure that remainder of line contains only whitespace,
//so that input such as "6sdfh4q" gets rejected
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Unexpected input encountered!\n" );
exit( EXIT_FAILURE );
}
}
//number was successfully converted, so we print it
printf( "You entered the following valid number: %d\n", num_int );
}
输入有效数字时此程序的示例输出:
Enter a number: 65
You entered the following valid number: 65
输入无效输入时此程序的示例输出:
Enter a number: 6sdfh4q
Unexpected input encountered!
输入超出范围输入时此程序的示例输出:
Enter a number: 3000000000
Range error!
将其读入字符串并检查长度,然后在字符串上调用atol()
或sscanf()
将其转换为 int。