C整数安全输入

C整数安全输入,c,integer,scanf,gets,C,Integer,Scanf,Gets,如何使用scanf或gets获得整数(尤其是正数)的安全输入?我尝试了几种解决方案,每种解决方案都有一些问题 1。使用getchar()删除字符串输入 int safeInput() { int input; scanf("%d", &input); while(getchar() != '\n'); return input; } 此方法有效地处理字符串输入,但是,如果输入了3a等字符串,则input的值变为3,这不是真正的异常句柄 2。以字符串形式检

如何使用
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);
}
int-safeInput(){
字符[200]输入,安全输入;
获取(输入);
//我知道gets的安全问题,但这不是重点。
int i=0;
而(1){

如果(输入[i]>=48&&input[i]首先,如果你想要一个安全的输入,不要使用
get
。当你可以使用
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
返回1时,
%1s
已经吃掉了行末尾的任何东西,包括终止的“
n”
。但这有一个主要缺点:
scanf
只会在流的末尾或在读取一个额外的(非空)后结束字符。因此,Felix Palmen的答案使用起来更简单、更安全。

首先,如果你想要一个安全的输入,不要使用
gets
当你可以使用
fgets
时,说你知道这些问题并不是一个真正的借口。接下来,诀窍是尝试读取int后面的一个非空字符:如果你没有找到one,那么在这行的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
返回1时,
%1s
已经吃掉了行末尾的任何东西,包括终止的“
n”
。但这有一个主要缺点:
scanf
只会在流的末尾或在读取一个额外的(非空)后结束字符。因此,Felix Palmen的答案使用起来更简单、更安全。

答案取决于您所说的“安全”的确切含义。如果您想捕获任何可能的输入错误,您唯一的选择就是使用
strtol()
系列的函数,它甚至允许范围检查。在我的文章中,我将介绍它的用法

以下是与您在此处尝试的内容相适应的代码,并附有注释:

#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;
}
#包括
#包括
#包括
#包括
//将成功返回为布尔值(0,1),成功时通过*号写入结果:
整数安全输入(整数*数字)
{
长a;
char buf[1024];//使用1KiB只是为了确保
如果(!fgets(buf,1024,stdin))
{
//读取输入失败:
返回0;
}
//有一些输入,将其转换为整数:
char*endptr;
errno=0;//重置错误号
a=标准温度(buf和endptr,10);
if(errno==ERANGE)
{
//长时间在射程之外
返回0;
}
如果(endptr==buf)
{
//没有读到任何字符
返回0;
}
如果(*endptr&&*endptr!='\n')
{
//*endptr既不是字符串的结尾,也不是换行符,
//所以我们没有转换整个输入
返回0;
}
如果(a>INT_MAX | a
答案取决于您所说的“安全”的确切含义。如果您想捕获任何可能的输入错误,您唯一的选择是使用
strtol()
系列的函数,它甚至允许进行范围检查。在我的文章中,我描述了它的用法

以下是与您在此处尝试的内容相适应的代码,并附有注释:

#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;
}
#包括
#包括
#包括
#包括
//将成功返回为布尔值(0,1),成功时通过*号写入结果:
整数安全输入(整数*数字)
{
长a;
char buf[1024];//使用1KiB只是为了确保
如果(!fgets(buf,1024,stdin))
{
//读取输入失败:
返回0;
}
//有一些输入,将其转换为整数:
char*endptr;
errno=0;//重置错误号
a=标准温度(buf和endptr,10);
if(errno==ERANGE)
{
//长时间在射程之外
返回0;
}
如果(endptr==buf)
{
//没有读到任何字符
返回0;
}
如果(*endptr&&*endptr!='\n')
{
//*endptr既不是字符串的结尾,也不是换行符,
//所以我们没有转换整个输入
返回0;
}
如果(a>INT_MAX | a
不要使用
gets
。关于第三种方法:
char*input;
只是声明一个指针,但是
input
没有指向任何地方,它没有初始化。阅读C教科书中关于指针的章节。不要使用
gets
。改用
fgets
。那么方法2有什么问题吗?1.逐行阅读(
fgets()
),2.解析输入(
strtol()
和朋友)。另请参见我的。@GreenRoof well没有NUL终止符完全是错误的。是的,如果使用
get
,输入溢出是一个问题。如果使用
fgets
,则不是问题。不要使用
get
。关于第三种方法:
char*input;
只是声明了一个指针,但
input
没有指向任何地方,它不是我初始化。阅读C教科书中有关指针的章节。在上,不要使用
get
。而是使用
fgets
。那么方法2有什么问题吗?1.逐行阅读(
fgets()
),2.解析输入(
strtol()
和friends).另请看我的。@GreenRoof没有NUL终结者是完全错误的。是的,inpu