Это часто обсуждаемая тема, полная мнений, но тем не менее интересная. Я заметил, что подавляющее большинство тех, кто уже ответил на аналогичные вопросы на этом сайте, придерживаются fgets()
. Я один из них. Я нахожу fgets()
чтобы было намного лучше использовать для пользовательского ввода, чем scanf()
за редким исключением. scanf()
рассматривается многими как неоптимальный метод обработки пользовательского ввода. Например
"...он скажет вам, удалось ли ему это или нет, но может сказать вам только приблизительно, где он потерпел неудачу, а вовсе не как или почему. У вас
очень мало возможностей для исправления ошибок".
(джеймсдлин). Но в интересах достижения баланса, я начну с этой дискуссии.
Для пользовательского ввода, который поступает от stdin
, т. е. ввод с клавиатуры, fgets()
будет лучшим выбором. Это гораздо более простительно, так как считываемая строка может быть полностью проверена перед попыткой преобразования
Один из немногих случаев, когда можно использовать форму scanf(): fscanf (), может быть использован при преобразовании входных данных из очень контролируемого источника, т. Е. При чтении строго отформатированного файла с повторяющимися предсказуемыми полями.
Для дальнейшего обсуждения это сравнение двух из них подчеркивает дополнительные преимущества и недостатки обоих.
Изменить: для решения дополнительного вопроса о переполнении:
"Еще одна вещь, которую я хочу спросить: даже когда мы используем fgets, что произойдет, если пользователь введет символов больше границы (я имею в виду много
символов), приведет ли это к переполнению буфера? Тогда как с
этим бороться?"
[fgets()](https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm хорошо разработан для предотвращения переполнения буфера, просто правильно используя его параметры, например:
char buffer[100] = {0};
...
while fgets(buffer, sizeof buffer, stdin);
Это предотвращает обработку ввода, превышающего размер буфера, что предотвращает переполнение.
даже используя scanf()
предотвращение переполнения буфера довольно прямолинейно: используйте описатель ширины в строке формата. Например, если вы хотите прочитать вводимые данные и ограничить размер ввода пользователем не более чем 100 символами, код будет включать следующее:
char buffer[101] = {0};// includes space for 100 + 1 for NULL termination
scanf("%100s", buffer);
^^^ width specifier
Однако с числами переполнение не так приятно использовать scanf()
. Чтобы продемонстрировать, используйте этот простой код, вводя два значения, указанные в комментарии по одному за запуск:
int main(void)
{
int val = 0;
// test with 2147483647 & 2147483648
scanf("%d", &val);
printf("%d\n", val);
return 0;
}
Для второго значения моя система выдает следующее:
NON-FATAL RUN-TIME ERROR: "test.c", line 11, col 5, thread id 22832: Function scanf: (errno == 34 [0x22]). Range error
`
Здесь вам нужно прочитать строку, а затем выполнить преобразование строки в число с помощью одного из strto_()
функции: strtol(), strtod(), ...). Оба включают возможность проверки на переполнение перед тем, как вызвать предупреждение или ошибку во время выполнения. Обратите внимание, что с помощью atoi()
, atod()
также не защитит от переполнения.