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

时间:2018-10-16 07:29:04

标签: c function methods do-while

我目前只能做一小部分作业。 分配的一项要求是

  

“调用一个函数,该函数提示用户输入二次方程的系数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循环中的所有内容组合在一起,以制作一个可以调用三次的大函数?

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

5 个答案:

答案 0 :(得分:3)

  

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

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

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

但是用户是good, bad and ugly,并且**发生了。如果代码要读取一行,对其进行解析以得到一个int范围,并检测到许多问题,则下面的代码将审查许多典型的虚假和恶意输入问题。

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

  • 文件结束
  • 输入流错误
  • 溢出
  • 没有领先的数值测试
  • 跟踪非数字文本
  • 长行过多

首先使用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); 
     }

答案 1 :(得分:2)

  

我的问题是,如何将第一个函数与do / while循环中的所有内容组合在一起,以制作一个可以调用三次的大函数?

嗯,功能不必很大。需要考虑的因素是提示字符串和要读取的变量-后者可以留在调用main()中并从返回值分配。关于如何通常会检查输入,我建议将此检查留给scanf()并仅测试其返回值。

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

int input(char *prompt)
{   // prompts user to input integer
    // reads an integer from standard input and returns it
    int a, s;   // leave it to scanf to check the input:
    while (printf("%s", prompt), fflush(stdout), s = scanf("%d", &a), !s)
    {
        printf("INPUT ERROR!\n");
        do s = getchar(); while (s != '\n' && s != EOF);    // consume bad input
    }
    if (s == EOF) puts(""), exit(0);    // no more input
    return a;
}

然后您可以在main()中做

     a = input("Enter a value for a: ");
     b = input("Enter a value for b: ");
     c = input("Enter a value for c: ");

(无循环)。

答案 2 :(得分:1)

scanf()已经根据格式说明符(%d)为您处理了输入,因此您只需要了解scanf的工作原理并使用它来检查和构建您的功能:)

当您写scanf("%d", &a);时,程序会因为%d的说明而希望写一个整数,如果读取了整数,程序会将其写到变量a中。

但是函数scanf也有一个返回值,即,您可以执行check = scanf("%d", &a);,在这种情况下,check的值为0或1。这是因为返回值记录了已成功读取了多少个值。如果输入dsfugnodg,则没有数字,因此它将返回0。如果输入659 32,它将成功读取第一个值并返回1。

您的函数将类似于:

#include <stdio.h>

int getAndPrint(char label)
{
    int n = 0, val = 0;
    do {
        printf("Enter a value for %c: ", label);
        n = scanf("%d", &val);
        if (n == 0) {
            printf("Error, invalid value entered.\n");
            /* Consume whatever character leads the wrong input 
             * to prevent an infinite loop. See: 
             * https://stackoverflow.com/questions/1669821/scanf-skips-every-other-while-loop-in-c */
            getchar();
        }
    } while (n == 0);
    printf("%c = %d\n", label, val);
    return val;
}

int main()
{
    int a, b, c;
    a = getAndPrint('a');
    b = getAndPrint('b');
    c = getAndPrint('c');
    printf("a=%d, b=%d, c=%d\n", a, b, c);
}

另请参阅: Scanf skips every other while loop in C

答案 3 :(得分:0)

我认为您需要以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>  // for isalpha

void InputAndCheck(int * pValue, const char * pName)
{
    do
    {
        printf("Enter a value for %s: ", pName);
        scanf("%d", pValue);
        if (isalpha(*pValue))
        {
            printf("INPUT ERROR!\n");
            continue;
        }
        else
        {
            break;
        }
    } while (1);

    // clear the input buffer
    fflush(stdin);
    return;
}

int main()
{
    int a, b, c;
    InputAndCheck(&a, "a");
    InputAndCheck(&b, "b");
    InputAndCheck(&c, "c");
    printf("a=%d;b=%d;c=%d;\r\n",a,b,c);
    return 0;
}

答案 4 :(得分:-2)

您正在寻找的是功能介绍。 这是一个:https://www.tutorialspoint.com/cprogramming/c_functions.htm

这是编程中非常重要的构建基块,您绝对应该学习掌握这一概念。

函数将允许您反复在不同的上下文中执行一些代码,而只需更改上下文(参数)即可。

像这样声明

int add(int first, int second){
    //here we can use first and second
    printf("first: %d\n", first);
    printf("second: %d\n", second);

    //and eventually return a value
    return first+second;

}

现在,当使用我们的代码时,我们将重用以前的代码执行任务,结果根据所传递的参数而有所不同。

printf("1+2 = %d\n", add(1, 2));
-->3
printf("2+2 = %d\n", add(2, 2));
-->4

您的任务的示例解决方案:

//this will handle validation
int validateInput(int input){
    if(isalpha(input)){
        printf("INPUT ERROR!\n");
        return 0;
    }
    return 1;
}

//this will prompt the user and return input only if the input is valid
int askForCoefficient(unsigned char coefficientName){
    int valid = 0;
    int value = 0;
    while(!valid){
        printf("Enter a value for %c: ", coefficientName);
        value = scanf("%d", &value);
        valid = validateInput(value);

    }

    printf("%d\n", value);

    return value;

}