【问题标题】:How to check input with scanf?如何使用scanf检查输入?
【发布时间】:2020-04-17 07:31:04
【问题描述】:

我有以下代码:

#include <stdio.h>

void printMenu() {
    printf("********************************\n");
    printf("*Enter a number (-1 to exit):  *");
    printf("\n* 1 - Add new student          *");
    printf("\n* 2 - Delete a student         *");
    printf("\n* 3 - Update student           *");
    printf("\n* 4 - Print a student          *");
    printf("\n* 5 - Print all students       *");
    printf("\n********************************\n");
    printf("\nEnter: ");
}

int main (int argc, char **argv) {
    int a;

    printMenu();
    scanf("%d", &a);

    while(a != -1) {
        switch(a) {
            case 1:     
                printf("1\n");
                break;
            case 2:     
                printf("2\n");
                break;
            case 3:         
                printf("3\n");
                break;
            case 4:         
                printf("4\n");
                break;
            case 5:         
                printf("5\n");
                break;
            default:       
                printf("\nInvalid answer!\n");
                break;
        }
       
        puts("");
        printMenu();
        scanf("%d", &a);  
    }
    return 0;
} 

我想检查scanf 的输入。例如,如果用户输入一个数字,它会成功运行,但是如果用户输入一个字符串或字符之类的东西,它会一次又一次地不停地打印菜单。

我想检查用户是否输入了数字。如果没有,我想再次询问输入。 我试过这样的事情:

if(scanf("%d", &a)!=1) {
     printf("Enter again: ");
     scanf("%d", &a);
}

或者:

assert(scanf("%d", &a);

assert 函数程序停止执行,但我希望它在一段时间后继续执行。 有什么想法吗?

【问题讨论】:

标签: c input scanf


【解决方案1】:

在处理交互式输入时,我觉得总是很方便 消耗输入行,然后分析它。
这样,无论在输入上给出什么(符合预期 与否),它不会留在输入流中阻止进一步分析。

一般是这样的

/**
  gcc -std=c99 -o prog_c prog_c.c \
      -pedantic -Wall -Wextra -Wconversion \
      -Wc++-compat -Wwrite-strings -Wold-style-definition -Wvla \
      -g -O0 -UNDEBUG -fsanitize=address,undefined
**/

#include <stdio.h>

int
main(void)
{
  for(;;)
  {
    printf("Please, provide something interesting: ");
    char input_line[0x100];
    if(!fgets(input_line, sizeof(input_line), stdin))
    {
      printf("no more input\n");
      break; // leave the loop
    }
    int answer;
    if(sscanf(input_line, "%d", &answer)!=1)
    {
      printf("an integer was expected.\n");
      continue; // go back to the prompt
    }
    printf("%d + %d = %d\n", // make use of the provided information
           answer, answer, answer+answer);
  }
  return 0;
}

【讨论】:

    【解决方案2】:

    但如果用户输入类似字符串或字符的内容(例如 a 或 grebv),它会一次又一次地不间断地打印菜单

    这是因为当 scanf 失败时没有读取任何内容,因此您必须绕过非数字,例如使用 getchar/fgets 读取到行尾。警告您还必须管理 EOF 的情况,例如,因为 stdin 在文件中被重定向。

    待办事项:

    if(scanf("%d", &a)!=1) {
         printf("Enter again: ");
         scanf("%d", &a);
    }
    

    即使在第二个 scanf 之前添加无效输入的刷新也是不够的,因为您可能有两个或多个连续错误(第二个 scanf 也失败)。

    一种方式可以是例如:

    #include <stdio.h>
    
    void printMenu() {
      fputs("********************************\n"
            "*Enter a number (-1 to exit):  *\n"
            "* 1 - Add new student          *\n"
            "* 2 - Delete a student         *\n"
            "* 3 - Update student           *\n"
            "* 4 - Print a student          *\n"
            "* 5 - Print all students       *\n"
            "********************************\n"
            "\nEnter: ", stdout);
    }
    
    int main()
    {
      int a;
    
      do {
        printMenu();
    
        if (scanf("%d", &a) != 1) {
          /* flush invalid input up to the end of line */
          while ((a = getchar()) != '\n') {
            if (a == EOF) {
              puts("...EOF...");
              return -1;
            }
          }
          a = 0; /* any 'invalid' value managed in the 'default' case of the 'switch'*/
        }
    
        switch (a) {
        case -1:
          break; /* or 'return 0;' and the 'do while' is a 'for(;;)' */
        case 1:     
          printf("1\n");
          break;
        case 2:     
          printf("2\n");
          break;
        case 3:         
          printf("3\n");
          break;
        case 4:         
          printf("4\n");
          break;
        case 5:         
          printf("5\n");
          break;
        default:
          puts("\nInvalid answer!");
          break;
        }
      } while (a != -1);
    
      return 0;
    }
    

    编译和执行:

    /tmp % gcc -Wall a.c
    /tmp % ./a.out
    ********************************
    *Enter a number (-1 to exit):  *
    * 1 - Add new student          *
    * 2 - Delete a student         *
    * 3 - Update student           *
    * 4 - Print a student          *
    * 5 - Print all students       *
    ********************************
    
    Enter: 1
    1
    ********************************
    *Enter a number (-1 to exit):  *
    * 1 - Add new student          *
    * 2 - Delete a student         *
    * 3 - Update student           *
    * 4 - Print a student          *
    * 5 - Print all students       *
    ********************************
    
    Enter: aze
    
    Invalid answer!
    ********************************
    *Enter a number (-1 to exit):  *
    * 1 - Add new student          *
    * 2 - Delete a student         *
    * 3 - Update student           *
    * 4 - Print a student          *
    * 5 - Print all students       *
    ********************************
    
    Enter: 2
    2
    ********************************
    *Enter a number (-1 to exit):  *
    * 1 - Add new student          *
    * 2 - Delete a student         *
    * 3 - Update student           *
    * 4 - Print a student          *
    * 5 - Print all students       *
    ********************************
    
    Enter: -1
    /tmp % 
    /tmp % ( echo 1 ; echo aze ; echo 2 ) | ./a.out
    ********************************
    *Enter a number (-1 to exit):  *
    * 1 - Add new student          *
    * 2 - Delete a student         *
    * 3 - Update student           *
    * 4 - Print a student          *
    * 5 - Print all students       *
    ********************************
    
    Enter: 1
    ********************************
    *Enter a number (-1 to exit):  *
    * 1 - Add new student          *
    * 2 - Delete a student         *
    * 3 - Update student           *
    * 4 - Print a student          *
    * 5 - Print all students       *
    ********************************
    
    Enter: 
    Invalid answer!
    ********************************
    *Enter a number (-1 to exit):  *
    * 1 - Add new student          *
    * 2 - Delete a student         *
    * 3 - Update student           *
    * 4 - Print a student          *
    * 5 - Print all students       *
    ********************************
    
    Enter: 2
    ********************************
    *Enter a number (-1 to exit):  *
    * 1 - Add new student          *
    * 2 - Delete a student         *
    * 3 - Update student           *
    * 4 - Print a student          *
    * 5 - Print all students       *
    ********************************
    
    Enter: ...EOF...
    /tmp % 
    

    【讨论】:

      猜你喜欢
      • 2021-12-25
      • 1970-01-01
      • 2023-03-18
      • 2019-02-23
      • 2015-06-09
      • 2021-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多