首页 > 解决方案 > 提示用户输入整数值并检查有效输入的函数

问题描述

我目前被困在我需要做的任务的一小部分。任务的一项要求是

“调用一个函数,提示用户输入二次方程的系数 a、b 和 c 的每个值,并返回输入的值,并对有效输入进行错误检查(scanf 返回一个值)。”

我不知道该怎么做。我可以很容易地提示用户输入,我可以检查它是否是有效的输入,但我不知道如何把它变成一个函数。我目前的代码是:

   {
   if (isalpha(a))
   {
      printf("INPUT ERROR!\n");
      printf("Enter a value for a: ");
      scanf("%d", &a);
   }
   } //this is how I would normally check the input

   int main(void) //start of main() function definition
   {
      int a, b, c, n, D; //declares integer variables a, b, c, n, and D
      float root1, root2; //declares float variables root1 and root2

      do //do while loop starts here
      {
         printf("Enter a value for a: "); //prompts user to input integer for variable 'a'
         scanf("%d", &a); //reads an integer from the keyboard and stores in the variable 'a' 
         printf("%d\n", a); //returns value of integer that was input for variable 'a'

         printf("Enter a value for b: "); //prompts user to input integer for variable 'b'
         scanf("%d", &b); //reads an integer from the keyboard and stores in the variable 'b'
         printf("%d\n", b); //returns value of integer that was input for variable 'b'

         printf("Enter a value for c: "); //prompts user to input integer for variable 'c'
         scanf("%d", &c); //reads an integer from the keyboard and stores in the variable 'c'
         printf("%d\n", c); //returns value of integer that was input for variable 'c'
         ...}

抱歉任何格式错误,但这基本上是我坚持的程序的一部分。

我的问题是,如何将第一个函数与 do/while 循环中的所有内容结合起来,以创建一个可以调用 3 次的大函数?

我不知道如何使用函数来切换 a for b 和 c 的所有实例,因为我以前从未真正使用过这样的函数。

标签: cfunctionmethodsdo-while

解决方案


提示用户输入整数值并检查有效输入的函数

如果用户只逐行输入有效的整数文本,那么代码很简单:

// Overly idealized case
fputs(prompt, stdout);
char buf[50];
fgets(buf, sizeof buf, stdin);
int i = atoi(buf);

但是用户是好,坏和丑陋的,**它发生了。如果代码想要读取一行,将其解析为 in-rangeint并检测大量问题,下面是审查许多虚假和恶意输入的典型问题的代码。

我特别感兴趣的是检测过长的输入是恶意的,并且作为针对黑客的谨慎设计而无效。int如下所示,几乎没有理由允许超过 20 个字符的 32 位有效输入。这种理性值得更深入的解释。

  • 文件结束
  • 输入流错误
  • 溢出
  • 没有领先的数字测试
  • 尾随非数字文本
  • 线路过长

首先读取一行fgets()输入,然后int应用各种验证测试。如果fgets()没有读取整行,则读取其余部分。

#include <limits.h>
#include <ctype.h>

// Max number of `char` to print an `int` is about log10(int_bit_width)
// https://stackoverflow.com/a/44028031/2410359
#define LOG10_2_N 28
#define LOG10_2_D 93
#define INT_DEC_TEXT (1 /*sign*/ + (CHAR_BIT*sizeof(int)-1)*LOG10_2_N/LOG10_2_D + 1)

// Read a line and parse an integer
// Return:
//   1: Success
//   0: Failure
//   EOF: End-of-file or stream input error
int my_get_int(int *i) {
  // Make room for twice the expected need. This allows for some
  // leading/trailing spaces, leading zeros, etc.
  //           int        \n  \0
  char buf[(INT_DEC_TEXT + 1 + 1) * 2];
  if (fgets(buf, sizeof buf, stdin) == NULL) {
    *i = 0;
    return EOF; // Input is either at end-of-file or a rare input error.
  }
  int success = 1;

  char *endptr;
  errno = 0;
  long value = strtol(buf, &endptr, 10);


  // When `int` is narrower than `long`, add these tests
#if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
  if (value < INT_MIN) {
    value = INT_MIN;
    errno = ERANGE;
  } else if (value > INT_MAX) {
    value = INT_MAX;
    errno = ERANGE;
  }
#endif
  *i = (int) value;
  if (errno == ERANGE) {
    success = 0;  // Overflow
  }

  if (buf == endptr) {
    success = 0; // No conversion
  }

  // Tolerate trailing white-space
  // Proper use of `is...()` obliges a `char` get converted to `unsigned char`.
  while (isspace((unsigned char ) *endptr)) {
    endptr++;
  }

  // Check for trailing non-white-space
  if (*endptr) {
    success = 0; // Extra junk
    while (*endptr) {  // quietly get rest of buffer
      endptr++;
    }
  }

  // Was the entire line read?
  // Was the null character at the buffer end and the prior wasn't \n?
  const size_t last_index = sizeof buf / sizeof buf[0] - 1;
  if (endptr == &buf[last_index] && buf[last_index - 1] != '\n') {
    // Input is hostile as it is excessively long.
    success = 0;  // Line too long
    // Consume text up to end-of-line
    int ch;
    while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
      ;
    }
  }

  return success;
}

示例使用

     puts("Enter a value for a: ", stdout);
     fflush(stdout);  // Insure output is seen before input.
     int a;
     if (my_get_int(&a) == 1) {
       printf("a:%d\n", a); 
     }

推荐阅读