Как проверить ввод с помощью scanf - PullRequest
5 голосов
/ 19 января 2009

Как я могу проверить ввод пользователя с помощью scanf. Прямо сейчас у меня что-то вроде этого, но не работает.

ПРИМЕЧАНИЕ: у меня есть atoi только для проверки того, что проверка scanf работает.

scanf("%[0987654321.-]s",buf);

i = atoi(buf);

if(i)
    index = i;

Ответы [ 6 ]

15 голосов
/ 19 января 2009

Использование scanf() обычно является плохой идеей для пользовательского ввода, так как сбой оставляет указатель FILE в неизвестной позиции. Это связано с тем, что scanf означает «отформатированный отсканированный», а число неотформатированных немного больше, чем , чем пользовательский ввод.

Я бы предложил использовать fgets() для ввода строки, а затем sscanf() в строке для фактической проверки и обработки.

Это также позволяет вам проверять строку на наличие тех символов, которые вы хотите (либо с помощью цикла, либо с помощью регулярного выражения), для чего семейство функций scanf на самом деле не подходит.

Например, использование scanf() с "%d" или "%f" будет останавливаться на первом нечисловом символе, поэтому не будет отлавливать конечные ошибки, такие как "127hello", что даст вам 127. И использовать его с неограниченным %s - это просто , умоляя переполнить буфер.

Если вам действительно нужно использовать спецификатор формата []scanf или sscanf), я не думаю, что за ним должно следовать s.

И, для надежного решения ввода, использующего этот совет, см. здесь . Если у вас есть строка ввода в виде строки, вы можете sscanf к своему сердцу содержание.

5 голосов
/ 19 января 2009

Кажется, вы хотите проверить строку как ввод. Это зависит от того, хотите ли вы проверить, что ваша строка содержит double или int. Следующие проверки для двойного (разрешены пробелы в начале и в конце).

bool is_double(char const* s) {
    int n;
    double d;
    return sscanf(s, "%lf %n", &d, &n) == 1 && !s[n];
}

sscanf вернет преобразованные элементы (без '% n'). n будет установлено на количество обработанных символов ввода. Если все входные данные были обработаны, s [n] вернет завершающий символ 0. Пробел между двумя спецификаторами формата учитывает необязательные конечные пробелы.

Следующие проверки для int, используемые методы:

bool is_int(char const* s) {
    int n;
    int i;
    return sscanf(s, "%d %n", &i, &n) == 1 && !s[n];
}

Был вопрос об этом здесь , который включает в себя и другие способы C ++ для этого, такие как использование потоков строк и функций из boost, например lexical_cast и так далее. Как правило, они должны быть предпочтительнее таких функций, как scanf, поскольку очень легко забыть передать «%» в scanf или какой-либо адрес. scanf не распознает это, но вместо этого будет делать произвольные вещи, в то время как lexical_cast, например, выдаст исключение, если что-то не так.

1 голос
/ 19 января 2009

Мой подход заключается в том, чтобы прочитать пользовательский ввод в строку, а затем преобразовать его в long, используя strtol(). strtol() возвращает указатель на первый символ входной строки, который он не смог обработать, поэтому, проверив этот символ, вы узнаете, была ли проанализирована полная строка, например:

char *string;
char *endptr;
long result;

scanf("%as", string);
errno = 0;
result = strtol(string, &endptr, 10);
if (ERANGE == errno)
    printf("Input number doesn't fit into long\n");
else if (*endptr)
    printf("%s is not a valid long number - it contains invalid char %c\n",
        string, *endptr);
else
    printf("Got %ld\n", result);

В этом фрагменте scanf() поручено автоматически выделить string достаточно большой, используя модификатор формата "a" (это расширение GNU). Если вы не используете GNU, выделите string вручную и ограничьте максимальный размер в формате scanf().

Этот подход позволяет лучше обрабатывать ошибки.

0 голосов
/ 19 января 2009

"buf" должен быть указателем. Похоже, вы передаете по значению.

0 голосов
/ 19 января 2009

То, что вы указали в первом аргументе scanf, это спецификаторы преобразования . scanf попытается преобразовать ввод в формат, но иногда вы можете быть удивлены тем, с чем он будет совпадать:)

Первая проверка, которую вы должны сделать, - это возвращаемое значение из scanf (оно даст вам количество подходящих входов). Если вы не получили ожидаемое число, вы знаете, что с вводом что-то не так. В вашем случае это должно быть 1.

if( scanf("%[0987654321.-]s", buf) == 1 )
{
      if( sanit_check( buf ) ) 
      {
      /* good input */
      }
      else
      {
      /* invalid input */
      }
}
else 
{
/* invalid input */
}

Кроме того, вам нужно будет самостоятельно проверить работоспособность конверсии, которую вы попросили scanf.

0 голосов
/ 19 января 2009

Если вы пытаетесь прочитать только число, используйте:

int i;
scanf( "%d", &i );

Если вам нужно выполнить более сложную проверку, вам придется сделать это самостоятельно. Scanf не сделает это за вас.

...