[英]C Integer Safe Input
如何使用scanf
或gets
获得安全的整数输入(尤其是正数)? 我尝试了几种解决方案,每种解决方案都有一些问题。
1.使用getchar()
删除字符串输入
int safeInput() {
int input;
scanf("%d", &input);
while(getchar() != '\n');
return input;
}
此方法有效地处理输入字符串,但是,如果字符串如3a
被输入时,的值input
变为3
,这是不是真正的异常处理。
2.以字符串形式检索输入,然后转换为整数值。
int safeInput() {
char[200] input, safe_input;
gets(input);
// I know about the security issue about gets - but it's not the point.
int i = 0;
while (1) {
if (input[i] >= 48 && input[i] <= 57) safe_input[i] = input[i];
else break;
i++;
}
return atoi(safe_input);
}
该方法存在以下问题:如果输入的字符串长度大于分配给input
字符串,则无法处理。
3.如果使用指针定义字符串怎么办?
我关心通过指针定义input
,例如char *input;
。 但是,一旦我执行gets(input)
(或scanf("%s", input)
),就会引发运行时错误。
那么使用scanf
或gets
从控制台窗口检索整数值的正确方法是什么?
答案取决于您所说的安全到底是什么意思。 如果要捕获任何可能的输入错误,则唯一的选择是使用strtol()
系列的函数,该strtol()
甚至可以进行范围检查。 在远离scanf()
新手指南中 ,我描述了它的用法。
这是适合您在此处尝试的代码,并带有注释:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
// return success as boolean (0, 1), on success write result through *number:
int safeInput(int *number)
{
long a;
char buf[1024]; // use 1KiB just to be sure
if (!fgets(buf, 1024, stdin))
{
// reading input failed:
return 0;
}
// have some input, convert it to integer:
char *endptr;
errno = 0; // reset error number
a = strtol(buf, &endptr, 10);
if (errno == ERANGE)
{
// out of range for a long
return 0;
}
if (endptr == buf)
{
// no character was read
return 0;
}
if (*endptr && *endptr != '\n')
{
// *endptr is neither end of string nor newline,
// so we didn't convert the *whole* input
return 0;
}
if (a > INT_MAX || a < INT_MIN)
{
// result will not fit in an int
return 0;
}
// write result through the pointer passed
*number = (int) a;
return 1;
}
首先,如果您想要安全的输入, 请不要使用gets
。 当您可以使用fgets
时, fgets
您对这些问题的了解并不是真正的借口。 接下来,诀窍是尝试在int之后读取一个非空白字符:如果找不到任何人,则int后面没有任何内容。
int safeInput(int *input) { // the return value is the indicator of failed read
int c;
char dummy[2]; // never forget the terminating null!
if (scanf("%d%1s", input, dummy) == 1) return 1;
// in case of error, skip anything up to end of line or end of file
while (((c = fgetc(stdin)) != '\n') && (c != EOF));
return 0;
}
这里的scanf
是,当scanf
返回1时, %1s
一直吃到行尾的所有内容, 包括终止符' n'
。 但这有一个主要缺点: scanf
将仅在流的结尾或读取一个附加的(非空白)字符后结束。 因此,Felix Palmen的答案使用起来更容易,更安全。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.