Бьерн Страуструп. Язык программирования С++. Специальное издание (2011) (1004033), страница 20
Текст из файла (страница 20)
Отметим, что символьные константы выводятся в поток именно как символы, а не как соответствующие им числовые значения. Например, код гоЫ/г() ( сои!« ' а '; сои!« ' Ь ': сои!« ' с ': ) поместит в выходной поток последовательность айс. Утомительно то и дело повторять имя стандартного потока вывода при последовательном выводе нескольких величин. К счастью, результат операции «можно использовать для последующей операции вывода. Например: гоЫ й1 (1и! 1) ( сои!«мйе еа!ие о11ы "«1« ' хи '; ) По своему действию эта функция эквивалентна представленной ранее функции й () . Подробнее потоки рассматриваются в главе 21.
3.5. Строки В стандартной библиотеке определен тип егг1ия, дополняющий рассмотренные ранее строковые литералы. Тип з(г1ия обеспечивает множество полезных операций, таких как конкатенация (сопсагеиайои). Например: 89 3.5. Строки Мппд и1 = »Нег!о»! и!пя 2= - «И»; гоЫт1() и!г!па иЗ = з1»", в»з2»"! ) п' ! сои!«зЗ; Здесь строка иЗ инициализируется значением (текстом) Не!1о, ног!И! со специальным знаком «перевод строки» на конце. Сложение строк означает их конкатенацию.
Строки можно складывать со строками, строковыми литералами и символами. Во многих приложениях конкатенация реализуется в форме добавления чего-либо к концу заданной строки, что напрямую поддерживается операцией»вч Например: гойи! т2 (згг1пяи з1, ит!пяи з2) ( и1 = з1» ' ~п'; УУ добавить к концу содержимого символ перевода строки з2»= ' '~п' ! УУ добавить к концу содержимого символ перевода строки ) Показанные способы добавления к концу строки семантически эквивалентны, но я предпочитаю второй из них, так как он короче и, к тому же, реализуется эффективнее в машинном коде, Естественно, что строки можно сравнивать между собой и со строковыми литералами.
Например: з!г!пя !псин!анап ! го1И геиропг( (сонм з!ппаз аизтег) ( (!'(апз»гег==!псап!аи!оп ) ( УУ сотворим чудо 0)псап(абоп - колдовство, заклинание) ) е1зе иУ(апзтег== "уеи" ) ( уу ... ) уу ... Класс зИпя из стандартной библиотеки описывается в главе 20. Помимо прочих полезных вещей он предоставляет возможность работы с подстроками. Например: Ии!Пя ПатЕ= "ГИ!Е(и Б!Гааз!Гирь ! го1И тЗ () зиг(паз = пате.ииатг(6,10) ! УУи ="$ииииггир" Глава 3. Обзор стандартной библиотеки 90 пате. гер!асв (О, 5, "зх(!ейо!аз«); У нате становится "№сйо!ая 5ооизггир" Операция' яиояггО возвращает копию подстроки, задаваемой аргументами. Первый аргумент означает индекс (позицию) начала подстроки, а второй — ее длину.
Так как начальным значением индекса является нуль, то строка я принимает значение Бггоияггир. Операция гер1асе() замещает исходное значение подстроки на новое. В данном случае, подстрока начинается с индекса 0 и имеет длину 5, так что это Мзей; она замещается на Майо!ая; таким образом, окончательное значение строки пате есть Мсйо1ая 5(гоияггир. Дополнительно отметим, что длина замещаемой подстроки и нового значения не обязаны совпадать. 3.5.1. С-строки Как известно, С-строки (или строки языка С) — зто массивы символов с терминальным нулем (й5.2.2).
С-строки легко преобразуются в значения типа я(г1пи. Но может потребоваться и обратное преобразование, например, когда имеется значение типа ягг1пи, а нужно вызвать функцию, принимающую аргумент типа С-строки. Его-то и нужно тогда извлечь из значения типа зи(пи с помощью функции с зи () (520.3.7). Например, мы можем вывести значение строки пате библиотечной функцией рг1пЯ) языка С (я2!.3): гоЫ5'() ( рг!пи'( "вате: %з',и",пате.е згг() ); ) 3.6.
Ввод гоЫ !'() ( и«Г г; сгп» зг йоиЫе дз зу считать цехов значение в ! Здесь, и во многих местах далее, автор использует слово «операция» как синоним слова «действие» в самом широком смысле. В строгом же смысле, здесь имеет место функцио- нальный вызов. — Прим. ред. В стандартной библиотеке тип Виват управляет посимвольным вводом встроенных типов данных точно так же, как рассмотренный выше тип ояггеат управляет их выводом. Действие типа 1я(геапз несложно распространить и на пользовательские типы. Для обозначения операции ввода используется знак» («извлечь из потока»), а ет обозначает стандартный поток ввода. Тип правого операнда операции» определяет, что именно вводится и куда записывается результат ввода.
Например, следующий код 3.6, Ввод 91 с(и»А ) УУ считать значение с плавающей запятой двойной точности в 4 читает число, вроде 1234, из потока ввода в целую переменную я и значение с плавающей запятой, вроде 12.34е5, в переменную 4типа Иоай!е (числа с плавающей запятой двойной точности). Ниже дан пример программы, осуществляющей преобразования из дюймов в сантиметры и обратно. Вы вводите число и символ, обозначающий единицу измерения: сантиметры (символ ' с') или дюймы (символ ' я'). Программа выведет соответствующее значение в других единицах измерения: тя та1и ( ) ( сопя(1(оа11асяог = 2. 54; 1!оазх, т, ст; сйаг ей = О; УУ ! дюйм равен 2.54 ст сои!«ьеляег !впаяй: "; с(и»х; сгл»сй; У считать число с плавающей запяпюй ,У считать суффикс линзой (сй) ( саяе '!': !и=х; от =х "1асяог ( Ьгеай; саяе 'с' т=х11асяог; ст=х; Ьгеай; йе1аий: !и=от=д( Ьгеай; ) УУ дюймы УУ сантиметры сои!«!п«ч 1п= ч«сзи«ь от~и"! ) 1пя та!и () ( за1пе яяг; сотс< "Р!еаяе, еп1ег уоиг лате~ив; с!п» яяг; Оператор ял11сй сравнивает значение с набором констант: Оператор Ьгеай осуществляет выход из оператора я(я11сй.
Константы в разных саке-ветвях должны быть разными. Если проверяемое значение не совпадает ни с одной из них, то выбирается 4е1ал!г-ветвьь Программист, в общем случае, не обязан реализовывать я!е1ал!г-ветвь. Часто требуется прочитать последовательность символов. В этом случае удобно помещать результат ввода в объект типа яяг!ля. Вот соответствующий пример: Глава 3. Обзор стандартной библиотеки сон!« "Нейо, "«вп«"! тп"; Если вы введете Епс то вывод будет таким: Недо, Епс! По умолчанию, символ-разделитель (В5.2.2), например, пробел, прерывает ввод, так что если вы введете Емс В)ооаахе притворяясь несчастным королем Йорка, то все равно на выходе получите то же са- мое: Нейо, Емс! Считать целиком всю строку можно с помошью функции яег!(пе(), например: (пг гпа(п ( ) ( згнпл вгг; сон!« "Ргеаге, епгег уоиг пате~а"; аег((пе(с(п, во) т сон!« "НеИо, "«вгг«"! тп" ! ) Теперь при вводе Ег(с Вгооаахе на выходе мы получим желаемое: Нело, Епс В)ооаахе) Тип з(ппя имеет чудесное свойство принимать на хранение тексты любого размера, так что если вы вдруг введете пару мегабайт двоеточий, то программа выведет вам в ответ всю эту кучу знаков — если только компьютер или операционная система не исчерпают при этом какой-либо критический ресурс.
3.7. Контейнеры Часто в процессе решения самых разных задач удобно создать коллекцию (набор) объектов некоторого типа, чтобы потом такой коллекцией манипулировать. Простейшим примером является процесс чтения символов в строку и последующий вывод строки на дисплей (или принтер). Класс, основной целью которого является хранение обьекп)ов, называется ноно)ейнером.
Выбор подходящих контейнеров и реализация фундаментальных методов работы с ними, достаточных и удобных для решения конкретной задачи, являются важным этапом разработки программ. Для иллюстрации наиболее важных контейнеров стандартной библиотеки рассмотрим простую программу, храняшую имена и номера телефонов.
Это задача, 3 7. Контейнеры различные подходы к решению которой хорошо понятны специалистам разных профилей. 3.7.1. Контейнер )гестог Для большинства программистов на С встроенный массив пар значений [имя, телефонный номер) является естественной точкой отсчета: д запись телефонной книги зггисг Епиу ( ззг(пя пате! [п( питЬет ): Епггу рйопе Ьоой [1000] ! !!телефонная книга на !ООО записей 77 испол~лозанне !вывод записи) гоЫ рпнс епиу (1пг 1) ( соие«рйопе Ьоой [1] . нате« ' ' « рйопе Ьоой [1] . питЬег« ' Хп '; гесгог<Епиу> рйопе Ьоой (1000) гоЫ рггпг егпгу (1п! 1) ( сои!«рйопе Ьоой [1] .пате «' '«рйопе Ьоой[1] .питьег«'',и' ! ) гоЫ ачЫ епзг(ез (1пз и) д увеличиваем размер книги на и записей ( рйоне Ьоой. гез1ге(рйопе Ьоой.з(ге () ьп); ) 77 используем как раньше Функция з1хе(), член класса гесгог, возвращает количество размещенных элементов.
Обратите внимание на круглые скобки в определении объекта рйопе Ьоой. Мы создали единственный объект типа гесгог<Епггу> и проинициализировали его начальным размером. Это разительно отличается от объявления встроенного массива: гесгог<Епггу> Ьоой (1000) г,У гес(ог из ! ООО элементов гесгог<Епзгу> Ьоойз [1000] ! ~7 !ООО пустых векторов Если в объявлении объекта вы по ошибке используете квадратные скобки вместо круглых, то компилятор наверняка обнаружит ошибку в тот момент, когда вы попытаетесь использовать объект. Объекты типа гесгог могут участвовать в операциях присваивания: гоЫ1 (гесгог<Епиу> з г) ( гетог<Епггу> г2 = рйопе Ьоой! Однако встроенные массивы имеют жестко фиксированные размеры. Если мы выберем избыточный размер, то впустую израсходуем память; если же размер будет недостаточным, то произойдет переполнение.
В любом случае, придется писать низкоуровневый код по управлению выделением памяти. Контейнер гесгог из стандартной библиотеки [516.3) берет на себя эту заботу: Глава 3. Обзор стандартной библиотеки 94 При этом копируются все элементы векторов. Таким образом, после инициализации и операции присваивания в функции Т() векторы и и я2 содержат независимые копии объектов типа Еп(гу из телефонной книги.
Когда вектора содержат много элементов, невинно выглядящие инициализация и присваивание могут оказаться недопустимо дорогостоящими операциями. В таких случаях лучше использовать ссылки или указатели. 3.7.2. Проверка диапазона индексов Стандартный тип вес(ог по умолчанию никаких проверок индексов не производит (З!6.3.3). Например: чоЫ ('() ( т( (=рйопе Ьоой [10011 . нитЬег( ) // !00! вне диапазона индексов Вероятнее всего, такое присваивание поместит в переменную ! некоторое неконтролируемое значение, а не породит сообщение об ошибке.