Как правильно и безопасно использовать sscanf - PullRequest
8 голосов
/ 27 февраля 2012

Прежде всего, другие вопросы об использовании sscanf не отвечают на мой вопрос, потому что общий ответ - вообще не использовать sscanf и использовать fgets или getch, что невозможно в моем случае.

Проблема в том, что мой профессор C хочет, чтобы я использовал scanf в программе.Это требование.Однако программа также должна обрабатывать все неправильные данные.

Программа должна прочитать массив целых чисел.Не имеет значения, в каком формате поставляются целые числа для массива.Чтобы упростить задачу, программа может сначала прочитать размер массива, а затем целые числа, каждая в новой строке.

Программа должна обрабатывать входные данные, подобные этим (и сообщать об ошибках соответственно):

  1. 999999999999999 ... 9 (числа больше целого)
  2. 12a3 (не следует читать это как целое число 12)
  3. a ... z (строки)
  4. 11 aa 22 33 \ n все в одной строке (это можно сделать, отбросив все после 11)
  5. входы больше, чем входной массив

Может бытьболее неправильные случаи - это единственное, о чем я могу подумать.

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

Все должно соответствовать стандарту C99.

Ответы [ 3 ]

10 голосов
/ 27 февраля 2012

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

Если этот объект не имеет подходящего типа, или если результат преобразование не может быть представлено в объекте , поведение недеформированные определенно.

Просто и понятно. Вы можете подумать о %5d трюках и подобных, но вы обнаружите, что они ненадежны. Или, может быть, кто-то подумает об ошибке. scanf функции не обязаны устанавливать errno.

Следуйте за этим забавная маленькая страница : они заканчивают тем, что бросают scanf в целом.


Итак, вернитесь к своему профессору C и спросите их: как именно C99 предписывает, чтобы sscanf сообщал об ошибках ?

1 голос
/ 27 февраля 2012

Если вы должны использовать scanf, чтобы принять ввод, я думаю, вы начнете с чего-то вроде следующего.

int array[MAX];
int i, n;
scanf("%d", &n);
for (i = 0; i < n && !feof(stdin); i++) {
    scanf("%d", &array[i]);
}

Это решит (более или менее) проблему ввода в произвольном формате, поскольку scanf автоматически пропустит начальный пробел при сопоставлении с форматом %d.

Ключевым наблюдением для многих других ваших проблем является то, что scanf сообщает вам, сколько кодов формата он успешно проанализировал. Таким образом,

int matches = scanf("%d", &array[i]);
if (matches == 0) {
   /* no integer in the input stream */
}

Я думаю, что это касается непосредственно (3) и (4)

Само по себе это не совсем обрабатывает регистр ввода 12a3. В первый раз в цикле scanf будет анализировать '12 as an integer 12, leaving the remaining a3` для следующего цикла. Вы получите сообщение об ошибке в следующий раз. Это достаточно хорошо для целей вашего профессора?

Для целых чисел, превышающих maxint , например, "999999 ....... 999", я не уверен, что вы можете сделать с прямыми scanf.

Для входов больше, чем входной массив , это не проблема scanf как таковая . Вам просто нужно посчитать, сколько целых чисел вы уже проанализировали.

Если вам разрешено использовать sscanf для декодирования строк после того, как они были извлечены из входного потока чем-то вроде scanf("%s"), вы также можете сделать что-то вроде этого:

while (...) {
    scanf("%s", buf);
    /* use strtol or sscanf if you really have to */
}

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

1 голос
/ 27 февраля 2012

Хорошо, пусть sscanf принимает все входные данные как% s (т.е. строки), а затем программа анализирует их

...