- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
typedef enum { SUCCESS = 0, NOTNUMBER = 1, BOUNDS = 2, EOFREACHED = 3 } rdstat_t;
int flush_line(FILE *stream) {
  int ch;
  do {
    ch = fgetc(stream);
  } while (ch != EOF && ch != '\n');
  return ch;
}
/* enough to contain (1 + length of ASCII string of SIZE_MAX
   decimal representation) characters */
#define SIZE_T_BUF_SIZE 100
/* reads until newline or EOF, writes (size_t *out) if success */
rdstat_t read_size_t(FILE *stream, size_t *out) {
  char str_SIZE_MAX[SIZE_T_BUF_SIZE];
  snprintf(str_SIZE_MAX, SIZE_T_BUF_SIZE, "%zu", SIZE_MAX);
 
  char buf[SIZE_T_BUF_SIZE];
  if (!fgets(buf, SIZE_T_BUF_SIZE, stream)) 
    return EOFREACHED;
  if (buf[strlen(buf) - 1] != '\n') {
    flush_line(stream);
    return NOTNUMBER;
  }
  buf[strlen(buf) - 1] = 0;
  char *ch;
  for (ch = buf; *ch; ++ch)
    if (!isdigit(*ch)) 
      return NOTNUMBER;
  if (strlen(buf) == strlen(str_SIZE_MAX) && strcmp(buf, str_SIZE_MAX) > 0) 
      return BOUNDS;
    
  sscanf(buf, "%zu", out);
  return SUCCESS;
}
                                 
        
            Наваял функцию для чтения size_t из файла с защитой от дурака (писал код будучи больным, чесслово).
Ничего умнее печати SIZE_MAX в строчку и лексикографического сравнения для проверки границ введенного числа не придумал %)
        
        
верю.
sscanf() + "%n" + проверки постафактумом.
Тогда уж strtoul/strtoull, к ним проверки проще привернуть.
P.S. Я вот слабо представляю, как проверять диапазон по количеству символов, прочтённых scanf'ом.
Пример для 32-битного числа: 8589934591. scanf() спарсит его как 4294967295. Количество цифр абсолютно одинаковое.
просто забить на эту глупую проверку.
все равно не помогает, если пользователь вводит неправильное число (типа 2 вместо 1). и это случается на несколько порядков чаще чем ввод числа близкого к пределу значений.
к слову. у меня на одном прошлом проекте, чудаки в конфигах этим страдали: они писали "none"/"not available" вместо "0" (что atoi() послушно парсил) в тех местах где значения было запрещено менять с дефолтов. для кого то возможность неправильного ввода это баг - для других это фича.
если у тебя такой юз-кейс есть, то это уже говно само по себе.
тут уже про "наименьшее удивление" пользователя говорить поздно: скорее всего пользователь каждый раз материться когда система хочет что бы он 9-ти-значное число (посчитал и) ввел.
это обработка ввода пользователя, в той или иной форме.
ввод пользователя должен обрабатыватся толерантно и временами с умом и гибкостью.
на шкале толерантности, я может быть слегка перехожу типичные границы. но это же опять навеяно личным опытом работы с пользователями и консультантами, которые этот ввод должны делать постоянно. и которые должны эти мессаджбоксы ошыбок ввода постоянно закрывать.
и к слову в моем случае это больше из Перла, нежели чем С. на Перле я начинал с харкорных проверок всего что только можно (потому что в перле легко делаются). но годы спустя, я в некоторых местах скатывался почти до ввода на естественном языке (было больше шуткой, но работало).
Это всегда зависит от контеста. В каком процес-ориентед приложении, это 100% нормальный код. (Да, есть еще области и люди которые линейную последовательность действий программируют как линейную последовательность действий, а не (типичный для жабы) кластерфак иерархий классов.)
http://ideone.com/01QhDE
Аааааа.
и заменить на