Функция scanf() располагает двумя возможностями для прекращения ввода. При любом варианте строка начинается с первого встреченного непробелыюго символа. Если задан формат %s, строка продолжается до следующего (не включая его) пробель ного символа (символа пробела, табуляции или новой строки). Если указана ширина поля, как в %10s, функция scanf() читает до получения 10 символов или до появления первого пробельного символа, в зависимости от того, что произойдет раньше (рис. 11.3).
Символьные строки и строковые функции 439

Рис. 11.3. Ширина поля и функция scanf()
Вспомните, что функция scanf() возвращает целочисленное значение, равное количеству успешно прочитанных элементов, или EOF при обнаружении конца файла.
В листинге 11.11 иллюстрируется работа функции scanf(), когда задана ширина поля.
Листинг 11.11. Программа scan_str .о

Вот результаты грех пробных запусков программы:
Введите два имени.
Джейн Покер
Прочитано 2 имени: Джейн и Покер.
Введите два имени.
Иван Миттельшпиль
Прочитано 2 имени: Иван и Миттельшпи.
Введите два имени.
Вениамин Каверин
Прочитано 2 имени: Вениа и мин.
В первом запуске оба имени вписываются в разрешенные предельные размеры. Во втором запуске были прочитаны только первые 10 символов имени Миттельшпиль, поскольку мы применяем формат %10s. В третьем запуске в name2 попадают последние три буквы из имени Вениамин, т.к. второй ввод возобновляется там, где закончился первый ввод: в данном случае — внутри слова Вениамин.
В зависимости от природы желаемого ввода, для чтения текста с клавиатуры может быть удобнее пользоваться функцией fgets(). Например, функция scanf() не особенно подходит для ввода названия книги или песни, если только название не состоит из одного слова. Типичным применением scanf() является чтение и преобразование смеси данных разных типов в некоторой стандартной форме. Например, если входная строка содержит название инструмента, складской номер и цену за штуку, то можно воспользоваться scanf() либо написать собственную функцию, которая будет
1
440 Глава 11 выполнять проверку на предмет ошибок ввода. Если вы хотите обрабатывать ввод по слову за раз, можете применять scanf().
Функция scanf() страдает тем же потенциальным недостатком, что и gets(): она может приводить к переполнению, если вводимое слово не умещается в целевую область памяти. Но для предотвращения такого переполнения можно использовать параметр ширины поля в спецификаторе %s.
Вывод строк
Теперь давайте перейдем от ввода строк к их выводу. Мы снова будем применять библиотечные функции. Для вывода строк в С доступны три стандартных библиотечных функции: puts(), fputs() и printf().
Функция puts()
Функция puts() очень проста в использовании. Ей нужно только передать в качестве аргумента адрес строки. В листинге 11.12 демонстрируется несколько способов из множества доступных.
Листинг 11.12. Программа put out.с

Вывод имеет следующий вид:
Как и в предшествующих примерах, каждая строка выводится в собственной строке, потому что при отображении строки функция puts() автоматически добавляет символ новой строки.
Этот пример напоминает, что фразы, заключенные в двойные кавычки, представляют собой строковые константы и трактуются как адреса. Кроме того, имена строковых массивов также считаются адресами. Выражение &strl [5] — это адрес шестого элемента в массиве strl. Этот элемент содержит символ ' в ', и именно он puts() применяет в качестве начальной точки. Аналогично, str2 + 4 указывает на ячейку памяти, содержащую второй символ 'а' из строки "Указатель", поэтому вывод начинается с него.
Символьные строки и строковые функции 441
Как функция puts() узнает, когда остановиться? Она прекращает вывод, когда встречает нулевой символ, так что лучше, чтобы он был в строке. Не повторяйте ошибку, проиллюстрированную в листинге 11.13!
Листинг 11.13. Программа nono.с

Поскольку в массиве dont отсутствует завершающий нулевой символ, он не является строкой, поэтому функция puts() не знает, где остановиться. Она будет выводить содержимое ячеек памяти, следующих за dont, пока не обнаружит нулевой символ где- то в другом месте. Чтобы гарантировать, что нулевой символ не окажется слишком далеко, массив dont в программе хранится между двумя настоящими строками. Вот как выглядит вывод:
Читать дальше