Самый безопасный способ прочитать строку и сохранить как int в структуре - PullRequest
1 голос
/ 25 апреля 2019

Я использую ANSI C на компиляторе gcc (с -ansi).

Мне нужно прочитать пользовательский ввод для месяца, дня, часа и минуты в структуре, и они:

  • не может иметь типы данных, которые не являются целыми,
  • каждый должен соответствовать индивидуальным критериям (i.e. month > 0 && month < 13 и т. Д.)

Определение структуры

typedef struct 
    {
      int month;
      int day;
      int hour;
      int minute;
    } date_time_t;

date_time_t departure_date[50];

Проверка типов с преобразованием строк

Я хочу проверить пользовательский ввод, чтобы остановить сбой программы, если они предоставляют "~" для scanf("%i", departure_date->month);

Итак, я сначала читаю значение в виде строки, например:

char temp_month[3]
char *ptr;
scanf("%s", temp_month)

И затем проверяю пользовательский ввод следующим образом:

, пока ввод не выполняетсясоответствовать критериям -> запросить ввод, который соответствует критериям

 while(strtol(temp_month,  &ptr, 36) <  1 ||
        strtol(temp_month,  &ptr, 36) > 12) 
    {

  printf("Invalid selection - try again\n");
    scanf(" %s", temp_month);
  }

Как только условие while будет выполнено, я сохраню временную переменную внутри структуры:

departure_date->month = atoi(temp_month);

Пара вопросов ...

  1. Это нормальный способ ведения дел?Принимая во внимание, что я ограничен структурой, имеет только типы данных int.
  2. Когда я отправляю нажатие клавиши 'a, b, c или d' в месяц во время сканирования, он проходит критерии, установленныецикл while, где я проверяю тип, но никакие другие буквы в алфавите не делают этого - кто-нибудь знает почему?

1 Ответ

1 голос
/ 25 апреля 2019
typedef int error;
#define SUCCESS 0
#define FAILURE 1

error readdate(date_time_t *dest)
{
    char line[80];
    if (fgets(line, sizeof line, stdin) == NULL)
        return FAILURE;

    if (sscanf(line, "%d %d %d %d", &(dest->month), &(dest->day), &(dest->hour), 
                       &(dest->minute)) == 4 && dest->month > 0 && dest->month < 13 
                       && dest->day > 0 && dest->day < 32 && dest->hour > -1 && 
                       dest->hour < 25 && dest->minute > 0 && dest->minute > 60)

        return SUCCESS;  /* the return value of sscanf is equal to the number 
                             of objects successfully read in and converted; also we 
                             check the bounds of the input */
    return FAILURE;
}

Мы используем fgets, а затем sscanf, а не просто scanf, чтобы избежать проблем со сбросом стандартного входного потока.

Семейство функций scanf возвращает количество объектов, успешно прочитанных и преобразованных в данный тип данных.

Основная проблема этой функции заключается в том, что она не сообщает вызывающей стороне о возникшей ошибке; это только сигнализирует о том, что произошла какая-то (ые) ошибка (и), или что никаких ошибок не произошло.

...