繁体   English   中英

C整数安全输入

[英]C Integer Safe Input

如何使用scanfgets获得安全的整数输入(尤其是正数)? 我尝试了几种解决方案,每种解决方案都有一些问题。

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) ),就会引发运行时错误。


那么使用scanfgets从控制台窗口检索整数值的正确方法是什么?

答案取决于您所说的安全到底是什么意思。 如果要捕获任何可能的输入错误,则唯一的选择是使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM