输入错误的程序(C)后程序会发疯

时间:2019-02-01 08:31:29

标签: c input stdin

我有一个应该从stdin获取数字的函数。应该检查它是否为有效数字,并可以选择在特定范围之间进行设置。如果输入相当长(例如10个字符),则该函数将打印错误消息并重置循环,一切都会按预期进行。但是,如果我输入的时间太长了,就像这样:

1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

然后出了点问题。循环会不断重置,但无论我输入什么内容,即使它完全有效,它也不再接受它。

我想这可能是因为stdin溢出了吗?但这不是fgets()的意义吗?它只读取特定数量的字符,并丢弃其他所有字符?在不使用异常的情况下如何解决这个问题?

有问题的函数:

int safeinp(int * num, const char *message, int low, int high)
{
    long a;
    char buf[11]; // 9 digits for the number + "\n\0"
    int success; // flag for successful conversion

    do
    {
        puts(message);
        if (!fgets(buf, 11, stdin))
        {
            fprintf(stderr, "Unagle to obtain input.\n");
            return 1;
        }

        // have some input, convert it to integer:
        char *endptr;

        a = strtol(buf, &endptr, 12);
        if (errno == ERANGE)
        {
//this if() right here is what gets executed endlessly if the input is bad
                fprintf(stderr, "Invalid number.\n");
                success = 0;
            }
            else if (endptr == buf)
            {
                fprintf(stderr, "Invalid input.\n");
                success = 0;
            }
            else if (*endptr && *endptr != '\n')
            {
                fprintf(stderr, "Conversion error.\n");
                success = 0;
            }
            else
            {
                success = 1;
                if (low != high) {
                    a = (a < low) ? fprintf(stderr, "Input has been adjusted to fit the bounds.\n"), low : a;
                    a = (a > high) ? fprintf(stderr, "Input has been adjusted to fit the bounds.\n"), high : a;
                }
                *num = a;
            }
        } while (!success); 
        return success;
    }

问题发生在Visual Studio 2017 for Windows 10中。

2 个答案:

答案 0 :(得分:2)

否,fgets() 不会清空“缓冲区”。如果输入长字符串,则代码每次将读取10个字符,直到到达输入的行尾。下一个循环将再次等待。

精简示例:

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char **argv)
{
  char buf[11];

  do {
    puts("TEST");
    fflush(stdout);
    if (!fgets(buf, sizeof(buf), stdin)) {
      fprintf(stderr, "Unagle to obtain input.\n");
      return 1;
    }

    printf("input: %s\n", buf);
  } while (1);

  return(0);
}

试运行:

$ gcc -Wall -o dummy dummy.c
$ ./dummy 
TEST
123456789012345678901234567890
input: 1234567890
TEST
input: 1234567890
TEST
input: 1234567890
TEST
input: 

TEST
^C
$

更新:该提案尝试吃掉所有剩余的字符,直到换行符为止:

    /* replacement for fgets(buf, sizeof(buf), stdin) */
    char *p = buf;
    char c;
    unsigned left = sizeof(buf) - 1;
    while ((left-- > 0) && ((c = fgetc(stdin)) != '\n')) {
      if (feof(stdin)) {
        return(1);
      }
      *p++ = c;
    }
    *p++ = '\0';

    /* eat the rest until newline */
    while (c != '\n') {
      c = fgetc(stdin);
      if (feof(stdin)) {
        return(1);
      }
    }

新的测试运行:

$ gcc -Wall -o dummy dummy.c
$ ./dummy 
TEST
123456789012345678901234567890
input: 1234567890
TEST
1
input: 1
TEST
1234567890
input: 1234567890
TEST
^C

答案 1 :(得分:2)

a返回strtolLONG_MIN后,您需要检查LONG_MAX。不能保证正确解析输入后未将errno设置为ERANGE

       The  strtol() function returns the result of the conversion, unless the
       value would underflow or overflow.  If an  underflow  occurs,  strtol()
       returns  LONG_MIN.   If  an overflow occurs, strtol() returns LONG_MAX.
       In both cases, errno is set to ERANGE.

libc函数不会成功重置errno

此外,您在strtol(..,.., base)->您的基数是12