Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何防止使用scanf的输入溢出?_C_Integer_Overflow_Scanf - Fatal编程技术网

如何防止使用scanf的输入溢出?

如何防止使用scanf的输入溢出?,c,integer,overflow,scanf,C,Integer,Overflow,Scanf,我对C比较陌生,想知道如何防止输入溢出 例如,我有: scanf("%d", &a); 其中a是一个整数 那么我能做些什么来阻止某人输入一个大于最大整数的数字呢?由于我正在处理的问题的限制,您必须使用scanf。如何限制输入?防止用户输入非常具有挑战性。 没有魔法之手可以伸出手来阻止用户不断敲击键盘 但是代码可以限制它读取的内容 scanf()很难限制。它可能不会在溢出时设置errno。代码可以将char的数量限制为9。这是第一步,但不能输入“100000000”或

我对C比较陌生,想知道如何防止输入溢出

例如,我有:

scanf("%d", &a);
其中a是一个整数

那么我能做些什么来阻止某人输入一个大于最大整数的数字呢?由于我正在处理的问题的限制,您必须使用
scanf
。如何限制输入?

防止用户输入非常具有挑战性。
没有魔法之手可以伸出手来阻止用户不断敲击键盘

但是代码可以限制它读取的内容

  • scanf()
    很难限制。它可能不会在溢出时设置
    errno
    。代码可以将char的数量限制为9。这是第一步,但不能输入“100000000”或“0000000000000000 1”之类的值

  • 学究式的方法会使用
    fgetc()
    。下面是一个
    无符号
    方法
    int
    需要更多的时间

    unsigned a = 0;
    int ch = fgetc(stdin);
    while (isspace(ch)) {
      ch = fgetc(stdin);
    }
    while (isdigit(ch)) {
      ch -= '0';
      if (a >= UINTMAX/10 && (a > UINTMAX/10 || ch > UINTMAX%10)) {
        a = UINTMAX;
        break;  // overflow detected.
      }
      a = a*10 + ch;
      ch = fgetc(stdin);
    }
    ungetc(ch, stdin);  // Put back `ch` as it was not used.
    
  • 但我更喜欢改变目标,简单地再次告诉用户,即使这意味着阅读更多的字符

    // 0:success or EOF
    int Read_int(const char *prompt, int *dest, int min, int max) {
      for (;;) {
        char buf[(sizeof(int)*3 + 3)*2];  // 2x generous buffer
        fputs(prompt, stdout);
        if (fgets(buf, sizeof buf, stdin) == NULL) {
          return EOF;
        }
        char *endptr;
        errno = 0;
        long l = strtol(buf, &endptr, 10);
        // no conversion or junk at the end ....
        if (buf == endptr || *endptr != '\n') {
          continue;
        }
        if (!errno && l >= min && l <= max) {
         *dest = (int) l;
         return 0; // success
        }
      }
    }  
    
    // Sample usage
    int a;
    Read_int("Enter an `int`\n", &a, INT_MIN, INT_MAX);
    
    //0:成功还是失败
    int Read_int(常量字符*提示符,int*dest,int min,int max){
    对于(;;){
    char buf[(sizeof(int)*3+3)*2];//2x缓冲区
    FPUT(提示、标准输出);
    if(fgets(buf,sizeof buf,stdin)=NULL){
    返回EOF;
    }
    char*endptr;
    errno=0;
    长l=strtol(buf和endptr,10);
    //最后没有转换或垃圾。。。。
    如果(buf==endptr |*endptr!='\n'){
    继续;
    }
    
    如果(!errno&&l>=min&&l使用
    scanf
    读取字符串,然后自己解析它?理论上,您可以看到errno是否是超出范围错误的ERANGE。但是这不是为scanf指定的标准。请参阅
    “C89和C99以及POSIX.1-2001标准没有指定ERANGE错误”
    ,换句话说,您应该使用
    strtol
    如果您需要读取整数,同时还需要检查溢出。如果必须使用scanf,一种简单的方法是读取
    双精度
    ,而不是使用scanf(范围更大),执行您自己的范围检查,然后将结果转换为
    int
    ,如果它符合您的条件。只要您的有效整数范围不太大,这将不会丢失信息。@Brandin:ANSI-C规范确实规定匹配一个数字序列,然后使用strtol函数转换。因此,如果该值太大,则一个long,你会得到一个ERANGE。但是,如果它对于int来说太大,但是适合一个long,那么会发生什么呢。
    // 0:success or EOF
    int Read_int(const char *prompt, int *dest, int min, int max) {
      for (;;) {
        char buf[(sizeof(int)*3 + 3)*2];  // 2x generous buffer
        fputs(prompt, stdout);
        if (fgets(buf, sizeof buf, stdin) == NULL) {
          return EOF;
        }
        char *endptr;
        errno = 0;
        long l = strtol(buf, &endptr, 10);
        // no conversion or junk at the end ....
        if (buf == endptr || *endptr != '\n') {
          continue;
        }
        if (!errno && l >= min && l <= max) {
         *dest = (int) l;
         return 0; // success
        }
      }
    }  
    
    // Sample usage
    int a;
    Read_int("Enter an `int`\n", &a, INT_MIN, INT_MAX);