Как проверить ввод с помощью scanf? - PullRequest
0 голосов
/ 17 апреля 2020

Привет, ребята. У меня есть следующий код:

#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. Например, если пользователь вводит число, оно работает успешно, но если пользователь вводит что-то вроде строки или символа (например, a или grebv), он печатает без остановки меню снова и снова.

Я хотел бы проверить если пользователь вводит номер или нет. Если нет, я хотел бы спросить еще раз о входе. Я пробовал такие вещи, как:

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

Или:

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

С assert функция программирования перестает выполняться, но я хочу, чтобы она продолжалась через некоторое время. Есть идеи?

Ответы [ 2 ]

1 голос
/ 17 апреля 2020

При работе с интерактивным вводом я считаю удобным всегда использовать строку ввода, а затем анализировать ее.
Таким образом, что бы ни было дано на входе (соответствует ожиданиям или нет), оно не останется в входной поток блокирует дальнейший анализ.

Это обычно выглядит так

/**
  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;
}
0 голосов
/ 17 апреля 2020

, но если пользователь вводит что-то вроде строки или символа (например, a или grebv), он печатает без остановки меню снова и снова

это потому, что когда scanf не удается ничего не читается, поэтому вы должны обойти не число, например, чтение до конца строки с getchar / fgets . Предупреждение: вам также нужно управлять регистром EOF, например, потому что stdin перенаправлен в файл.

Для этого:

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

недостаточно даже добавить flu sh недопустимого ввода перед вторым 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 % 
...