Второе отличие означает, что до тех пор, пока строка ввода не слишком длинная, функция gets_s() ведет себя подобно gets(), благодаря чему gets() проще заменить функцией gets s(), чем fgets(). Третье отличие означает необходимость в обучении применению этой функции.
Давайте сравним приемлемость функций gets(), fgets() и gets_s(). Если строка ввода умещается в целевую область памяти, то все три функции работают успешно. Но функция fgets() включает в строку символ новой строки, поэтому может возникнуть необходимость в коде для его замены нулевым символом.
А что происходит, если длина строки ввода превышает заданный размер? Тогда использование функции gets() будет небезопасным — могут быть повреждены данные и нарушена безопасность. Функция gets_s() безопасна, но если вы не хотите, чтобы программа прекратила работу или выполнила выход каким-нибудь способом, придется подумать над тем, как написать и зарегистрировать специальные “обработчики”. Кроме того, если все же удается сохранить программу в работоспособном состоянии, функция gets_s() отбросит остальную часть строки ввода независимо от вашего желания. В случае, когда строка не умещается в заданную область памяти, с функцией fgets() иметь дело проще, чем с двумя другими функциями, и она предоставляет больше возможных вариантов. Если нужно, чтобы программа обработала остальную часть строки ввода, это можно сделать, как показано в листинге 11.8. Если же требуется, чтобы программа обработала остальную часть строки ввода, это также возможно, как видно в листинге 11.9.
Таким образом, когда ввод не соответствует ожиданиям, функция gets s() является менее удобной и гибкой по сравнению с fgets(). Вероятно, это одна из причин, по которой функция gets s() представляет собой лишь необязательное расширение библиотеки С. И с учетом необязательности gets_s() обычно лучшим выбором будет функция fgets().
Функция s _ gets ()
В листинге 11.9 представлен один из способов применения функции fgets(): чтение всей строки и замена символа новой строки нулевым символом либо чтение части строки, умещающейся в заданную область памяти, и отбрасывание остальных символов — т.е. своего рода разновидность функции gets s(), но без дополнительных препятствий. Ни одна из стандартных функций не удовлетворяет этому описанию, но мы можем создать такую функцию самостоятельно. Она пригодится в будущих примерах. В листинге 11.10 демонстрируется один из подходов.
Листинг 11.10. Функция s_gets()

438 глава 11

В то время как функция fgets() возвращает NULL, указывая на конец файла или ошибку чтения, функция s_gets() пропускает обработку остальных данных. В противном случае она имитирует работу программы из листинга 11.9, заменяя в строке символ новой строки нулевым символом, если названный символ присутствует, и отбрасывая остальную часть строки в противоположной ситуации. Затем она возвращает то же самое значение, что и fgets(). Мы будем использовать эту функцию в последующих примерах.
Возможно, вас интересует, в чем смысл отбрасывания остальной части слишком длинной строки. Проблема в том, что если остальную часть строки оставить, она становится входными данными для следующего оператора чтения. Это может, например, вызвать аварийное завершение программы, если следующий оператор чтения ожидает значение типа double. Отбрасывание остальной части строки поддерживает операторы чтения в состоянии синхронизации с вводом с клавиатуры.
Наша функция s_gets() не идеальна. Наиболее серьезный ее недостаток в том, что она молча отбрасывает лишние входных данных, не ставя об этом в известность ни программу, ни пользователя, и тем самым лишая его других возможностей, таких как повторение ввода или нахождение большего объема памяти. Еще один недостаток — отсутствие мер на случай неправильного применения вроде передачи размера, равного 1 или меньше. Тем не менее, эта функция вполне может служить заменой функции gets() в наших примерах.
Функция scanf()
Давайте снова возвратимся к функции scanf(). Ранее для чтения строки мы использовали функцию scanf() с форматом %s. Основное отличие между функциями scanf() и fgets() связано с тем, как они определяют момент достижения конца строки: функция scanf() больше ориентирована на “получение слова”, а не на “получение строки”. Функция gets(), как вы уже видели, принимает все символы вплоть до первого символа новой строки, как это делает fgets(), если строка является достаточно короткой.
Читать дальше