Глава 1. Первые шаги
Создание консольного приложения
Структура программы
Комментарии в программе
Вывод данных в языке С++
Вывод данных в языке С
Ввод данных в языке С++
Ввод данных в языке С
Интерактивный ввод символов
Получение данных из командной строки
Предотвращение закрытия окна консоли
На стройка отображения русских букв в консоли
Преждевременное завершение выполнения программы
Глава 2. Переменные и типы данных
Типы данных
Инициализация переменных
Оператор typеdef
Динамическое определение типа данных
Константы
Спецификаторы хранения
Области видимости переменных
Пространства имен
Массивы
Строки
Указатели
Ссылки
Динамическое выделение памяти
Структуры
Битовые поля
Объединения
Перечисления
Приведение типов
Глава 3. Операторы и циклы
Побитовые операторы
Операторы присваивания
Оператор запятая
Операторы сравнения
Приоритет выполнения операторов
Оператор ветвления if
Оператор ?:
Оператор выбора switch
Цикл for
Цикл while
Цикл do...while
Оператор continue
Оператор break
Оператор goto
Глава 4. Числа
Основные функции для работы с числами
Округление чисел
Тригонометрические функции
Преобразование строки в число
Преобразование числа в строку
Генерация псевдослучайных чисел
Глава 5. Массивы
Получение н изменение значения элемента массива
Перебор элементов массива
Доступ к элементам массива с помощью указателя
Массивы указателей
Динамические массивы
Многомерные массивы
Поиск минимального н максимального значения
Сортировка массива
Проверка наличия значения в массиве
Копирование элементов из одного массива в другой
Сравнение массивов
Глава 6. Символы и строки
Настройка локали в языке С
Настройка локали в языке С++
Изменение регистра символа
Проверка типа содержимого символа
С-строки
Доступ к символам внутри С-строки
Перебор символов С-строки
Основные функции для работы с С-строками
Поиск и замена в С-строке
Сравнение С-строк
Класс string
Вводи вывод строк
Преобразование объекта в С-строку или в массив символов
Получение и изменение размеров строки
Получение и изменение содержимого строки
Поиск в строке
Сравнение строк
Итераторы
Расширенные символы н строки
Функции для работы с расширенными символами
Преобразование расширенных символов в обычные и наоборот
Функции для работы с расширенными строками
Класс wstring
Глава 7. Работа с датой и временем
Форматирование даты и времени
\
Измерение времени выполнения фрагментов кода
Глава 8. Пользовательские функции
Расположение объявлений н определений функций
Способы передачи параметров в функцию
Передача массивов в функцию
Необязательные параметры
Переменное количество параметров
Перегрузка функции
Встраиваемые функции
Константные параметры
Статические переменные
Способы возврата значения нз функции
Указатели на функции
Рекурсия
Глава 9. ООП
Объявление класса
Объявление атрибутов
Объявление и определение методов
Конструкторы и деструктор
Конструктор копирования
Статические атрибуты и методы
Созданпе констант внутри класса
Константные методы
Дружественные функции н классы
Массивы объектов
Динамическое создание объектов
Указатели на объекты и члены класса
Передача объектов в функцию н возврат объектов
Наследование
Множественное наследование
Указатели на объекты производных классов
Виртуальные методы
Динамическое определение типа объекта
Оператор dynamic_сast
Абстрактные методы и классы
Глава 10. Перегрузка операторов
Перегрузка бинарных операторов
Перегрузка унарных операторов
Перегрузка операторов инкремента и декремента
Перегрузка операторов присваивания
Перегрузка оператора []
Перегрузка оператора доступа к члену класса
Перегрузка операторов new и delete
Перегрузка операторов << и >>
Преобразование объекта в другой тип данных
Глава 11. Обработка ошибок
Операторы try...catch и throw
Класс exception
Пользовательские классы исключений
Ограничение типа исключений, генерируемых внутри функции
Назначение обработчиков верхнего уровня
Отключение вывода предупреждающих сооощений
Способы поиска ошибок в программе
Отладка программы в Microsoft Visual С++ 2010 Express
Глава 12. Ввод и вывод данных
Запись в файл и чтение из файла
Файлы произвольного доступа
Создание временных файлов
Перенаправление ввода/вывода
Ввод/вывод расширенных символов и строк
Ввод/вывод данных в языке С++
Открытие и закрытие файла
Запись в файл и чтение из файла
Файлы произвольного доступа
Проверка состояния потока
Классы basic_istringstгеаm, basic_ostringstream и basic_stringstream
Считывание данных из буфера
Настройка локали для потока
Форматированный ввод/вывод в языке С++
Установка и сброс флагов формата
Манипуляторы формата
Создание пользовательских манипуляторов
Работа с файловой системой
Переименование и удаление файла
Проверки прав доступа к файлу и каталогу
Изменение прав доступа к файлу
Получение информации о файле
Функции для работы с дисками и каталогами
Перебор объектов, расположенных в каталоге
Глава 13. STL
Итераторы
Функторы
Инверторы
Редакторы связей
Адаптеры
Обзор контейнеров
Класс deque. Двусторонняя очередь
Вставка элементов
Удаление элементов
Доступ к элементам
Класс list. Список
Вставка элементов
Удаление элементов
Доступ к элементам
Сортировка, объединение и переворачивание списков
Класс vector. Динамический массив
Вставка элементов
Удаление элементов
Доступ к элементам
Получение и изменение размера вектора
Специализация veсtor<bоol>
Класс map. Ассоциативный массив с уникальными ключами
Создание объекта
Вставка элементов
Удаление элементов
Доступ к элементам
Класс multimap. Ассоциативный массив с повторяющимися ключами
Создание объекта
Вставка элементов
Удаление элементов
Доступ к элементам
Класс priority_queue. Очередь с приоритетами
Класс queue. Очередь
Класс stack. Стек
Текст
                    @Прохоре,ю/С НА, 2010 '.
 2 
1612.10
Созданпе "YCToro "роекта
В процессе изуч ения основ языка С++ мы будем создавать консольные приложения.
Консольное прuло:женuе  это проrpамма, отображающая текстовую информацию и
позволяющая вводить символы с клавиатуры. Консольное приложение позволит не
отвлекать ся на изучение среды разработки, а полностью сосредоточить СБое внимание
на изучении синтаксиса языка.
Создать консольное приложение можно дву:мя способами. Первый способ заключается
в создании пустоrо проекта и написании кода с нуля. Именно этим способом мы буде м
пользоваться на протяж ении всей книrи. Второй способ позволяет создать консольное
приложение с помощью мастера. В этом случае мастер создаст все необходимое файлы
и заполнит их шаблонами кода.
Чтобы создать пустой проект в меlПO ФаЙл выбираем пункт С'оздатъ I П!,окт. В
открывшемся окне выделяем пункт КоИfОJn.ИОI?' Щ)ПЛОЖI?'IПI{I \\';i1l32. Вводим название
проекта (например, "helloworld") в поле ПI'Ш. Введенное название автоматически
копируется в поле lfu.ш !,шшш. В поле Расположш,.. указываем путь к каталоrу, в
котором 6уд ет сохран ен проект, и устанавливаем фл ажок Создать кат:;)лоr для
!,шшш. Нажимаем кнопку ОК. В результате откроется окно J\IacT!, ЩШЛОЖШПI
\\';iIl32. Нажимаем кнопку Дал. В rpуппе переключателей т,Ш I1J"IЛО",""'IПШ
выбираем KOHCOJThHO I1JШЛОЖ"'IП. Снимаем флажок П!,два!,ПТJThНО
fKOI'o-ППIJПЧ)ОВ:;)lПIыii заrолово:к и устанавливаем флажок Пу(тоii Щ)ОI?'КТ. Нажимаем
кнопку rOTOBO. В результате проект будет создан и открыт в rлавном окне.
Создать пустой проект можно rораздо быстрее. Для этоrо в окне С'озда тъ I1J'ОКТ
вместо пункта Ь:ОИfОJП.ИОI?' П})IIЛОЖI?'IПII?' \\'Ъ.l32 следует выделить пункт Пу(тоii
I1J'ОКТ. В этом случае проект будет создан сразу после нажатия кнопки ОК.
После создания пустоrо проекта необходимо добавить основной файл. Для этоrо в окне
ОБОЗ})l?'ватl?'Jn. })I?'Шl?'шоп"i щелкаем правой кнопкой мыши на пункте Фаiiлы ПfХО,ll;Ноrо
:кода и из KOHTeKCTHoro меню выбираем пункт Добавить I Создать ')Ш"МI?'IП. В
результате откроется окно ДОQаВЛI?НПI?' HOBoro ')ЛII?'IП:;). Выделяем пункт Фаiiл С++
(.е!'!'), вводим название файла (например, "тшn ") и нажимаем кнопку До6авптъ. В
результате файл будет добавлен в папку проекта и ero название отобр азится в окне
ОБОЗ})l?'ватl?'Jn. })I?'Шl?'шоп"i, а сам файл 6уд ет открыт на отдельной вкладке.
При изуч ении языков проrpаммирования принято начинать
надпись "Неll0, world 1" в окно консоли. Не буд ем
продемонстрируем, как это выrлядит на С++ (листинr 1.1).
с проrpаммы, выводящей
нарушать традицию и
Листинrи на странице http://unicros s.narod.ru/cpp/


@Прохоре,ю/С НА, 2010 '.  3  1612.10 I .1IИСТIПП 1.1. Пер вnя пр orp n",m # include <iostream > int main (1 std: : cout « rrHello, world! rr « std:: endl; return о; { в первой строке проrpаммы с помощью директивы inc1 ude подключается файл io st re am, В котором объявлен объект со ut, предназначенный для вывода данных в окно консоли. Далее создается функция main ( 1, внутри которой расположены все остальные инструкции, оrpаниченные фиrурными скобками. Именно функция с названием main (1 будет автоматически вызываться при запуске проrp аммы. Перед названием функции указыв ается тип Бо:звращае Moro значения. Ключевое слово in t означает, что функция возвращает целое число. В о:звращаемое значение указывается после ключевоrо слова r et ur n В самом конце функции main ( ) . Число о в данном случае означает нормальное завершение проrpаммы. Если указано друтое число, ТО это свидетельствует о некорректном завершении проrpаммы. Соrласно стандарту, внутри функции main () ключевое слово r etur n МОЖНО не указывать. В этом случае ко мпилятор должен само стоятельно вставить инструкцию, Бо:звращающJ'lO значение о. Вывод строки "Неll0, world 1" осуществляется с помощью объекта сои t. Чтобы исключить конфликт имен все стандартные идентификаторы в языке С++ определены в пространстве имен std. Поэтому перед именем объ екта со ut необходимо указ ать название пространства имен. Между нззванием пространства имен и названием объекта указываются два двоеточия (std: :cout). И, наконец, константа end1 (сокращение от 11 end line 11) вставляет символ перевода строки. Теперь попробуе м скомпилировать и запустить проrpамму. Для этоrо до бавляем содержимое листинrа в созданный файл, а затем из меню ПО("ТРОI?'IПН. выбираем пункт ПОСТl'оптъ l'шmI или нажимаем клавишу <F7> В результате в окне Вывод ото бр аз ится сл едую щая и н Ф ор мац ия: 1> Построение начато: проект: helloworld, Конфиrурация: Debug Win32  1> main.cpp 1> hellowor1d.vcxproj > C:\book\he11owor1d\Debug\he11owor1d.exe ========== Построение: успешно: 1, с ошибками: О, без изменений: О, пропущено: О ========== Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  4  1612.10 Данный результат свидетельствует об успешном создании файла helloworld. ехе в кон фиrурации Debug Сотладка) в палке С:\Ьо ok\helloworld\D ebug\. Если при наборе были допущен ы ошибки, то их описание будет отображено в окне Вывод. В кач естве примера уберем точку с запятой после константы end1 и попробуе м произвести компиляцию. Результат будет выrлядеть так 1> Построение начато: проект: helloworld, Конфиrурация: Debug Win32  1> main.cpp 1>c:\book\he11owor1d\he11owor1d\main.cpp(51: error С2143: с интакс иче екая ошиб ка : о тсутс твие rr; rr пе ред rr re t ur n rr ========== Построение: успешно: О, с ошибками: 1, без изменений: О, пропущено: О ========== Фраза "успешно: О, с ошибками: 111 rОБОрИТ о наличии ошибки в проrpамме. Описание самой ошибки приводится строкой ранее. Указывается название файла, номер ошибки С"С2143"), а также подробное описание ошибки, в данном случае на русском языке. После исправления ошибки необходимо заново скомпилировать проект. Чтобы посмотреть результат выполнения проrраммы из меню Отладка выбираем пункт ЗаП)'ск 6", отладки или нажимаем комбинацию клавиш <Ctrl>+<FS> В результате откро ется ОКНО консоли с приветствием, а также со строкой 11 Для продолжения нажмите любую клавишуll. Нажатие любой клавиши приведет к закрытию окна консоли. Запустить проrpамму можно также в режиме отладки. Для этоrо из меню Отладка выбираем пункт Начать отла;!J;КУ или нажимаем клавишу <FS>. В этом случае окно консоли откроется, затем сразу закроется, а в окне ВЫВОД отобразится отладочная информация. Как сделать, чтобы окно консоли сразу не закрывалось, мы рассмотрим далее в этой rлаве. Следует заметить, что при нажатии клавиши <FS> ипи комбинации клавиш <Ctrl>+<FS> производится проверка актуальности скомпилированноrо файла. Если файл устарел СВ проrpамме сделаны изменения), то будет выведено окно, в котором предлarается произвести повторную компиляцию. Чтобы выполнить повторную компиляцию нажимаем кнопку Да. Таким образом, можно не производить предварительную компиляцию, а сразу запускать проrpамму. Прu.мечанuе Если в менк От m дка н ет пункта '3а П)"СК 6з отладки, т о пр едварителъно в менк СI'ВИС нео б хо димо вы брать пункт пl'aMTI'Ы I Расппq)IOIЫ<' паl'амтl' ы. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  5  1612.10 Созданпе консольноrо "рпложенпя Чтобы создать консольное приложение с ПОМОЩЬЮ мастера в меню Фаiiл выбираем пункт С'оздатъ I Пl'окт. В открывшемся окне выделяем пункт KOHCOJThHO IIJНIЛОЖШI \\';i1l32. Вводим название проекта (например, "welcome ") в поле ПJ\o1Я. Введенное название автоматически копируется в поле IfI...1Я })I?'ШI?'IПIЯ. В поле Ра СПОЛОЖНП указывае м путь к кат ал ory , в котором буд ет сохранен проект, и устанавливаем флажок Создать кат:;)лоr для })I?'ШI?'IПIЯ. Нажимаем кнопку ОК. В результате откроется окно J\Ьст1' IIJ)lIЛожmПI \\';i1l32. Нажимаем кнопку Дал. В rpуппе переключателей т,ш IIJ"IЛО","""Ш1Я выбираем KOHCOJThHO IIJНIЛОЖШI. Устанавливаем фл ажок Прl?';!J;Ва})птI?'Jn.НО fKOI'o-ППIJПIрОВ:;)lПIыii заrолово:к. Флажок ПустоЙ щ,окт должен быть снят. Нажимаем кнопку rOTOBO. в результате будут созданы следующи е файлы: -+ welcome. срр  основной файл проекта; -+ stdafu.h  файл для подключения зarоловочных файлов, используе мых в проекте. Этот файл необходимо подключать во всех файлах проекта; -+ stdafu . срр  файл ы stdafu . h и stdafx . срр и с пользую тся для по стр о е ния файл а предкомпилированноrо заrоловка (welcome.pch) и файла предкомпилированных типов (stdafu. obj); -+ targetver.h  в этом файле подюочается файл SDKDDKVer.h, обеспечивает определение последней доступной ппатформы Windows. Файлы stdafu. срр и targetver.h оставляем без изменений. В конец вставляем строку, ПОЗВОЛЯ::ЮЩYIO использовать в проrpамме предназначенный для вывода данных в окно консоли: который файл а stdafu . h объект cout, # include <iostream > С одержимое файл а stdafu.h приведено в листинrе 1.2. I ЛНСТIПП 1.2. ('одер ЖИI>Ю фай:rm s o:la fX.ll #pragma оnсе #include rrtargetver. h rr #include <stdio.h> #include <tchar.h> # include <iostream > Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  6  1612.10 Директива р ragma СО значением о nс е указывает, что сод ержимое файла может быть включено только один раз. Директивы incl ude ПОДКЛЮЧaIOТ файлы, в которых содержатся объявления идентификаторов. Такие файлы называются за80ловО"iЬ!МU файлами. Они содерж ат только объявление идентификаторов без описания их реализации. Обратите внимание на то, что в директиве inc lude зarоловочные файлы подключаются разными способами. Поиск файлов, указанных внутри yrловых скобок, ПРОИЗВОДИТСЯ в системных каталоrах, а поиск файлов, указанных внутри кавычек, производится в каталоrе проекта. Таки м образом, названия файлов стандартной библиотеки необходимо указыв ать внутри уrловых скобок, а пользовательских файл ов внутри кавычек Внимательный читатель наверняка обратил внимание на то, что три первых зarоловочных файла содержат расширение h, а в последней директиве расширение файла не указано. Наличие расширения файл а принято в стандартной библиотеке языка С. В стандартной библиотеке языка С++ расширение файла принято не указывать. Так как язык С++ наследует все библиотеки языка С, то файлы можно подключать как в стиле языка С, так и в стиле языка С++. Например, файл string.h из стандартной библиотеки языка С доступен в языке С++ под названием cstring, а файл math.h под названием cmath. Отличие между ЭТ1lМИ способами подключения заключается в импортировании идентификаторов. В языке С при подключении файла (налример, math .h) все идентификаторы импортируются в rлобальное пространство имен, а в языке С++ при подключении файла (например, cmath) идентификаторы определяются в пространстве имен под названием std. Поэтому перед идентификатором необходи мо указ ать название пространства имен (например, std:: со u t). Использование простраНС1Б имен позволяет избежать конфликта имен в проrpамме. Чтобы посмотреть содержимое зarоловочноrо файла (например, stdio .h) щелкните правой кнопкой мыши на строке "#include <stdio.h>" и из KOHCTeKCTHoro меню выберите пункт ОТКl'ытъ докуl'l<'НТ <st,lio.l,>. В результате з arоловочный файл stdio. h будет открыт на отдель ной вкладке. Следует заметить, что файл stdio.h сод ержит объявления идентификатор ов, предназначенных для операций ввода/вывода в языке С. Так как для вывода мы используем объект со ut, объявленный в файле iostream, то подключение файла stdio.h можно вообще удалить из файла stdafx.h. Производить операции ввода/вывода мы буд ем только в стиле языка С++. Теперь рассмотрим содержимое файла welcome. срр (листинr 1.3). Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  7  1612.10 I .1IИСТIПП 1.3. Содер ЖИI>юе фnй:rm ,,'еlcоюе .орр #include rrstdafx. h rr using narrespace std; int tmaln(lnt argc, TCНAR* argv[]) cout « rrWelcome to с++! rr « endl; return о; Сравните этот листинr с предыдущим при мер ом (листинr 1.1). Первое, что должно броситься в rлаза  это название функции (вместо названия main (1 используется название tmaln ( 1) и наличие двух параметров Параметры расположены внутри крyrл ых скоб ок и разделены запятой. Параметр состоит из объявления типа данных и названия. Первый параметр (argc) имеет тип int, который соответствует целочисленному :значению. Через этот параметр доступно количество apryMeHToB, переданных в командной строке. Следует учитывать, что первым apryMeHToM является название исполняемоrо файла. Поэтому значение параметра ar gc не может быть меньше единицы. Через второй параметр (argv) доступны все apryMeHTbl в виде строки (тип TCНAR *) Квадратные ско бки после названия BToporo параметра означают, что доступен массив строк Более подробно передачу apryMeHToB через командную строку мы рассмотрим далее в этой rлаве. Для вывода строки "Welcome to C++I ", как и в предыдущем примере, используется объект сои t, объявленный в файле io stre ат. Файп iostream мы подключили в файле stdаш.h, поэтому повторно подключать ero не нужно. Достаточно подключить только файл stdafu.h в начале проrpаммы. Обратите внимание на то, что перед объектом сои t и константой е ndl не указан о название пространства имен std, так как все идентификаторы, объявленные в пространстве имен s td были импортированы в основную проrpамму с помощью инструкции: using narrespace std; Хотя это очень удобно, следует избеrать импортирования всех идентификаторов в rло6альное пространство имен, так как возможны КОН фликты имен. Вме СТО этоrо способа лучше импортировать определенные идентификаторы. Например, импорruровать только иденru фикаторы с ои t и endl можно так: using std:: cout; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  8  1612.10 using std:: endl; Если необходимо импортировать все иденти фикаторы, то следует оrpаничить область видимости. Например, указ ать инструкцию using внутри функции. В этом случае область видимости оrpаничена рамками функции и в rлоб альное пространство имен идентификаторы не попадут. Скомпилировать и запустить проrpамму на исполнение можно также как и в предыдущем разделе. Для запуска без отладки нажимаем ко мбинацию клавиш <Ctrl>+<FS> Если нужно просто скомпилировать проект, то нажимаем клавишу <F7> Запуск с отладкой осуществляется нажатием клавиши <FS>. Запомните эти комбинации кл авиш наизусть. Структура "роrраl\II\IЫ Запускать проrpамму мы научились, теперь можно приступать к изучению языка С++. Как видно из предыдущих примеров, проrpамма состоит из инструкций, расположенных в текстовом файле. Структура обычной проrpаммы выrлядит так: <ПОдключение заrоловочных файлов> <Объявление rлобальных переменных> <Объявление функций, классов и др.> int main ([ int argc, char * argv [] ] 1 <Инструкции> return о; <Определение функций и классов> В самом начале проrpаммы подключаются зarоловочные файлы, в которых содержатся объявления идентификаторов без их реализации. Например, чтобы иметь возможность вывести данные в ОКНО консоли нео6ходи МО ПОДКЛЮЧИТЬ файл iostre ат, в которо М содержится объявление объекта сои t. Подключение осуще ствляется с ПОМОЩЬЮ директивы inc lude: # include <iostream > С помощью директивы incl ude можно подключать как стандартные зarоловочные файлы, так и пользовательские файлы. После подключения файл ов производится объявление 8Ло6алЫiЫХ nеременных. Переменные предназначены для хранения значений определенноrо Т1Iпа. lлобальные переменные видны во всей проrpамме, включая функции. Если объявить переменную внутри функции, то область видимости переменной будет оrpаничена рамками функции Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  9  1612.10 и в дрyrих частях проrpаммы использовать переменнJ'lO нельзя. Такие переменные назЫВaIOТСЯ локалЫiЫМU. Объявить целочисленнJ'lO переменнJ'lO можно так: int Х; В этом примере мы объявили переменную с названием 11 х" И указали, что переменная может хранить данные, имеющие тип int. Ключевое слово int означает, что переменная предназначена для хр анения целоrо числа. Попытка присвоитъ переменной значение, имеюще е дрyrой тип приведет к предупр ежденшо или ошибке. Исключением являются ситуации, в которых КО мпилятор мож ет произвести прео6разование типов данных без потери точности. Например, целое число без проблем преобразуется в веще ственное ЧИСЛО, однако попытка прео6разовать вещественное число в целое приведет к выводу предупреЖДaIOщеrо сообщения, даже если после точки стоит ноль. Пример сообщения: warning С 42 44: =: пр ео б р аз о вание rr do ub le rr в rr int rr, во зможна по те р я данных Хотя компилятор предупреждает о потери данных, проrpамма все равно будет СКО мпилирована. Поэтому обращайте внимание на сообщения, которые ВЫВОДЯТСЯ в окне Вывод на вкладке ПостоmI при компиляции. Иначе проrpамма будет работать, но результат выполнения будет некорректным. Обратите внимание на то, что объявление переменной заканчивается точкой с запятой. Большинство инструкций в языке С++ должно заканчивается точкой с запятой. Если точку с запятой не указ ать, то компилятор сообщит о синтаксической оши бке. Пример сообщения: error С2144: синтаксическая ошибка: перед rr int rr требуется rr; rr Чтобы увидеть строку, о которой с ообщает компилятор, сделайте двойной щелч ок мышью на сообщении в окне Вывод. В результате строка с ошибкой в проrpамме станет активной и слева от нее отобразится маркер. В нашем случае активной буд ет строка, расположенная сразу после объявления rлобальной переменной. При объявлении можно сразу присвоитъ начальное значение переменной. Присваивание значения переменной при объявлении называется инициализацией переменной. Чтобы произвести инициализацию переменной после ее названия указывается оператор =, а зате м значение. Пример : int х = 10; Если rлобальной переменной не присвоено значение при объявлении, то она буд ет иметь значение о. Если локальной переменной не присвоено значение, то переменная будет содер жать произвольное значение. Как rоворят в тако м случ ае переменная содержит II MyC ор 11 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  10  1612.10 Обратите внимание на то, что перед оператором = и после Hero вставлены пробелы. КоличеС1БО пробелов может быть произвольным или пробелов может не быть вовсе. Кроме Toro, допускается вместо пробелов использовать символ перевода строки или символ табуляции. Например, эти иструкции вполне допустимы: int х=21; int у= int z 85; = 56; Тем не менее, следует придерживаться единообразия в коде и обрампять операторы одним пробелом. Если присваивание про изводится в объявлении функц ии (задается значение параметра по умолчанию), то пробелы принято не указывать вовсе. Следует уч итывать, что это не строrие правила, а лишь рекомендации по оформлению кода. Как видно из предыдущеrо при мера, инструкция может быть расположена на нескольких строках. КОНЦОМ инструкц ии является точка с запятой, а не конец строки. Например, на одной строке может быть несколько инструкций: int х = 21; int у = 85; int z = 56; пз этоrо правила есть исключения. Например, после директив препроцессора точка с запятой не указ ывается. В ЭТОМ случае концом инструкции является конец строки. Директиву препроцессора можно узнать по символу # перед названием директивы. Типичным примером директивы препроцес сора является директива inc 1ude, которая используется для подключения зarоловочных файлов: # include <iostream > После объявления rлобальных переменных MOryт располarаться объявления функций и классов. Такие объявления называются прототШ2аМU. Схема прототипа функции выrлядит следующим образом: <Тип возвращаемоrо значения> <Название функции>([<Тип> [<Параметрl>] [, ..., <Тип> [<Параметр Ы>] ] ] 1 ; Например, прототип функции, которая складывает два целых числа и возвращает их су мму выrлядит так int summa(int х, int у); После объявления функции необходимо описать ее реализацию, которая называется определением функции. Определение функции обычно располarается после определения функции main ( 1 . Обратите вниманние на то, что объявлять прототип функции main (1 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 11  1612.10 не нужно, так как определение этой функции обычно расположено перед определением друrих функций. Пример определения функции summa ( 1 : int summa(int х, int у) return х + У; { Как видно из примера, первая строка в определ ении функц ии summa (1 совпадает с объявлением функции. Следует заметить, что в объявлении функции можно не указыв ать названия параметров. Достаточно указ ать информацию о типе данных. Таким образом, объявление функции можно записать так: int summa(int, int); После объявления функции ставится точка с запятой. В определении функции внутри фиryрных скобок должна быть описана реализация функции. Так как в объявлении указ ано, что функция возвращает целочисленное значение, следовательно после описания реализации необходимо вернуть значение. Возвращаемое значение указыв ается после ключевоrо слова r eturn. Если функция не возвращает никакоrо значения, ТО перед названием функции вместо типа данных указывается ключевое слово vo id. Пример объявления функц ии, которая не возвращает значения: void pr int (int) ; Пример определения функции р r int (1 : void print(int хl std::cout «х «std::endl; Вся ре ализ ация функции должна быть расположена внутри фиryp ных ско бок Открывающая скобка может находиться на одной строке с определением функции, как в предыдущем примере, или в начале следующей строки. Пример: void print(int хl { std::cout «х «std::endl; Мноrие проrpаммисты СЧИТaIOТ такой стиль наиболее прие:млемым, так как открывающая и закрывающая скобки расположены дрyr под дрyrом. На мой же взrляд образуется лишняя пустая строка. Так как размеры экрана оrpаничены, при наличии пустой строки на экран помещается меньше кода и прИХОДИТСЯ чаще пользоваться полосой прокрутки. Если размещать инструкции с равным отступом, то блок кода выделяется визуально и следить за положением фиrypн ых скобок просто излишне. Тем Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  12  1612.10 более, что редактор кода позволяет под светить парные ско бки. Чтобы найти пару фиryрных ско бок следует поместить указатель ввода перед скобкой. В результате СКО 6ки будут подсвечены. Какой стиль использовать, зависит от личноrо предпочтения проrpаммиста или от правип офор мпения кода, принятых в определенной фирме. lлавное, чтобы стипь оформпения внутри одной проrраммы был одинаковым. Перед инструкциями внутри фиrурных скобок следует размещать одинаковый отступ. В кач естве отступа можно использовать пробелы или символ табуляции. При использовани пробелов размер отступа равняется трем или четырем пробелам для блока первоrо уровня. Для вложенных блоков количество пробелов УМНОЖaIOТ на урОБ ень вложенности. Если для блока первоrо уровня вложенности использовалось три пробела, то ДЛЯ блока BToporo ур ОВНЯ вложенности ДОЛЖНО использоваться шесть пробелов, ДЛЯ тpenero уровня  девять пробелов и т. д. В одной проrpамме не следует использовать и пробелы и табуляцию в качестве отступа. Необходимо выбрать чтото одно и пользоваться этим во всей проrpамме. Закр ЫВaIOщая Ф иryрная скобка обычно размещается в конце блока на отдельной строке. После СКО 6ки точка с запятой не указывается. Однако наличие точки с запятой оши6ко й не является, так как инструкция может не содерж ать выражений вообще. Например, такая инструкция вполне допустима, хотя она ничеrо не делает: Самой rлавной функцией в проrpамме является функция main (1 . Именно функц ия с названием main (1 будет автоматически вызываться при з алуске проrpаммы. Функцня и ме ет ДЕ а пр ототи п а: int main(); int main(int argc, char *argv[J); Первый прототип функции имеет синоним: int main (void) ; Значение void означает, что функция не принимает пара метры. Подобный синтакс ис используется в языке проrpаммирования С. В языке С++ указание ключевоrо слова vo id является излишним. Достаточно указ ать пустые скобки. Второй прототип при меняется для получения значений, указанных при запуске проrpаммы из командной строки. Количество значений доступно через параметр argc, а сами значения через параметр arg-v. Перед названием функции указ ывается тип возвращаемоrо значения. Ключевое слово in t означает, что функция возвращает целое число. Возвращаемое значение указыв ается после ключ eвoro слова re turn в само м конце функции main () . Число о Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  13  1612.10 означает нормальное завершение проrpаммы. Если указано друтое число, то это свидетельствует о некорректном завершении проrpаммы. Соrласно стандарту, внутри функции main () ключевое слово r etur n МОЖНО не указывать. В этом случае ко мпилятор должен самостоятельно вставить инструкцию, БОЗВращmoщJ'lO значение о. Во:звр ащаемое значение передается операционной системе и может использоваться для определения корректности завершения проrpаммы. В листинrе 1.4 приведен пример проrpаммы, структуру которой мы рассмотрели в этом раздел е. Не расстраивайтесь, если ЧТОТО показалось непонятным. Все ЭТО мы будем изуч ать более подробно в следJ'lOЩИХ rл ав ах книrи. На ЭТОМ этапе достаточно лишь представлятъ структуру проrраммы и самое rлавное уметь ее скомпилировать и запустить на выполнение. Напомню, что ДЛЯ выполнения проrpаммы следует создать пустой проект, а не консольное приложение. I .1IИСТIПП 1.4. ПрИI>reр проrрnI1Ы 11 Подключение заrоловочных файлов # include <iostream > 11 Объявление rлобальных переменных int х = 21; int у = 85; 11 Объявление функций, классов и др. int summa(int х, int у); void print(int х); 11 r лавная функция int main () in t z; 11 сб ъявле ние ло каль ной пе реме нно й z = summa (х, у); 11 Вызов функции s'l.1tLl1Lla () pr int (" 1 ; / / Вызов функции pr int (1 return о; { 11 Определение функций и классов int summa(int х, int у) return х + У; void print(int хl std::cout «х «std::endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  14  1612.10 КОI\II\Iентарпп в "porpaMMe Комментарии предназначены для БСТаБЮI пояснений в текст проrpаммы и компилятор полностью их иrнорирует. Внутри комментария может располаrаться .тno60Й текст, включая инструкции, которые выполнять не следует. Помните, комментарии нужны проrpаммисту, а не ко мпилятору. Вставка комментариев в КОД позволит через некоторое время быстро вспомнить предназначение фрarмента кода. В языке С++ пр и сутств уют два типа комментариев: однострочный и MHoro строчный. Одностроч'НЫЙ комментарий начинается с символов 11 и заканчивается в конце строки. Вставлять однострочный комментарий можно как в начале строки, так и после инструкции. Если символ комментария разместить перед инструкцией, то она не будет выполнена Если символы 11 расположены внутри кавычек, то они не является признаком начала комментария. Примеры однострочных комментариев: 11 Это комментарий std: : cout « rrHello, world! rr; 11 Это комментарий 11 std:: cout « rrHello, world! rr; 11 Инструкция выполнена не будет char s [] = rr // Это НЕ комментарий! ! ! rr; МНО80С тро ч, н ый ком.ме нтарий н ач ин ается с с и мв ол ов / * и з аканч ив ает ся с и мв ол ами * /. Комментарий может быть расположен как на одной строке, так и на нескольких. Кроме Toro, :мноrо строчный комментарий можно раз мещать внутри выражения, хотя это и нежелательно. Следует иметь в виду, что MHoro строчные комментарии не Moryт быть вложенными, поэтому при комментировании больших блоков следует проверятъ, что в них не встречается заКРЫВaIOщая комментарий комбинация символов * /. Тем не менее, однострочный комментарий мож ет быть расположен внутри мноrострочноrо комментария. Примеры мноrострочных комментариев: /* Мноrострочный комментарий */ std: : cout « rrHello, world! rr; /* Это комментарий * / /* std:: cout « rrHello, world! rr; // Инструкция выполнена не будет * / int Х; Х = 10 /* Комментарий */ + 50 /* внутри выражения */; char s [] = rr /* Это НЕ комментарий! !! * / rr; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  15  1612.10 Редактор в VC++ позволяет быстро закомментировать фрarмент кода. Для этоrо необходимо выделить одну инструкцию (или сразу несколько инструкций), а затем из меню Прав};;:;) выбрать пункт ДОПОJППIТI?'Jn.НО I ПРl?'образовать ВЫДI?'Лl?'lПIыii фраrмl?'НТ в :к OI'o-II'o-I{IНТ а}) Iп"i. Можно также нажать кнопку ЗаКОI'o-II'o-Ie'НТIч)овать ВЫ,Це'ЛI?'IПIЫI?' ("тро:кп на панели инструментов TI?'KfTOBblii })I?'дактор. Если панель инструментов не отображена, в меню Вид выбираем пункт ПаИJШ IПНТ}))"'1'о-II?'НТОВ I TI?'KfTOВblii })I?'дактор. Кроме тoro, можно воспользоваться клавишами быстроrо доступ а. Для этоrо следует нажать комбинацию клавиш < Ctrl >+<К>, а зате м ко мбинацию кл авиш <Ctrl>+<C> Если строка выделена полностью, то перед ней будет вставлен однострочный комментарий. Если выделен лишь фрarмент строки, то он буд ет обернут в мноrострочный комментарий. Чтобы убрать комментарий следует выделить фр асмент, а затем из меню Пl'авка выбрать пункт ДОПОJППIТI?'Jn.НО I OTI'o-Ie'IПIТЬ Щ)l?'обраЗОВ:;)IПII?' в :к OI'o-II'o-II?'НТ:;)Iн-п"i. Можно также нажать кнопку ОТМI?'IПIТЬ Щ)l?'обраЗОВ:;)IПII?' ВЫде'ЛI?ННЫХ ("тро:к в :KOI'o-II'o-II?'НТ:;)lн-п"i на панели инструментов ТI?'К("ТОВЬП":'"I })I?'дактор. Кроме Toro, можно воспользоваться кл авишами быстроrо доступа. Для этоrо следует нажать комбинацию клавиш <Ctrl>+<K>, а затем комбинацию клавиш <Ctrl>+<U> ВЫВОД данных В языке С++ Для вывода данных в языке С++ предназначены объекты сои t, cer r И с 10g, объявленные в файле io stre ат. Объект с out используется для вывода обычных сообщений в окно консоли. Объекты се rr И clo 9 применя::ются для вывода сообщений об оши бках. Такж е как и объект со ut объекты се rr И с 10 9 первоначально связаны с окном консоли, однако возможно перенаправить поток на друтое устройство или в файл. Для понимания всех возможностей этих объектов требуется знание принципов объектноориентированноrо проrpаммирования (ООП). Так как ООП мы еще не изуч али, в этом разделе будут рассматриваться только основные возможности объектов. В последJ'lOЩИХ rлавах мы вернемся к изучению ЭТИХ объектов. Прежде чем использовать объекты необходимо подключить файл iostream с помощью директивы inc 1ude: # inc1ude <iostream > Обратите внимание на то, что название файла указывается внутри yrловых скобок без расширения h, так как файл io stream входит в состав стандартной библиотеки С++. После подключения файла все объекты будут доступны через пространство имен st d, поэтому при обращении к объекту необходимо указ ать название пространства имен и Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  16  1612.10 два символа двоеточия перед названием объекта. Например, вывести строку "Неll0, world!" можно так: std: : cout « rrHello, world! rr; Если каждый раз указывать название пространства имен лень, то можно импортировать все иденти фикаторы в rлобальное пространство имен с помощью инструкции: using narrespace std; В этом случае название пространства имен указ ывать не нужно: cout « rrHello, world! rr; Хотя это очень удобно, следует избеrать импортирования всех идентификаторов в rло6альное пространство имен, так как возможны КОН фликты имен. Вме СТО этоrо способа лучше импортировать определенные идентификаторы. Например, импорruровать только объект с out можно так: using std:: cout; После названия объекта указывается оператор «, который как бы указывает направление вывода. При разработке собственных объектов можно переrpузить этот оператор и тем самым управлять выводом. После оператора « передается объект, который будет выведен в окне консоли. В каче стве объекта можно указать число, строку, а также объект, в котором оператор « переrpужен. Пример: std: : cout « std: : cout « std: : cout « char str[] = std::cout «str; 11 Строка Результат выполнения этоrо примера будет таким: 1081.5Hello, world!Hello, world! Как видно из результата, все данные ВЫВОДИЛИСЬ на отдельных строках (сокращение от" end line "). Пример: 10; // Целое число 81.5; // Вез.u=ственное число rr Hello , world! rr; // с тро ка rr Hello , world! rr; выводятся на одной строке. Чтобы данные можно воспользоваться константой е ndl std: : cout « rrStr ingl rr; std: : cout « std: : endl; std: : cout « rrStr ing2 rr; Результат в окне консоли: Stringl String2 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  17  1612.10 На самом дел е е ndl не совсем константа. Можно сказать, что ЭТО функция (называемая манипулятором), внутри которой производится вывод символа перевода строки и возвращается ссылка на поток вывода. Блarодаря возврату ссылки можно строить цепочки из операторов «. Например, предыдущий пример можно залисать так: std: :cout « rrStringl rr « std: :endl « rrString2 rr ; Для перевода строки можно также воспользоваться комбинацией символов "\n ll , которые обозначают символ перевода строки. Пример : std: :cout « rrStringl rr « rr\n rr « rrString2 rr ; Для вывода строк, состоящих из двухбайтных символов, предназначены объекты wco ut, wce rr И wclo g, объявленные в файле io stream. Объект wcou t предназначен для вывода обычных сообщений, а объекты wc er r И wclog для вывода сообщений 06 ошибках. Пример: std: :wcout « Lrrstring rr ; С помощью стандартноrо вывода можно создать индикатор выполнения процесса в окне консоли. Чтобы реализовать такой индикатор нужно ВСПОМНИТЬ, что символ перевода строки в Windows состоит из двух символов \ r (перевод каретки) и \ n (перевод строки). Таким образом, используя только символ перевода каретки \ r можно перемещаться в начало строки и перезаписывать ранее выведенную ин формацию. П ример индикатора процесса показан в листннrе 1. s. I .1IИСТIПП 1.5. Индик nTop въшолнения про цeccn #include <iostream> int main (1 int i, j; std: : cout « rr... 0%"; for (i=5; i<101; i+=51 { for (j=O; j<500000000; ++jl; // Имитация цроцесса std: : cout « rr\r... rr « i « rr%rr; std::cout «std::endl; return о; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  18  1612.10 Так как данные перед выводом Moryт помещаться в буф ер, вполне возможно потребуется сбросить буф ер явным образом. Сделать это можно с помощью метода flush(l: std::cout.f1ush(l; ВЫВОД данных В языке С Язык С++ поддерживает также операции вывода из языка С, объявленные в файле stdio. h. В языке С++ вместо этоrо файла можно подключать файл cstdio: # include <cstdio> Для вывода одиночноrо символа применяется функция р ut char (1 . Прототип функц ии: int putchar(int Ch); Пример вывода символа: std: : putchar ( I w I ); 11 w std::putchar (1191; // w Вывести строку позволяет функция ри ts ( 1 . Прототип функции: int puts(const char *Str); Функция выводит строку St r и вставляет символ перевода строки. Пример: std::puts(rrStringlrr); std::puts(rrString2rr); Резуль тат в ып ол н ен ия: Stringl String2 Для Ф орматированноrо вывода используется функция pr in t f (1 . Прототип функции: int pr intf (const char * Format, ...); В параметре F ormat указыв ается строка специальноrо формата. Внутри этой строки можно указать обычные символы и спецификаторы формата, наЧИНaIOщиеся с символа %. Вместо спецификаторов формата подставляются значения, указанные в качестве парамеТРОБ. Количество спецификаторов ДОЛЖНО совпадать с количеством переданных парамеТРОБ. В качестве значения функция возвращает количество выведенных символов. Пример вывода строки и числа: std::printf(rrString\n rr ); std: : printf (rrCount %d\nrr, 10); std: : printf (rr%s %d\nrr, rrcount rr , 10); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  19  1612.10 Резуль тат в ып ол н ен ия: String Count 10 Count 10 В первом примере строка формата не содержит спецификаторов и выводится как есть. Во втором примере внутри строки фор мата используется спецификатор Ы, предназначенный для вывода целоrо числа. Вме СТО этоrо спецификатора подставляется число 1 о, переданное во втором параметре. В треть ем примере строка содержит сразу два специ фикатор а %s и ы. Специ фикатор %s, предназначен для вывода строки, а спецификатор % d  для вывода целоrо числа Вме сто спецификатора %s будет под ставлена строка "С ount", а вместо спецификатора %d  число 10. Обратите внимание на то, что тип данных переданных значений должен совпадать с типом спецификатор а. Если в каче стве значения для специ фикатора %s указать число, то это приведет в ошибке времени исполнения. Никакой проверки соответствия типа на этапе ко мпиляции не ПрОН'ЗБОДИТСЯ. Спецификаторы имеют следующий синтаксис: % [<Модификаторы>] [<Ширина>] [.<Точность>]<Тип> В параметре <Тип> Moryт быть указаны следующие символы: -+ с  символ: std:: printf (rr%c rr , Iw l ); 11 w std:: printf (rr%c rr , 119); 11 w -+ s  строка: std: : printf (rr %srr, rrstring rr ); 11 String -+ d или i  десятичное целое число со 'Знаком: st d: : р r int f (" % d Н", 1 О, 3 01 ; / / 1 О 3 О std: :printf ("%d Н", 10, 301; // 10 зо -+ u  десятичное целое число без 'Знака: std: : printf (rr %u rr , 10); 11 10 -+ о  восьмеричное число без 'Знака: std: : printf (" %0 %0", 10, 0771; / / 12 77 std: : printf (" %#0 %#0", 10, 0771; / / 012 077 -+ х  шести адц атеричное число без 'Знака в нижнем реrистре: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/СНА,2010ii 20 1612.10 std: : printf (rr %х %х rr, 10, Oxff); 11 а ff std: : printf (rr %#х %#х rr, 10, Oxff); 11 Оха Oxff -+ х  шестн адц атеричное число без знака в верхнем реrистре: std: : printf (" %Х %Х", 10, Oxffl; / / А FF std: : printf (" %#Х %#Х", 10, ОхН 1; / / ОХА OXFF -+ f  вещественное число в десятичном представлении: std::printf("H Н", 18.65781452, 12.51; //18.65781512.500000 std: : printf (" Н",  18.657814521; / /  18.657815 std::printf("%#.Of %.Of", 100.0, 100.01; // 100. 100 -+ е  вещественное число в экспоненциальной форме (буква "е" в нижнем реrистре): std: : printf (" %е", 18657.814521; / / 1.8 65781е+004 std: : printf (" %е", 0.0000814521; / / 8 .1452 OOe 005 -+ Е  вещественное число в экспоненциальной форме реrистре): std: : printf (" %Е", 18657.814 521; / / 1.8 65781Е+004 -+ g  эквивалентно f или е (выбирается более короткая запись числа): (буква 1111 е в верхне м std: : printf (" %g %g %g", 0.086578, 0.000086578, 1. 8 65E0051 ; // 0.086578 8.6578e005 1.865e005 -+ G  эквивалентно f или Е (выбирается более короткая запись числа): std::printf("%G %G %G", 0.086578, 0.000086578, 1.865E0051; // 0.086578 8.6578E005 1.865E005 -+ р  вывод адреса переменной : int х = 10; std: : printf (" %р", &xl; / / 0012 FF 60 st d: : р r int f (" % #р", &х 1; / / ОХОО 12 FF 6 О -+ %  символ процента (%): std: : printf (" 10% %" 1; / / 10% Параметр <Ширина> задает минимальную ширину поля. Если строка меньше ширины ПОЛЯ, то она дополняется про6елами. Если строка не помещается в указ aHHJ'lO ширину, ТО значение иrнорируется и строка ВЫВОДИТСЯ полностью: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  21  1612.10 std: : printf (rr I %35 I rr, rrstring rr ); 11 I string I std: : printf (rr I %105 I rr, rrstring rr ); 11 string I Задать минимальную ширину можно не только для строк, но и для друrих типов: std: : pr intf (rr I % 10d I rr, 25); 11 25 I std: : printf ('" %10f''', 12.51; / / 12.500000' Параметр <Точное ть > задает количество :знаков после точки для веще ственных чисел. Перед этим параметро м обязательно должна стоять точка. Пример: std: : printf ('" %10. 5f''', 3 .141592653591; / / 3.14159' std: : pr intf (" , %.3 f ' ", 3. 141592653591 ; / / '3 .142 ' Если параметр <Точно с ть > используется применительно к целому числу, то минимальное количество цифр. Если число содержит меньшее количество вначале числа доб авляются нули. Пример : // // / / '123456789' он задает цифр, то std::printf(rr'%7d ,rr , std::printf(rr'%.7d ,rr , std::printf(rr'%.7d ,rr , 1001 ; 1001 ; 1234567891 ; 100' '0000100' Если параметр <Точно с ть > используется применительно максимальное количе С1БО СИМВОЛОВ. Символы, которые отброшены. Пример: std: : pr intf (rr I %5.75 I rr, rrHello, world! rr) ; 11 I Hello, std: : pr intf (rr I % 15.205 I rr, rrHello, world! rr); 11 Hello, world! Вме сто минимальной ширины и точности можно указать символ *. в этом случае значения передаются через параметры функции р r int f (1 в порядке указания символов в строке формата. Примеры: к строке, то он н е по мещaIO тся задает будут std: : printf ('" %*. *f''', 10, 5, 3.141592653591; / / 3.14159' std: : pr intf (" , %. * f ' ", 3, 3. 141592653591 ; / / '3 .142 ' std: : printf (rr I %*s I rr, 10, rrstring rr ); 11 string I В первом примере вместо первоrо символа * подставляется число 1 О, указанное во втором параметре, а вместо moporo символа * подставляется число 5, указанное в третьем параметре. Во втором примере вместо символа * подставляется число 3, которое задает количество цифр после точки. В треть ем примере символ * заменяется числом 1 О, которо е задает минимальную ширину поля. В параметре <МОД ификато ры> MoryT быть указаны следующие символы: -+ #  для восьмеричных зн ачений добавляет в начало символ rro rr, шестнадцатеричных значений добавляет комбинацию символов rro Х rr для (если Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  22  1612.10 используется тип rrXrr) ИЛИ rrox rr (если используется тип rrx rr ), для вещественных чисел указывает всеrда ВЫВОДИТЬ дробную точку, даже если задано значение О в параметре <Точно сть>: std: : printf (rr %#0 %#0 rr, 10, 0771 ; // 012 077 std: : printf (rr %#х %#х rr, 10, Oxffl; // Оха Oxff std: : printf (" %#Х %#x rr , 10, Oxffl; // ОХА OXFF std::printf("%#.Of %. Of rr, 100.0, 100.01 ; // 100. 100 -+ о  задает наличие ведущих нулей ДЛЯ числовоrо знач ения: std: : printf (rr I %7d I rr, 100); 11 100 I std: : printf (rr I %07d I rr, 100); 11 10000100 I -+   задает выравнивание по левой rpанице области. По умолчанию используется выравнивание по правой rpанице. Пример: std::printf(rr'%5d ' '%5d'rr, 3, 3); 11 31 13 st d: : р r int f (rr I %0 5d I I % 05d I rr, 3, 3); 11 I 00003 I 13 -+ пр об ел  вставляет пробел перед положительным ЧИСЛОМ. Перед отрицательным числом будет стоять минус. Пример : std::printf(rr,% d ' 1% d 'rr , 3, 3); 11 '31 31 -+ +  задает обязательный вывод знака, как для отрицательных, так и для положительных чис ел. Пример: std::printf(rr'%+d ' '%+d 'rr , 3, 3); 11 '31 1+31 -+ h  предназначен для вывода значения переменной, имеющей тип s ho rt in t. Пример: short int х = 32767; st d: : р r int f (" % hd", х 1; / / 32767 -+ 1 (буква Il эль 11) предназначен для вывода значения переменной, имеющей Т1Iп 10ng int. Пример: 10ng int х = 2147483647; std::printf("%ld", xl; //2147483647 Модификатор 1 можно двухбайтноrо символа соответственно. Пример: использ овать совместно с типами с и s, для вывода и строки, состоящей из двухбайтных символов Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  23  1612.10 wchar t str[] = Lrrstrlng rr ; std: : printf (rr %ls rr, str); 11 string -+ L предназначен для вывода значения переменной, имеюще й тип long do ub le. Пример: 10ng douk1e х = 8е+2 45; std: : printf (" Не", xl; / / 8. ООООООе+245 Следует учитывать, что функции ри tc har ( 1 , р uts (1 и р r in tf (1 при меняются в языке с. ХОТЯ ИХ можно использовать и в языке С++, тем не менее для вывода данных стоит отдать предпочтение объекту со ut. Описание функций р utc har (1 , ри ts (1 и pr in t f (1 приведено в этой книrе лишь для Toro, чтобы вы моrли разобраться в чужо м коде. В оставшейся части книrи мы будем использовать только обь ект сои t. Ввод д;нrnых в языке С++ Для ввода данных в языке С++ предназначен объект с in, объявленный в файле iostre ат. Объект с in позволяет BBecТ1l данные лю60rо BcтpoeHHoro типа, например, ЧИСЛО, символ ИЛИ строку. В этом разделе мы рассмотрим ЛИШЬ основные возможности этоrо объекта, так как ДЛЯ понимания всех возможностей требуется знание прИНЦИПОБ объектноориентированноrо проrpаммирования (ООП). В последующих rл ав ах мы вернемся к изучению объекта с in. Прежде чем использовать объект cin необходимо ПОДКЛЮЧИТЬ файл iostream с помощью директивы include: # include <iostream > В кач естве примера использования объекта с in произведем суммирование двух целых ч исел, введенных пользователем (листинr 1. б). I .1IИСТIПП 1.6. С)"",rnp овnние ДБр: введенных чисел # include <iostream > int main (1 int х = о, у = о; std::cout « rr x = rr; std: : cin » х; std: : cout « rry = rr; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  24  1612.10 std: : cin » У; std: : cout « rrS'l.1tLl1Lla = rr « х + у « std:: endl; return о; { в первой строке производится подключение файла iostre ат. Далее внутри функции main () объявляются две локальные переменные: х И у. Ключевое слово int в начале строки означает, что объявляются целочисленные переменные. При объявлении переменным сразу присваивается начальное значение (О) с помощью оператора. Если значение не присвоитъ, ТО переменная будет иметь произвольное значение, так называемый "мусор". Как ВИДНО из примера, на ОДНОЙ строке можно объявить сразу несколько переменных, разделив их запятыми. В слеДJ'lOщей строке с помощью объекта со ut ВЫВОДИТСЯ подсказка для пользователя (rr X = rr). Блarодаря этой подсказке пользователь будет :знать, что от Hero требуется. После ввода числа и нажатия клавиши <Enter> значение будет присвоено переменной х. Ввод значения прОИЗВОДИТСЯ с помощью объекта с in. После названия объекта указывается оператор », который как бы указывает направление ввода. При разработке собственных объектов можно переrpузить этот оператор и тем самым управлять вводом. После оператора » передается название переменной, в которой будут сохранены введенные данные. Так как объ екты с out и cin объявлены в пространстве имен s td, название пространства имен необходимо указ ать перед объектами. Далее производится вывод подсказки и получение BToporo числа, которое сохраняется в переменной у. В следующе й строке производится сложение двух чисел и вывод результата. Процесс ввода двух чисел и получения суммы выrлядит так: х = 10 У = 20 Summa = 30 При вводе данных производится попытка преобразования к типу переменной. В наше м примере строка" 1 О" будет преобразована в число 1 О, а строка "2 О" в число 20. Однако, вместо числа пользователь может BBecТ1l БУIffiЫ. В этом случае преобразование закончится неудач ей, переменной не будет присвоено значение, а введенное значение останется в буфере и будет автоматически считано следующей операцией ввода. Проверить отсутствие ошибки при преобр азовании можно с помощью метода go od (1 объекта cin. Прототип метода: bool good() const; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  25  1612.10 Метод goo d () возвращает лоrическое значение tr ие, которое соотвествует числу 1, если ошибок не ПрОИЗОШТIО, или значение false, СОО1БеТСТВJ'!Oще е числу О, в противном случае. Вывести сообщение об ошибке и прервать выполнение проrpаммы можно так: std::cout « rr x = rr; std: : cin » Х; if (std:: cin. good (1 == falsel std::cout « rrError rr «std::endl; re t ur n 1 ; 11 Бых од им из фуНl'ЩИИ main () { В этом примере для проверки усл овия используется оператор ветвления Н. После названия оператора внутри круrлых скобок указывается проверяе мое выражение. Если выражение возвращает лоrическо е значение true (истина), то будут выполнены инструкции внутри Ф иryрных скобок Если выражение возвращает значение fa1se (ложь), то инструкции внутри Ф иryрных скобок иrнорируются и управление передается инструкции, расположенной сразу после закрывающей Ф иrурной ско бки. Проверка значения, Бозвращаемоrо методом goo d ( ) , осуще ствляется с ПОМОЩЬЮ оператора ==. При ошибке метод goo d (1 вернет значение fa1s е, следовательно условие f a1se == fa1s е буд ет истинным. В этом случае выводим с ообщение об ошибке и выходим из функции main (1 (и следовательно из проrpаммы), возвращая значение 1. Обратите внимание на то, что оператор проверки на равенство содержит два символа =. Указание одноrо символа = является лоrической ошибкой, так как этот оператор используется для присваивания значение переменной, а не для проверки уел ОБИЯ. Использ овать оператор присваивания внутри лоrическоrо выражения допускается, поэтому компилятор не выведет сообщение об оши бке, однако проrpамма может выполняться некорректно. Подобную ошибку часто допускают начинающие проrpаммисты. Например, в следующем примере вместо проверки равенства числу 11, ПРОИЗВОДИТСЯ операция присваивания: int х = 10; if (х = 111 std: : cout « rr x 11" «std::endl; { Любое число не равное О трактуется как лоrическое значение true, поэтому производится проверка условия true == tr ие, которое является ист1lным. Проверка соответствия условия значению t rue производится по умолчанию. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  26  1612.10 Прерывать выполнение проrpаммы в случае ошибки мы научились, теперь рассмотрим в озможность обработки ошибки (листинr 1.7). I .1IИСТIПП 1.7. Обр nбот Kn ошиб ок BBOД<l # include <iostream > int main (1 int х = О, У = о; boo1 f1ag = false; do { std::cout « rr x = rr; std: : cin » Х; if ('std: :cin.good(11 std::cout «std::endl « rrError rr «std::endl; std::cin.clear(); std::cin.ignore(255, 11 Сбрасываем флar ошибки '\n' 1; / / Очищаем буф=р else flag = true; while (' flagl ; f1ag = false; do std: : cout « rry = rr; std: : cin » У; if ('std: :cin.good(11 std::cout «std::endl « rrError rr «std::endl; std::cin.clear(); std::cin.ignore(255, 11 Сбрасываем флar ошибки '\n' 1; / / Очищаем буф=р else flag = true; while (' flagl ; std: : cout « rrS'l.1tLl1Lla = rr « х + у « std:: endl; return о; в этом примере внутри функции main (1 объявляются три локальные переменные: х, у И f lag. Переменные х И у являются целочисленными, а переменная f lag имеет Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  27  1612.10 лоrический тип Ь 001. Тип Ь 001 позволяет хранить в переменной только два значения: true (истина) и fa1se (ложь). Значение true соответствует числу 1, а значение fa1s е  числу о. В переменной f 1ag мы будем сохранять текущий статус обработки ошибок При возникновении ошибки ее необходимо 06ра60тать, а затем вывести повторный запрос на ввод числа. Вполне возможно эту процедуру нужно будет выполнить несколько раз. Причем количество повторов заранее неизвестно. Для выполнения ОДНИХ и тех же инструкций несколько раз предназначены циклы. В наше м примере используется цикл do... whi1e. Инструкции внутри фиrypн ых скобок будут выполняться ДО тех пор, пока лоrическое выражение после ключевоrо слова while является ИСТИННЫМ. Проверка условия ПРОИЗВОДИТСЯ после выполнения инструкций внутри фиrурных скобок, поэтому инструкции выполняются минимум один раз. Обратите внимание на лоrическое выражение ! f lag. Восклицательный :знак, расположенный перед переменной инвертирует значение. Например, если переменная содержит значение true, то выражение возвращает значение f alse. Так как проверка значения на истинность ПРОИЗВОДИТСЯ по умолчанию, выражение может не содержать операторов сравнения. Внутри цикла ВЫВОДИМ подсказку пользователю с помощью объекта со ut, а затем получаем значение с помощью объекта cin и сохраняем ero в переменной. Далее проверяем наличие ошибки с помощью метода goo d (1 объекта с in. Если произошла ошибка, то выводим сообщение II Епо[" . Так как ошибка была обработана необходимо сбросить флar ошибки. Для этоrо предназначен метод с 1ear (1 объекта с in. Прототип метода: void clear(iostate State=goodbit, bool Reraise=false); В прототипе всем параметрам присвоено начальное значение, поэтому, если значения по умолчанию устраивaIOТ, параметры можно не указывать. Сбросить флаr ошибки не достаточно, так как ошибочное значение попрежнему находится в буф ере. Если буфер не очистить, то значение буд ет автоматически передано следующе й операции ввода, что породит повторную ошибку. В результате цикл будет выполняться бесконечно. Проиrнорировать значение, расположенное в буфере, можно с помощью метода ignor е (1 объекта cin. Прототип метода:. istream &ignore(streamsize Count=l, inttype Metadelim=EOF); Первый параметр задает максимальное количество считываемых из буф ера символов (по умолчанию один символ). Второй параметр задает символразделитель. Если Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  28  1612.10 символразделитель встретится раньше, чем будет считано указанное количество символов, то считывание прекращается. Метод возвращает ссылку на поток В нашем примере очистка выполняется пока не будут считаны 255 символов, либо пока не встретится символ перевода строки (\ n). Символ перевода строки также удаляется из буфера. После очистки буфера проверяется значение переменной f 1ag. Так как значение переменной является ЛОЖНЫМ, цИКЛ будет выполнен еще раз. Если оши 6ки нет, выполняются инструкции, расположенные после ключевоrо слова else. В нашем случае переменной f lag присваивается значение t rue. Это значение является уел овием ВЫХОД а из цикла. Далее таким же способом получаем второе число. Так как в предыдущем цикле значение переменной f lag было изменено, перед ЦИКЛОМ ПрОИ3БОДИМ восстановление ложноrо значения. Иначе ВЫХОД из цикла произойдет даже в случае оши 6ки. Если второе число успешно получено, ПРОИЗВОДИМ ВЫВОД суммы чисел. После объекта cin можно указать сразу несколько переменных, разделив их операторами ». В этом случае при вводе все значения можно указать на одной строке. Между собой значения должны разделяться пробелами, табуляцией или символом перевода строки. Эти символы не будут присвоены переменным. Например, проrpамму суммирования двух целых чисел можно записать так: int х = о, у = о; std::cin »х »у; std: : cout « rrS'I.1tLI1LIa = rr « х + у « std:: endl; При вводе строки "10 2 О" число 10 будет присвоено переменной х, а число 2 О  переменной у. Пробел иrнорируется. Числа мы вводить научились, теперь попробуем ввести строку. char str[255]; std::cout « rrstr = rr; std: : cin » str; std::cout «str «std::endl; В первой строке объявляется символьный массив, состоящий из 255 символов. Строки в языке С++ представляют собой последовательность (массив) символов, последним элементом KOToporo является нулевой символ (\ о). Обратите внимание на то, что нулевой символ (нулевой байт) не имеет никакоrо отношения к числу о. Коды этих символов разные. В слеДJ'lOщей строке выводится под сказка пользователю. Далее объекту cin передается указ атель на первый элемент массива str . Если в окне консоли Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  29  1612.10 ввести строку" НеПо, world 1" и нажать клавишу <Enter>, то массив st r будет содержать значение "Неll0 ,\0". Фрarмент "world 1" останется в буф ере, так как символ пробела является символомразделителем. Чтобы получить определенное количество символов необходимо воспользоваться методом get line () объекта cin. Прототипы метода: istream &getline(char *Str, streamsize Count); istream &getline(char *Str, streamsize Count, char Delim); В первом параметре задается указатель на строку, а во втором параметре максимальное количе ство СИМВОЛОВ. В параметре D elim можно дополнительно указать символ оrpаничитель. Метод, соответствYIOЩИЙ первому прототипу, ПРОИЗВОДИТ считывание Со un t 1 символов. Если раньше встретится символ перевода строки (\ n), то считывается фр arMeHT до этоrо символа. Символ перевода строки считывается, но не записывается в массив. В конец массива автоматически вставляется нулевой символ. В кач естве зн ачения метод возвращает ссылку на поток ввода. Пример использования метода get 1ine (1 приведен листинrе 1.8. Метод, соответствующий второму прототипу, производит считывание Count  1 СИМВОЛОВ. Если раньше встретится символ De lim, то считывается фраrмент до этоrо символа. Символ De lim считывается, но не записывается в массив. В конец массива автоматически вставляется нулевой символ. В качестве значения метод возвращает ссылку на поток ввода. I .1IИСТIПП 1.8. Ввод строк и #include <iostream> int main (1 char str[255]; std::cout « rrstr  rr.  , std::cin.getline(str, 255); std::cout «str «std::endl; return о; Ввод д;нrnых в языке С Язык С++ поддерживает такж е операции ввода из языка С, объявленные в файле stdio.h. В языке С++ вместо этоrо файла можно подключать файл cstdio: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  30  1612.10 # include <cstdio> Для ввода одноrо символа предназначена функция ge tc har ( 1 . Прототип функции: int getchar (void) ; в качестве значения функция возвращает код введенноrо символа. Чтобы символ был считан необходимо после ввода символа нажать клавишу <Enter>. Если было введено несколько символов, то буд ет считан первый символ, а остальные останутся в буфер е. Ключевое слово void внутри крyrлых скобок означает, что функция не принимает никаких параметров. Пример получ ения символа: char ch; std::printf(rrch = rr); ch = std::getchar(l; Для ввода строки предназначена функция get s ( 1 , однако применятъ ее в проrpамме не следует, так как функция не производит никакой проверки длины строки, что может привести к переполнению буф ер а. Лучше получать строку посимвольно с помощью функции get char (1 . Пр ототип функц ии: char *gets(char *Buffer); Для получения и автоматическоrо преобразования данных в конкр етный тип (например, в целое число) предназначена функция s сап f (1. При вводе строки функция не ПРОИЗВОДИТ никакой проверки ДЛИНЫ СтрОЮI, что может привести к переполнению буфера. Поэтому лучше отказ аться от использования этой функции. Прототип функции: int scanf (const char * Format, ...); в первом параметре указывается строка специальноrо формата, внутри которой задаются спецификаторы, аналоrичные применяемым в функции pr intf (1, а также некоторые дополнительные спецификаторы. В последующих параметр ах передаются ссылки на переменные. Пример получения целоrо числа: int Х; std::printf(rr x = rr); std:: scanf (rr%d rr , &х); 11 СИМВОЛ & обязателен! ! ! Обратите внимание на то, что перед названием переменной х указан символ &. В этом случае передается адрес переменной х, а не ее значение. При вводе строки символ & не указыв ается, так как название переменной без maдpaTHblX скоб ОК является ссылкой на первый элемеит мас сива. Пример ввода строки: char *str [255]; std::printf(rrstr = rr); std: : scanf (rr %2 54 s rr, str); 11 СИМВОЛ & не указывается! ! ! Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  31  1612.10 Считывание символов ПРОИЗВОДИТСЯ до первоrо символаразделителя, например, пробела, табуляции или символа перевода строки. Поэтому после ввода строки "Неll0, worldl" переменная str будет содержать лишь фрarмент "НеПо,", а не всю строку. Следует уч итывать, что функции get char (1 , get s (1 и s сап f (1 при меняются в яз ыке с. ХОТЯ ИХ можно использовать и в языке С++, тем не менее для ввода данных стоит отдать предпочтение объекту cin. Описание функций getc har ( 1 , ge ts (1 и s сап f (1 приведено в этой книrе лишь для Toro, чтобы вы моrли разобраться в чужо м коде. В оставшейся части книrи мы будем использовать только обь ект cin. IIнтераКТIIВНЫII ВВОД CIII\IВOJIOB Объект cin позволяет получить символ только после нажашя клавиши <Enter>. Если необходимо получить символ сразу после нажатия кл авиши на клавиатур е, то в VC++ можно воспользоваться функциями get che (1 и getc h (1 , которые объявлены в файле conio.h. Прототипы функций: #include <conio.h> int getche(vold); int getch(vold); Прu.мечанuе В неко то рых комШlЛЯТ арах функции ge t с he (1 и ge t с h (1 называю тс я ge t с h е (1 и get ch (1 соответственно. Функция ge tc he (1 возвращает код символа и выводит ero на экран. Обратите внимание на то, что нормально ВЫВОДЯТСЯ только 6J'Iffibl анrлийскоrо алфавита. При вводе русских букв возможно некорректное отображение букв в консоли. При нажатии кл авиши на клавиатуре функц ия ge tc h (1 возвращает код символа, но сам символ на экран не выводится. Это обстоятельство позволяет использовать функцию getc h (1 для получения кон фиденциальных данных (например, пароля). Следует учитывать, что код символа возвращается и при нажатии некоторых служебных клавиш, например, <Ноте>, <End> и др. В каче стве при мера использования функции get ch (1 создадим проrpамму для проверки правильности ввода пароля (листинr 1.9). Пар оль мож ет содержать до 1 б символов (цифры от О до 9 и латинские буквы от "а" до "z" в любом реrистре). При нажатии клавиши вместо символа будем ВЫВОДИТЬ :звездочку. Если символ не ВХОДИТ в допустимый набор, выведем сообщение об ошибке и завершим проrpамму. Проверку введенноrо пар оля произведем после нажатия клавиши <Enter>. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  32  1612.10 I .1IИСТIПП 1.9. Ввод Шlроля #include #include #include <iostream> <conio.h> // <cstring> // Для Для getch (1 strcmp (1 int main (1 char passwd[17], ch; boo1 f1ag = false; int i = о; std: : cout « rrpassword: rr; do ch = getch (1 ; if (i > 15 1 1 ch '\ r' 1 1 ch flag = true; passwd[i] = 1\01; I\n l ) e1se if ( 11 11 (ch > 47 && ch < 581 (ch > 64 && ch < 911 (ch > 96 && ch < 12311 // Цифры от О до 9 / / Буквы от А до Z 11 Буквы от а до z passwd [i] = ch; std: : cout « 1* 1; ++i; { els е { 11 Е с ли нед опус ти:м:ый С ИМБО Л, ТО вых од им std: : cout « std:: endl « rrError rr « std:: endl; return о; { while (' flagl ; 11 Сравнение паролей if (std:: strcmp (passwd, rrtest rr) == О) std: : cout « std:: endl « rrOK rr « std:: endl; e1se { std::cout «std::endl « rrError rr «std::endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  33  1612.10 return о; { в начале проrpаммы производим подключение файлов io stream, conio.h и с string. Файл iostream необходим для использования объекта со ut, файл conio.h  для функции get ch (1 , а файл cstrmg  для функции str стр ( 1 , предназначенной для сравнения двух строк Объект со ut и функция str стр (1 находятся внутри пространства имен st d, в то время как функция get ch (1 находится в rлобальном пространстве имен, поэтому перед функцией ge tc h (1 имя пространства не указывается Далее внутри функции main ( 1 объявляем четыре переменные. В символьный массив passwd, содержащий 17 элементов (1 б символов + '\0'), будут записываться введенные символы. В символьную переменную с h будем записывать код нажатой клавиши. Лоrическая переменная f1ag предназначена для хранения статуса ввода (если содержит значение tr ие, ТО ввод пар оля закончен), а целочисленная пере менная i предназначена для хр анения текущеrо индекса внутри массива passwd. Обратите внимание на то, что первый элемент мае сива имеет индекс О, а не 1. После объявления переменных ВЫВОДИМ под сказку пользователю с помощью объекта со ut. Затем внутри цикла do . . . whi1e получаем текущий символ с помощью функции get ch (1 и сохраняем ero код в переменной ch В следующей строке проверяем выход индекса за rp аницы массива (i > 15) и нажатие клавиши <Enter> При нажатии кл авиши <Enter> передается последовательность символов \ r \ n (перевод каретки плюс перевод строки), однако функция ge tc h (1 может получить только один символ, поэтому проверяется наличие или символа \ r или символа \ n. Ме жду собой лоrические выражения разделяются с помощью оператора I I (лоrическое ИЛИ). Чтобы все выражение вернуло истину достаточно, чтобы хотя бы одно из трех лоrических выражений было ИСТ1lННЫМ. Если выражение i > 15 является ложным, то проверяется выражение с h == 1\ r 1, В противном случ ае все выражение считается истинным и дальнейшая проверка не осуществляется. Если выраж ение ch 1\ r I является ложным, то проверяется выражение ch == I \ n I , В противном случае все выражение считается истинным и дальнейшая проверка не осуществляется. Если выражение с h == 1\ n I является ложным, то все выражение считается ложным, в противном случае все в ыр аж е ни е сч итается и сти нн ы м. Если выражение является истинным, то ввод пароля закончен. Чтобы выйти из ЦИЮIа присваиваем переменной f lag значение t rue. Кроме Toro, вставляем нулевой символ в конец массива. Он буд ет обозначать конец строки с введенным паролем. Посл е этих инструкций управление передается в конец цикла и про изводится проверка условия ' Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  34  1612.10 f 1ag. Так как усл овие вернет fa1se (, tr ие) происходит выход из цикла. После выхода из цикла производим проверку правильности пароля с помощью функции str стр (1 и выводим соответствующее сообщение. Функция str стр ( 1 принимает в качестве парамеТРОБ две строки (указ атель на первый элемент символьноrо массива) и возвращает число О, если строки равны. Сравнение производится с учето м реrистра СИМВОЛОВ. Сравнивать две строки с помощью оператора == нельзя, так как в этом случае ПРОИЗВОДИТСЯ сравнение адресов переменных, а не символов в строке. Если ввод пар оля не закончен, то ПРОИЗВОДИМ проверку ВХО ждения символа в ДОПУСТ1lМЫЙ диапазон значений (цифры от О ДО 9 И латинские 6J'Iffibl ОТ 11 а" до "z" В любом реrистре). Выполнить проверку допустимости символа необходимо, так как функция ge tc h (1 возвращает также коды некоторых служе бных клавиш, например, <Ноше>, <End> и др. Если условие не соблюдается, то выводим сообщение об оши бке и возвращаем значение О, тем самым завершая выполнение проrpаммы. Проверяемое условие сод ержит более сложное выражение, нежели в предыдуще м условии. Выраж ение разбито на несколько мелких выражений с помощью круrлых ско бок Внутри первых круrлых скобок проверяется соответствие символа диапазону чисел от О до 9. Ци фра О соответствует коду 48, а цифра  коду 57. Коды остальных цифр находятся в диапозоне между этими кодами. Чтобы не перечислятъ в выражении коды всех цифр используется проверка двух условий, раздел енных оператором && (лоrиче ское И). Выражение (ch > 47 && ch < 58 1 следует читать так: "если переменная ch содержит символ, имеющий код больше 47 и меньше 58, то вернуть значение true, в противном случае  значение false 11. Если условие внутри первых СКО бок является истинным, то все выражение является истинным и дальнейшая проверка не производится. Если усл овие внутри первых крyrлых скобок является ложным, то проверяется условие внутри вторых крyrлых скобок. Условие внутри третьих крyrлых скобок проверяется только если условие внутри вторых крyrлых СКО бок является ЛОЖНЫМ. В место кодов символов можно указать сами символы внутри апостроф ов. В этом случае условие будет выrляд еть так: e1se if ( (ch >= 'О' && ch <= '9' 1 / / Цифры от О до 9 I I (ch >= I А I && ch -с= I Z I ) 11 Буквы от А до Z I I (ch >= I а I && ch -с= I z I ) ) 11 Буквы от а до z Если символ входит в допустимый диапазон, то сохраняе м символ в мас сиве, выводим звездочку в окно консоли, а затем увеличиваем значение в переменной i на единицу, тем самым перемещая указатель текущей позиции на следJ'lOЩИЙ элемент массива. Выраж ение ++ i соответствует выражению i = i + 1. После этих инструкций Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  35  1612.10 управление передается в конец цикла и производится проверка условия 'f 1ag. Так как условие вернет tr ие ( 'fa1s е) инструкции внутри цикла будут выполнены еще раз. Полученне данных нз КОI\НШДНОII строкн Передать данные можно в командной строке после названия файла. Чтобы получить эти данные в проrpамме используется следующий формат функции main ( 1 : int main(int argc, char *argv[]) // Инструкции return о; Через первый параметр (argc) доступно количество apryMeHToB, переданных в ко мандной строке. Следует учитывать, что первым apryMeHToM является нззвание исполняемоrо файла. Поэтому значение параметра ar gc не может быть меньше единицы. Через второй параметр (argv) доступны все aprYMeHTbl в виде строки (тип char *). Квадратные скобки после названия BToporo параметра означaIOТ, что доступен массив СтрОК. Рассмотрим получение данных из командной строки на примере (листинr 1.1 О). I .1IИСТIПП 1.10. ПоЛ)"Ч"ние дшmых из коmндной строки #include <iostream> int main(int argc, char *argv[]) std: : cout « rr argc = rr « argc « std:: endl; for (int i=O; i<argc; ++i) std::cout «argv[i] «std::endl; return о; Теперь скомпилируем проrpамму в конфиrурации Deb ug (можно и в Re1ease, но тоrда необходимо изменить путь к исполняемому файлу) и запустим проrpамму на выполнение с помощью ко мандной строки. Запускаем командную строку. Для этоrо в меню Пуск выбираем пункт ВЫПОJПШТЪ. В открывшемся окне набираем команду cmd и нажимаем кнопку ОК. Откро ется черное окно, в котором буд ет приrлашение для ввода команд. Переходим в папку C\book\test\Debug (в моем случае проект с названием "test" расположен в папке с:\ book). Для этоrо набираем команду: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  36  1612.10 cd C:\book\test\Debug В командной строке должно быть приrлашение: C:\book\test\Debug> Для запуска проrpаммы вводим команду: test.exe paraml param2 В этой команде мы передаем проrpамме test.exe некоторые данные ("pacaт 1 pacaт2"). Результат выполнения проrpаммы буд ет выrлядеть так: argc = 3 test.exe paraml  р aram2 Первый элемент массива (argv [О]) не всеrда будет содержать только название исполняемоrо файл а. Если в командной строке запуск производится следующим образом: C:\book\test\Debug\test.exe param1 param2 то элемент буд ет содерж ать не только название файла, но и путь к нему: argc = 3 C:\book\test\Debug\test.exe paraml  param2 Предотвращенпе закрытпя окна консолп При запуске проrpаммы с помощью комбинации клавиш <Ctrl>+<FS> в конце " д б " автоматически вставляется строка ля продолжения наж:мите лю J'lO клавишу. Нажатие любой клавиши прИВОДИТ к закрытию окна консоли. Однако конечный пользователь таким образо м запускать проrp амму не будет. Если запуск производится из командной строки, то пользователь смож ет увидеть результат, но если запуск ПРОИЗВОДИТСЯ с ПОМОЩЬЮ двойноrо щелчка на значке файла, то ОКНО консоли откроется, а зате м сразу закроется. Чтобы окно не закрывалось необходимо вставить инструкцию, ОЖИДaIOЩYIO нажатие клавиши. Сделать это можно несколькими способами. Первый способ заключается в использовании функции getch (1 (листинr 1.11). Возвр ащаемое функцией значение можно проиrнорировать. Пр ежде чем использовать функцию необходимо подключить файл conio. h. Прототип функции: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  37  1612.10 #include <conio.h> int getch(vold); I .1IИСТIПП 1.11. ИСIЮЛЪЗОВnние ф)...к.ЦlШ tcil() # include <iostream > #inc1ude <conio.h> // Для getch(1 int main (1 // Инструкции std: : cout « rrpress <Enter> ... rr; getch(l; return о; Второй способ заключается в использовании функции syst ет (1 (листинr 1.12). Эта функция позволяет передать команду операционной системе. Для вывода строки "Для продолжения наж:мите лю6J'lO клавишу" и ожидания нажатия клавиши предназначена ко манда ра use. Прежде чем использовать функцию необходимо подключить файл cstd1ib (или std1ib .h). Прототип функции: #inc1ude <cstd1ik> int system(const char *Command); I .1IИСТIПП 1.12. ИСIЮЛЪЗОВnние ф)...к.ЦlШ s)'steшО #include <iostream> #inc1ude <cstd1ik> / / Для system (1 int main(1 { // Инструкции std::system(rrpauserr); return о; Два предыдущих способа требовали подключения дополнительных файлов. Кроме Toro, функция get ch (1 может не поддерживаться компилятором (возможно потребуется использовать функц ию get ch (1), а функция system (1 выполняет MHoro лишних операций. Вместо этих способов лучше использовать метод ge t (1 объекта с in. Этот метод позволяет получить введенный символ. Ввод осуще ствляется после нажашя Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  38  1612.10 кл авиши <Enter> Возвращаемое функцией значение можно проиrнорировать. Прототип метода: #include <iostream> int get (1 ; При использовании метода get (1 следует учитывать один нюанс. Если в проrpамме производился ввод данных, то в буф ере MOryT остаться символы. В этом случае первый символ автоматически будет передан методу get (1 и окно консоли сразу закроется. Поэтому после ввода данных необходимо дополнительно использовать метод igno re (1 . Прототип метода: #include <iostream> istream &ignore(streamsize Count=l, inttype Metadelim=EOF); Первый параметр задает максимальное количество считываемых из буф ера символов (по умолчанию один символ). Второй параметр задает символразделитель. Если символразделитель встретится раньше, чем будет считано указанное количество символов, то считывание прекращается. Метод возвращает ссылку на поток вывода. В большинстве случаев достаточно иrнорировать один символ (обычно символ перевода строки), указав название метода без параметров: std::cin.ignore(l.get(l; Однако в буф ере Moryт остаться и друrие символы. Поэтому лучше проиrнорировать сразу несколько символов, указав их количество (например, 200) в первом параметре, а символ перевода строки ВО втором: std: :cin.ignore (200, I\n l ) .get (); Если ввода данных не было, то достаточно использовать только метод ge t ( 1 . Пример использования методов ge t (1 и ignor е (1 приведен в листинrе 1.13. .1IИСТIПП 1.13. ИСIЮЛЪЗОВnние "TOДOB get() И igIю",О # include <iostream > int main(1 { // Инструкции std: : cout « rrpress <Enter> ... rr; std::cin.get(); 11 Если не было ввода данных 11 std:: cin. ignore (200, 1\ n 1) . get О; 11 Если был ВВОД данных return о; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  39  1612.10 НастроlIка отображенпя русскпх букв в консолп До сих пор во всех операциях вывода мы использовали латинские букв ы. Для этоrо были основания. Например, попытаемся вывести текст на русско м языке: std:: cout « rrДобро пожаловать в с++! rr; В результате в оки е консоли отобразится нечитаемый текст: юсЁю яюцрьпотр ЕП! Т С ++ ! Причина искажения русских букв заключается в ТОМ, что по умолчанию в окне консоли используется кодировка ср8бб, а в проrpамме мы выводим текст в кодировке Windows  1251. Коды русских букв в этих кодировках отличаются, поэтому происходит искажение. При использовании командной строки пользователь может сменить кодировку вручную, выполнив команду: chcp 1251 Однако этоrо не достаточно. Кроме смены кодировки необходимо изменить нззвание шрифта, так как по умолч анию используются точечные шри фты, которы е не поддерживают кодировку Windows  1251. Для нормальноrо отображения русских букв следует в свойствах окна выбрать шрифт Lucida Соnеоlе. Ве е эти деЙС1БИЯ вы можете произвести на СБоем компьютере, однако пользователи не ЗНaIOТ в какой кодировке ВЫВОДЯТСЯ данные из вашей проrpаммы. Следовательно необходимо предус мотреть вывод русских букв в текущей кодировке консоли. пз менить кодировку консоли можно с помощью функц ии sys tem ( 1 , однако сменить шрифт довольно проблематично. Проще изменить кодировку текста с Windows  125 1 на ср8бб. При использовании Visual С++ преобразование кодировки про изводится автоматически после настройки локали (локальных настроек компьютер а). Настр оить локаль позволяет функция s et 10 ca1e ( 1 . Для использования этой функции необходи мо подключить файл сl0С ale (или 10саlе. h). Прототип функции: #include <clocale> char *setlocale(int Category, const char *Locale); В первом параметре указывается катеrория в виде числа от О до 5. В место чисел можно использовать макроопределения LC  ALL, LC С OLLA ТЕ, LC  СТУР Е, LC MONETAR У, LC NUМER I С и LC TIME. При компиляции макроопредел ения будут заменены соответствJ'lOЩИМИ числами. В о втором параметре задается название локали в виде строки (например, "RussianRussia.1251" или ".1251"). Вместо названия можно указать Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  40  1612.10 пустую строку. В этом случае будет использоваться локаль , настроенная в системе. П ример настройки локали и вывода русских букв приведен в листинrе 1.14. I ЛИСТIПП 1.14. Настройка ЛОКaJШ #include <iostream> #include <clocale> int main (1 std: : setlocale (LC ALL, rrRussian  Russia. 1251 rr) ; std: : cout « rrДобро пожаловать в с++! rr « std:: endl; std: : cout « rrНa;:ю.Iите <Enter> для закрытия окна... rr; std: : cin. get (1 ; return о; При использовании Visual С++ эта проrpамма корректно выводит русские буквы вне зависимости от Toro, используется в консоли кодировка Windows  125 1 или ср8бб. Однако при использовании дрyrих компиляторов (например, MinGW) русские буквы попрежнему будут отображаться некорректно. Поэтому напишем проrpамму позволяющую вывести текст в кодировке ср8бб. Кроме Toro, предусмотрим функции для преобразования строки из кодировки Windows  125 1 в ср8бб и обратно (листинr 1.15). I Лист IШr 1.15. Файл COlI\'el't. .орр #include <iostream> // Для cout и endl #include <cstring> // Для strlen () , strcpy (1 #include <new> // Для bad a110c #include <t\Iindows . h> // Для с har То ОеrnA ( 1 #include rrconverts. h rr и strcpys (1 11 ВЫВОД строки в кодировке СР 866 void prlllt cp866(const char *str, short int х) char *buf; try { buf = new char[std::str1en(strl + 1]; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 41  1612.10 catch (std:: bad  a110c енl return; CharToOemA(str, buf); switch (хl case о: std::cout« buf; break; case 1: std::cout« buf «std::endl; break; case 2: std:: cout « buf « rr rr; break; default: std::cout «buf; break; de1ete [] buf; { 11 Преобразование строки в кодировку СР866 void convert to cp866(char *str) char *buf; try { buf = new char[std::str1en(strl + 1]; catch (std:: bad  a110c енl return; CharToOemA(str, buf); // std::strcpy(str, bufl; // Для MinGW strcpys(str, std::str1en(strl + 1, bufl; // Для vc++ delete [] buf; { 11 Преобразование строки в кодировку Windows1251 void convert to cp1251(char *str) char *buf; try { buf = new char[std::str1en(strl + 1]; catch (std:: bad  a110c енl return; OemТoCharA(str, buf); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  42  1612.10 // std::strcpy(str, bufl; // Для MinGW strcpys(str, std::str1en(strl + 1, bufl; // Для Vc++ delete [] buf; Как вы уже знаете, прежде чем идентиф икатор использовать, ero необходимо объявить в проrpамме. Ранее мы объявляпи функции перед определением функции main ( 1. В этом примере все функции вынесены в отдель ный файл, называемый модулем При использовании модулей определения функц ий раз мещают в файле с расширением срр, а все объявления выносят в в отдельный файл, имеющий расширение h. Причем названия Ф айлов должны совпадать. Содержимое файла converts.h приведено в листинrе 1.1 б. I .1IИСТIПП 1.16. Фnйл COlI\'el't. .11 #ifndef CONVERTS н #define CONVERTS н const short int PRINT ENDL = 1; const short int PRINTSPACE = 2; void prlllt cp866(const char *str, short int х=О); void convert to cp866(char *str); void convert to cp1251(char *str); # endif Ве е содержимое зarоловочноrо файла расположено внутри условия, которое проверяется перед ко мпиляцией. Условие выrлядит следующим образо м: #ifndef CONVERTS н // Инструкции # endif Это условие следует читать так Il если не существует макр оопределения CONVE RTS Н, то вставить инструкции в то место, rде подключается файл ll . Условие начинается с директивы #i fnde f и заканчивается директивой #е ndi f. Все это необходимо, чтобы объявления идентификаторов не вставляпись дважды. Иначе будут вставлены два одинаковых объявления, а это является ошибкой. Чтобы объявления не вставлялись дважды в первой инструкции внутри условия объявляется макроопределение CONVER TS н с помощью директивы #def lne Теперь повторная проверка условия вернет ложное значение. Файл converts.h содержит объявления двух констант (PRINTENDL и PRINTSPACE) и трех функций: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  43  1612.10 -+ pr ln t ер 866 (1  преобразует строку из кодировки Windows  125 1 в кодировку ср8бб и выводит ее в окно консоли. Исходная строка не изменяется; -+ со nver t to ер 8 66 (1  преобразует исходную строку из кодировки Windows  1251 в кодировку ср8бб; -+ со nver t to ер 1251 (1 преобразует исходную строку из кодировки ср8бб в кодировку Windows1251. Внутри функции pr ln t ер 8 66 (1 объявляется указатель buf , который может ссылаться на данные имеющие тип char . Указатели имеют такое же предназначение, что и переменные, НО вместо данных указ атели содержат адрес данных в па:мяти компьютера. Длина передаваемой в качестве перБоrо параметра строки зар анее неизвестна, поэтому па:мять выделяется динамически и указателю Ьи f присваивается адрес первоrо элемента символьноrо массива, размер KOToporo указан в квадратных скобках. Для получения длины строки используется функция s tr 1en (1. Эта функция возвращает длину без уч ета нулевоrо символа (который служит признаком конца строки), поэтому к длине строки прибавляется единица. Выдел ение динамической па:мяти может закончится неудачей, если размера доступной памяти не достаточно. Поэтому инструкция расположена внутри конструкции tr у. . . са t ch, которая позволяет перехватить и обработать исключение. Если внутри блока tr у возникнет исключение, то управление передается в блок cat ch, соответствYIOЩИЙ типу исключения. При нехватке памяш исключение имеет тип bada11oc. Этот тип указывается перед названием переменной (err) внутри круrлых СКО бок после ключевоrо слова са tch. Внутри блока са tc h можно произвести обработку исключения. В нашем случ ае просто производится выход из функции. Если исключение не возникло или произоШТI о исключение дрyrоrо типа, то инструкции внутри блока са tch не выполняются. После успешноrо выделения динамической кодировок с помощью функции CharToOemA (1 в кодировке Windows  1251, а во втором динамическую область памяти, которая была записана строка в кодировке ср8бб. Далее в зависимости от значения переменной х производится вывод строки В кодировке ср8бб в окно конс оли. Значение проверяется с помощью оператора swi tc h. Если значение переменной х равно О (case о) или переменная имеет значение отличное от 1 и 2 (блок def au1t), то производится вывод только строки. Если переменная име ет значение 1 (case 1), то после строки выводится символ перевода строки. Если памяти производится преобразование . В первом параметре передается строка параметр е пер ед ается ук аз а тель н а выделена ранее. В эту область будет Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 44  1612.10 переменная имеет значение 2 (case 2), то после строки выводится пробел. Обратите внимание на то, что в конце каждоrо блока расположен оператор Ь reak, который передает упр авление инструкции, расположенной после закрывающей фиryрной ско бки. При вызове функции значения О, 1 и 2 не несут никакой смысловой нarpузки. Поэтому значение О определено по умолчанию в объявлении функции и ero можно вообще не указывать при вызове. Значение 1 закреплено за константой PR INT  ENDL, а значение 2  за константой РЮ ЫТ S РАС Е Теперь при вызове функции вместо чисел можно использовать кон станты. Например, ВЫВОД строки и дальнейший перевод на новую строку выrлядит так: prl1lt ср8 66 (rrCTpOKa rr , PRINT  ENDL) ; Соrласитесь, это понятнее, чем: prl1lt ср8 66 (rrCTpOKa rr , 1); После выделения дина:мической па:мяти проrpаммист должен самостоятельно позаботиться о возвращении па:мяти операционной системе. Если этоrо не сделать и присвоить указ ателю друrой адрес, то область памяти будет потеряна. Несколько подобных про машек приведет к утечке памяти и один прекрасный момент свободная па:мять закончится. Восстановить память можно 6уд ет только после перезarрузки КО мпьютера. В ернутъ область па:мяти операционной системе из проrpаммы позволяет оператор delet е, после KOToporo передается указ атель на область. Если ранее выделялась па:мять для массива, то между оператором dele te и указ ателе м вставляются maдpaTHble скобки. После применения оператора de let е, использовать указ атель нельзя. Внутри функц ии с onver t t о ер 866 (1 также выделяется динамическая память, а зате м про изводится преобр азование кодировок с помощью функции С har То ОетА ( 1 . Далее с помощью функции st rc ру s (1 (для МinGW с помощью функции s tr ер у ( 1 ) производится копирование символов из дина:мической па:мяти в исходнJ'lO строку, а затем область возвращается операционной системе. Таким образом изменяется кодировка в исходной строке. Функция convert to ср12 51 (1 аналоrична функции convert to ср8 66 (1, но преобразование кодировки производится с помощью функции ОетТо Char А (1 . Теперь можно подключить эти файлы к проекту. Для создания файла converts.cpp в окне Обоз})I?'В;)ТI?'Jn. })I?'Шl?'ш.п"i щелкаем правой кнопкой мыши на пункте Ф;)iiлы ИfХО,ll;Ноrо :код;) и из KOHTeKcTHoro меню выбираем пункт Доб;)вить I Созд;)ть ')Ш"МI?'IП. В результате откроется окно Доб;)ВЛI?'НIII?' HOBoro ')ЛI?'I'o-II?'IП;). Выделяем пункт Ф;)iiл С++ (, срр), вводим название файла (" converts ") и нажимаем кнопку До6авптъ. В результате Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  45  1612.10 файл буд ет добавлен в папку проекта и ero название отобразится в окне 060ЗI'ваТJTh I'ШШПI, а сам файл будет открыт на отдельной вкладке. Вставляем в этот файл код из листинrа 1.15. Для создания файла converts.h в окне ОБОЗ})l?'ватl?'Jn. })I?'Шl?'шоп"i щелкаем правой кнопкой мыши на пункте Заrоловочныl?' фШ":'"ШЫ и из KOHTeKCTHoro меню выбираем пункт Добавить I Созда ть ')ЛII?'НТ. В результате откроется окно ДОQаВШ"IПII?' HOBoro ')Лl?'l'o-le'нта Выделяем пункт Заrоловочныii фm:"iл (.11), ВВОДИМ название файла (11 converts 11) и нажимаем кнопку Добавить. Вставляем в этот файл код из листинrа 1.16. Теперь, чтобы использовать эти функции, достаточно подключить файл converts.h в о сновной проrpамме. Пример использования функций приведен в листинrе 1.17. I .1IИСТIПП 1.17. Файл Iflап,.СИ' #include <iostream> #include rrconverts. h rr int main (1 prl1lt ср8 66 (rrДобро пожаловать,r, PRINT  SPACE) ; pr l1lt ср8 66 (rr B с++ I rr, PRINT  ENDL) ; char s [] = rrНa;:ю.Iите <Enter> для закрытия окна... rr; convert to cp866(s); std: : cout « 5; std::cin.get(); 11 Ождцаем нажатия <Enter> return о; Результат выполнения в окне консоли: Добро пожаловать в с++! Нажмите <Enter> для закрытия окна... Прu.мечанuе В V isua1 С ++ нельзя ис польз овать функцик р r ln t ер 8 6 6 (1 , если пр едварит елъно бы"", пр оизв едена IffiC тр о ЙЮl локали с пом ОЩblO функции s е t 10 с a1 е ( 1, так как пер ек о дир ов"" будет пр оизв едеlffi дваж ды. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  46  1612.10 Преждевреl\Iенное завершенпе выполненпя проrраммы в некоторых случаях мож ет возникнуть условие, при котором Д альнейшее выполнение проrpаммы лишено смысла, например, отсутствует свободная память при использовании динамической па:мяти. В этом случ ае имеет смысл вывести сообщение об ошибке и прервать выполнение проrpаммы досрочно. Для этоrо предназначена функция ех it (1. Прежде чем использовать функцию необходимо предварительно подключить файл cstd1ib (или std1ib. h в языке С). Прототип функции: # inc1ude <cstd1ik > void exit (int code); В качестве параметра функция принимает число, котор ое является статус ом завершения. Число О означает нормальное завершение проrpаммы, а любое дрyrое число  некорректное завершение. Эти числа передaIOТСЯ операционной системе. Вме сто чисел можно использовать макр оопределения Е XIT 5UC СЕ 55 (нормальное завершение) и EXIT FAILURE (аварийное завершение). Объявления макросов: # def ine EXIT 5UCCE55 О #define EXIT FAILURE 1 Помимо функц ии exi t (1 для аварийноrо завершения проrpаммы предназначена функция МО rt (1 . В этом случае завершение проrp аммы осуществляется операционной системой (выводится окно с сообщением "обнаружена ошибка. Приложение будет закрыто"). Прежде чем использовать функцию необходимо предварительно подключить файл cstd1ib (или std1ib. h в языке С). Прототип функции: #inc1ude <cstd1ik> void abort (void) ; В качестве примера произведем деление двух вещественных чисел, введенных пользователем, и выведем результат. При этом обработаем ошибки ввода и деление на нуль (листинr 1.18). Все сообщения об ошибках выведем на рус ском языке. .1IИСТIПП 1.18. ПреждевреreНlЮе зnвершение въпюлнения проrрn "'IЫ #include <iostream> #include <clocale> #inc1ude <cstd1ik> int main (1 douk1e х = О. О, У = О. о; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 47  1612.10 std: : setlocale (LC  ALL, rrRussian  Russia. 1251 rr) ; std: : cout « rr x ". , std: : cin » Х; std: : cout « rry std: : cin » У; if ('std: :cin.good(11 std::cout «std::endl « « std:: endl; ". , rr \ пОшиб ка пр и ввод е чисе л ! rr 11 Сбрасываем флar ошибки, иначе окно закроется std::cin.clear(); std: :cin.ignore (200, I\n l ) .get (); std::exit(l); 11 Завершаем выполнение проrраммы e1se if (у == 0.01 std:: cout « rrИа нуль делить нельзя! rr « std:: endl; std: :cin.ignore (200, I\n l ) .get (); std::exit(EXITFAILUREI; // Аналоrично std::exit(ll; std::cout « rr x I у = rr «х I у« std::endl; std: :cin.ignore (200, I\n l ) .get (); return о; { в этом примере вместо функции е xit (1 можно было воспользоваться инструкцией re turn, так как завершение проrpаммы выполняпось внутри функции main (1 Однако в больших проrpаммах основная часть кода расположена вне функции main () и в этом случае инструкцией r eturn для завершения всей проrpаммы уж е не обойтись. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  2  1712.10 Переменные  это участки па:мяти, используемые проrpаммой для хранения данных. Прежде чем использовать переменную, ее необходимо предварительно объявить rлобально (вне функций) или локально (внутри функции). В большинстве случаев объявление переменной является сразу и ее определением. lло6альные переменные видны внутри всех функций в файл е, а локальные переменные видны только внутри той функции, в которой они объявлены. Для объявления переменной используется следующи й формат [<Спецификатор>] [ <Модификатор>] <Тип> <П=ременнаяl>[=<Значениеl>] [, ..., <Переменная М> [=<Значение М>] ] ; IThIеНОВ:lнпе переl\Iенных Каждая переменная должна иметь уникальное имя, состоящее из латинских букв, цифр и :знака подчеркивания, причем и:мя переменной не может начинаться с цифры. При указ ании имени переменной важно уч итывать реrистр букв: х и х  разные переменные. В кач естве имени переменной нельзя использовать ключевые слова. Список ключевых слов приведен в табл. 2.1. Следует учитывать, что в некоторых ко мпиляторах MOryT быть определены дополнительные ключевые слова. Запоминать все ключевые слова нет необходимости, так как в редакторе эти слова подсвечивaIOТСЯ. Любая попытка использования ключевоrо слова вместо названия переменной приведет к ошибке при ко мпиляции. Помимо ключевых слов следует из6еrать совпадений со встроенными ид е нти Ф икатор ами. Правильные имена переменных х, у1, str пате, strName Неправильные имена переменных: 1 у, ИмяПе реме нно й. Последнее имя неправильное, так как в нем используются русски е буквы. Хотя на самом дел е такой вариант также будет работать, но лучше русские буквы все же не пр и менять. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  3  1712.10 Таблица 2.1. Клю,ееые слоеа языка с++ ает еlее auto enum Ьооl explicit break ехр ort case extem catch [аlее char f10at с!а" for const friend const cast goto с оntin ие if defa u1t in1in е delet е int do long dou Ые титЫе dynamic  сае! namespac е Тппы данных n"", this operator throw private true protected try public typ ed ef regist er typeid reint erpret  сае! typ enarne retum uшоn short unsigned signed usmg sizeof virt ua1 static void static сае! volati1e struct wchar t switch wlule template в языке С++ определены следующие элементарные типы данных: -+ bool  лоrический тип данных. Может содержать значения true (соответствует числу 1) ипи fa1se (соответствует числу О). При мер объявления переменной: bool is int; -+ char  код символа. Диапазон значений от  12 8 до 127. Пример объявления переменной: char ch; -+ wc har t  двухбайтовый символ Пример объявления переменной: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  4  1712.10 wchar t wch; -+ in t  целое число со :знаком. Диапазон значений зависит от разрядности операционной системы. В 1 ббитной операционной системе диапазон от  3 2 768 до 32 767. В 32битной операционной системе диапазон от 2 147 483 648 до 2 14 7 483 647. Пример объявления переменной: int Х; -+ f 10a t  веще ственное число. Пример объявления переменной : float У; -+ do ub le  вещественное число ДВОЙНОЙ ТОЧНОСТ1l. Пример объявления переменной: double z; Перед элементарным типом данных MoryT быть указаны следующие модификаторы или их комбинация: -+ signed  указывает, что символьный или целочисленный типы Moryт содержать отрицательные значения. Тип signe d с har соответствует типу char и может содержать значения от  12 8 до 127. Пример объявления переменной : signe d с har ch; Тип signe d int соответствует Т1Iпу int. Пример объявления переменной: signe d int х; -+ unsigned  указывает, что символьный или целочисленный Т1IПЫ не MOryT содержать отрицательные значения. Тип uns igne d char может содержать значения от О до 255. Пример объявления переменной: unsigned char ch; Диапазон значений ДЛЯ типа uns igne d in t зависит от разряди ости операционной системы. В 1 ббитной операционной системе диалазон от О до 65 535. В 32битной операционной системе диапазон от О до 4 294 967 295. Пример объявления переменной: unsigned int х; -+ shor t  может быть указ ан перед целочисленным типом. Диапазон значений у типов shor t int и s igne d s hor t int от  3 2 768 до 32 767. Пример объявления переменных: short int х; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  5  1712.10 signed short int У; Диапазон значений у типа unsigne d shor t in t от О до 65 535. Пример объявления переменной: unsigned short int Х; -+ 10 ng  может быть указан перед целочисленным типом и типом do uk1e. Диалазон значений у типов 10 ng int и s igned 10ng in t от  2 14 7 483 648 до 2 14 7 483 647. Пример объявления переменных: long int Х; signe d long int У; Диапазон значений у типа unsigne d 10ng in t от О до 4 294 967 295. Пример объявления переменной: unsigned long int Х; Ключевое слово long перед целым типом может быть указано дважды. значений у типов 10 ng 10 ng int и s igne d 10 ng 10 ng 9 223 372 036 854 775 808 до 9 223 372 036 854 775 807. объявления переменных: long long int Х; signed long long int у; Диапазон значений у шпа unsigne d long long in t может быть от о ДО 18 446 744 073 709 551 615. Пример объявления переменной: Диапазон int ОТ Пример unsigned long long int Х; Ключевое слово 10 ng можно указ ать также перед типом double. Пример объявления переменной: long double z; При использовании модификаторов тип in t подразумевается по умолчанию, поэтому тип int можно не указывать. Пример объявления переменных: short Х' // Эквивалентно: short int Х' , , 10ng у; // Эквивалентно: 10ng int у; signed "' // Эквивалентно: signed int "' , , unsigned k' // Эквивалентно: unsigned int k' , , в одной инструкции можно объявить сразу несколько переменных, указав из через запятую после названия типа данных: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  б  1712.10 int х, у, z; Если переменная может изменять СБое значение извне, то перед модификатором указыв ается ключевое слово vo la tile. Это ключевое слово предоmращает проведение опти:мизации проrpаммы, при котором предполarается, что значение переменной может быть изменено только в проrpамме. После объявления переменной ПОД нее выделяется определенная па:мять, размер которой зависит от используемоrо типа данных и разрядности операционной системы. Например, тип int в 1 ббитной системе занимает 1 б бит, в 32битной  32 бита, а в б4 битной  б4 бита. Чтобы сделать код машинонезависимым следует определять размер типа с помощью оператора siz ео f. Оператор имеет два формата: <Размер> <Размер> Пример: sizeof <Переменная >; sizeof «Тип данных »; int Х; std::cout «sizeof х «std::endl; std::cout «sizeof (х) «std::endl; std::cout «sizeof (bool) «std::endl; Обратите внимание на то, что тип данных обязательно должен быть указ ан внутри круr-л ых скобок, в то вре:мя как название переменной можно указать как внутри скобок, так б ез них. в каче стве примера использования оператора si ze of выведем текущий размер всех типов данных (листинr 2.1). l-тшет IПП 2.1. Не поль ЗОВ;[I mre опер ;[ITop;[l sizeof # include <iostream > using narrespace std; int main (1 cout « rЪооl cout « rrchar rr «sizeof (bool) «endl; rr «sizeof (char) «endl; cout « rrwchar t = rr «sizeof (wchar t) «endl; cout « rrint = rr «sizeof (int) «endl; cout « rrshort int = rr «sizeof (short int) «endl; cout « rrl ong int = rr «sizeof (long int) «endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  7  1712.10 cout « rrl ong long int = rr «sizeof (long long int) «endl; cout « rrfloat = rr «sizeof (float) «endl; cout « rrdouble = rr «sizeof (double) «endl; cout « rrl ong double = rr «sizeof (long double) «endl; cin.get(); return о; Результат выполнения проrpаммы в Visual С++ 2010 Express в 32битной операционной системе Windows ХР (размер указан в байтах): boo1 = 1 char = 1 wchar t = 2 int = 4 short int = 2 10ng int = 4 10ng 10ng int = 8 f10at = 4 douk1e = 8 10ng douk1e = 8 1 Iнпцпалп зацпя пе реl\Iенных При объявлении переменной ей можно сразу присвоить начальное значение, указав ero по сл е о п ер атор а =. Эта о п ер ац ия н аз ыв ается инициализацией п ер е ме н н ых. Пр и мер указ ания значения: int х, у = 10, z = 30, k; Пере менная становится видимой сразу после объявления, объявлением (после запятой) эту переменную уже инициализации дрyrих переменных: int х = 5, У = 10, z = х + У; 11 z равно 15 При инициализации допустимо указывать значение не только после оператора =, но и внутри круrлых скобок после имени переменной : int х (101; / / х равно 10 Инициализация rлоб альных (объявленных вне функций) переменных производится только один раз. Локальные (объявленные внутри функций) переменные инициализируются при каждом вызове функции, а статические (сохраняющие свое Листинrи на странице http://unicros s.narod.ru/cpp/ поэтому на одной строке с можно использовать для 
@ Прохоре'ю/С НА, 2010 '.  8  1712.10 значение между вызовами) локальные переменные  ОДИН раз при первом вызове функции. Если при объявлении переменной значение не было присвоено, то: -+ rло6альные переменные автоматически ПОЛУЧaIOТ значение о; -+ локальным переменным значение не присваивается. Переменная будет содержать произвольное значение, так называемый "мусор"; -+ статические локальные переменные автоматически получmoт значение о. Присвоить значение переменной можно уже после объявления, указав ero после оператора =. Эта операция называется прuсваuвшшем. Пример присваивания: int Х; Х = 10; Пере менной, имеюще й тип Ь 00 1, можно присвоить значения tr ие или f als е. Значение tr ие соотвеТС1Бует числу 1, а значение f als е  числу о. Числовые значения можно указ ать вместо значений t rue и false. Пример: boo1 а, Ь, с, d' , а true; Ь fal.se; с l' , d О. , 11 Эквивалентно: с 11 Эквивалентно: d true; false; Пере менной, имеющей тип с har, можно присвоить числовое значение (код символа) или указать символ внутри апостро фов. Обратите внимание на то, что использовать кавычЮI нельзя, так как в этом случае вместо одноrо символа будет два: собственно сам символ ппюс нулевой символ. Пример: char chl, ch2; ch1 119; / / Буква w ch2 = I w 1; 11 Буква w Внутри апостроф ов можно указать специальные символы. Специальные символы  это ко мбинации знаков, обозначaIOЩИХ служ ебные или непечатаемые символы. Перечислим специальные символы, доступные в С++: -+ \0  нулевой символ; -+ \ n  перевод строки; -+ \ r  возврат каретки; -+ \ t  rоризонтальная табуляция; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  9  1712.10 -+ \ v  вертикальная табуляция; -+ \ а  звуковой сиrнал; -+ \ ь  возврат на один символ; -+ \ f  перевод формата; -+ \'  апостроф; -+ \ rr  кавычка; -+ \?  знак вопроса; -+ \ \  обратная косая черта; -+ \ N  восьмеричное значение М; -+ \ хЫ  шестнадцатеричное значение N Пример указания восьмеричноrо и шестнадцатеричноrо значений: char chl, ch2; chl = 1\1671; 11 Буква w (восьмеричное значение) ch2 = '\х77 1 ; 11 Буква w (шестнадцатеричное значение) Пере менной, имеющей тип wchar t, значение присваивается также, как и переменной, имеющей тип char , только перед отрывающим апострофом указывается буква L: wchar t ch; ch = L I W I ; Целочи сленное значение задается в десятичной, восьмеричной или ше стнадцатричной форме. В осьмеричные числа начинаются с нуля и содержат цифры от О до 7. Шестнадцатеричные числа начинаются с комбинации символов Ох (или ох) и Moryт содержать числа от О до 9 и букв ы от А до F (реrистр букв не имеет значения). Восьмеричные и ше стнадцатричные значения прео6разJ'lOТСЯ в десятичное значение. Пример: 11 Д=сятичное значение 11 Восьмеричное значение z = Ох77; 11 Шестнадцатеричное значение Присвоить переменной нулевое значение можно указав круrлые скобки после названия типа: int х = int(); 11 х равно О int х, у, х = 119; У = 0167; "' , Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  10  1712.10 По умолчанию целочисленные константы имеют тип signed int. Если необходимо изменить тип на дрyrой, то после числа указ ываются следующие буквы: -+ L (или 1)  тип 10 ng int. Пример указания значения: 10L; -+ u (или и)  тип unsigned in t. Пример указ ания значения: 10 о; -+ если буквы u и L указ аны одновременно, то тип будет unsigned 10 ng int. Пример указ ания значения: 10 UL. Вещественное число может содержать точку и (или) экспоненту, начинающую ся с буквы Е (реrистр не имеет значения): float х, У; double z, k; х = 20.0; У = 12 .lе5; z = . 123; k=47.E5; Присвоить переменной нулевое значение можно указав круrлые скобки после названия типа: f10at х = f1oat(l; douk1e у = douk1e (1 ; По умолчанию вещественные константы имеют тип doub le. Если необходимо изменить тип на дрyrой, то после числа указ ываются следующие буквы: -+ F (или f)  тип f 10a t. Пример указания значения: 12. 3 f; -+ u (или и)  тип 10ng douk1e. Значение должно содержать точку и (или) экспоненту, иначе тип буд ет 10ng int. Пример указания значения: 12. 3L. Оператор typt'llef Оператор type de f позволяет создать псевдоним для существующеrо типа данных. В дальнейшем псевдоним можно указывать при объявлении переменной. Оператор имеет следующи й формат t уре de f <Суще с ТВyIOЩий тип> <1Ic е вд о ним> ; В качестве примера создадим псевдоним ДЛЯ типа 10 ng int: typedef long int lint; lint х = 5, У = 10; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 11  1712.10 После создания псевдонима, ero и:мя можно использовать при создании дрyrоrо псевдонима: typedef long int lint; t уре de f lint newin t ; newint х = 5, У = 10; Псевдонимы предназначены для создания машинонезависимых проrрамм. При переносе проrpаммы на дрyrой ко мпьютер достаточно будет изменить одну строку. Подо бный подход часто используется в стандарной библиотеке. Например, прототип функции str 1e n ( 1 , позволяющей получить длину строки, выrлядит так size t strlen(const char *Str); В этом прототипе тип данных 51 ze t, возвращаемый функцией st r len () , является псевдонимом для шпа uns igne d int, а не новым ТИПОМ. Дпнаl\lIIческое определенпе ТIша данных Для определения типа данных при выполнении проrpаммы предназначен оператор type id. Прежд е чем использовать оператор, необходимо подключить файл typ einfo: # include <typeinfo> Оператор имеет следующий формат: <Экземпляр класса type lnfo> = tуреld«Данные»; В кач естве значения оператор type id возвращает экземпляр класс а t уре ln fo Этот экз емпляр можно сравнить с дрyrим экземпляром Toro же клас са, используя операторы == (р авно) и ,= (не равно). Получить название типа данных позволяет метод name (1 . При мер использования оператора t уре id приведен в листинrе 2.2. I-тшст IПП 2.2. Динt1r".mчeс кое о:np еделеНlt?! ТИШI дtlи:ны:{ #include <iostream> #include <typeinfo> int main (1 long int х = 5; int у = 12; douk1e z = 3.14; std::cout «typeid(xl .name(1 «std::end1; std::cout «typeid(yl .name(1 «std::end1; / / 10ng // int Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  12  1712.10 std::cout «typeid(zl .name(1 «std::end1; std::cout «typeid(12.1fl .name(1 «std::end1; if (typeid(xl == typeid(yll std: : cout « rr==rr « std:: endl; / / douk1e // float else std::cout « rr!=rr «std::endl; 11 != if (typeid (хl ,= typeid (yll std::cout « rr!=rr «std::endl; 11 != e1se { std: : cout « rr==rr « std:: endl; std: : cin. get (1 ; return о; Константы Константы  это переменные, значения в которых не ДОЛЖНЫ изменяться во вре:мя работы проrpаммы. В боле е широком смысле под константой понимают любое значение, которое нельзя изменить, например, 10, 12 .5, I W I , rr str ing rr. При объявлении константы перед типом данных указывается ключевое слово со nst: const int Х = 5; Обратите внимание на то, что в названии константы принято использовать буквы только в верхнем реrистре. Если название кон станты состоит из нескольких слов, то между словами указывается символ подчеркивания. Это позволяет отличить внутри проrpаммы константу от обычной переменной. После объявления константы, ее можно использовать в выражениях: const int Х = 5; int У; у = х + 20; Присвоить значение константе можно только при объявлении. Любая попытка изменения значения в проrpамме приведет к ошибке при ко мпиляции: "error С3892: невозможно присваивать значения переменной, которая объявлена как константа " . Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  13  1712.10 Создать константу можно также с помощью директивы #def ine. Значение, указанное в этой директиве, подставляется в выражение до компиляции. Название, указ анное в директиве #def ine, принято называть макроопределением или макрОСОМ. Директива имеет следующий фор мат #define <Название макроса> <Значение> П ример использования директивы #def ine приведен в листинrе 2.3. I .1IИСТIПП 2.3. Не IЮЛЪ ЗОВn ине директив ы #,!еfп,е # include <iostream > #define Х 5 int main (1 int У; у = х + 20; std::cout «у« std::endl; std: : cin. get (1 ; return о; Обратите внимание на то, что оператор = не используется и в конце инструкции точка с запятой не указывается. Если точку с запятой указ ать, то значение вместе с ней будет вставлено в выражение. Например, если определить макр ос так: #define Х 5; то после подстановки значения, инструкция у = х + 20; будет выrлядеть следующим образом: у = 5; + 20; Точка с запятой после цифры 5 является концом инструкции, поэтому переменной у будет присвоено значение 5, а не 25. Подобная ситуация приводит к ошибкам, которые трудно найти, так как в этом случае инструкция + 2 о; не возбуждает ошибку при компиляции. В качестве значения макроса можно указ ать целое выражение, например: #define Х 5 + 5 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  14  1712.10 Это зн ачение также может привести к недоразумениям. Никакоrо вычисления выражения не про изводится. В се выражение целико м подставляется вместо названия макроса. Если инструкция выrлядит так: у = х * 20; то после подстановки значения, инструкция примет следJ'lOЩИЙ вид: у = 5 + 5 * 20; Приоритет оператора умно жения выше приоритета оператора сложения, поэтому число 5 буд ет умножено на 2 О, а затем к результату прибавлено число 5. Таким образом, результат буд ет 105, а не 2 О О, как это было бы при использовании контанты : const int Х = 5 + 5; int У; у = х * 20; // 200 В качестве значения макроса можно указ ать строку в кавычках: # def ine Е RR rr С 00 бще ние о б ошиб ке rr При указании длинной строки следует учитывать, что определение макро са должно быть расположено на ОДНОЙ строке. Если нужно разместить значение на нескольких строках, то в конце строки необходимо добавить обратную косую черту. После ко сой черты не ДОЛЖНО быть никаких символов, в том числе и комментариев. Пример: # def ine ERR rrСообщение об ошибке \ на нескольких \ с тро ках rr В языке С++ существуют встроенные макросы (до и после названия два символа подчеркивания): -+ FILE  имя файла; -+ LINE  номер текущей строки; -+ DATE  дата компиляции файла; -+ TIME  время компиляции файла. ПОМИМО этих макросов суще ствует множество дрyrих, объявленных в различных зarоловочных файлах. Эти макросы мы рассмотрим в соответствующих разделах книrи. Выведем текущи е значения встроенных макросов (листинr 2.4). Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  15  1712.10 I .1IИСТIПП 2.4. Встроенные т крос ы #include <iostream> int main (1 std: : cout « std: : cout « std: : cout « ЫЫЕ FILE DATE « std:: endl; « std:: endl; « std:: endl; « std:: endl; std::cout« TIME std: : cin. get (1 ; return о; Примерный результат выполнения: 4 c:\book\test\test\main.cpp Aug 30 2010 15:58:35 СпецпфпюlТОРЫ храненпя Перед модификатором и типом MOryт быть указаны следующи е спецификаторы: -+ аи to  так как локальные переменные по умолчанию являются автоматическими, ключевое слово а ut о в С++ практически не используется. Поддерживается только в целях совместимости с языком С. в VC++ 2010 ключевое слово а uto по умолчанию имеет несколько иной СМЫСЛ, который определен в новом стандарте С++Ох. В этом стандарте ключевое слово а ut о можно использовать вместо типа данных в объявлении переменной. Тип такой переменной определяется автоматически по значеншо, указанному при инициализации. Пример : auto х = 10; std: : cout « typeid (х 1 . name (1 « std:: end1; / / int аи to у = 10. 2 f ; std: : cout « typeid (уl . name (1 « std:: end1; / / f10at аи to z = 10. 2; std: : cout « typeid (" 1 . name (1 « std:: end1; / / douk1e Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  16  1712.10 -+ re gist er  является подсказко й компилятору, что переменная будет использовать ся интенсивно. Для ускорения доступа, значение такой переменной сохраняется в реrистрах процессора. Компилятор может проиrнорироватъ это объявление и сохранить значение в памЯТ1l. Ключевое слово может использоваться при объявлении переменной внутри блока или в параметрах функции. К rлобальным переменным не при меняется. Пример объявления переменной: register int i; -+ ех te rn  сообщает компилятору, что переменная определена в друтом месте, например, в дрyrом файле. Ключевое слово лишь объявляет переменную, а не определяет ее. Таки м образом, память под переменную повторно не выделяется. Если при объявлении ПРОИЗВОДИТСЯ инициализация переменной, ТО объявление становится определением переменной. В каче стве примера объявим переменную внутри функции main (1 , а определение переменной разместим после функции: #incl ude <io st re am> int main () extern int i; 11 Определение в друrом месте std::cout « i « std: :end1; // 10 std: :cin.get(l; return о; int i = 10; 11 Определение переменной i -+ st at ic  если ключевое слово указано перед локальной переменной, ТО значение буд ет сохраняться между вызовами функции. Инициализация статических локальных переменных производится только при первом вызове функции. При последJ'lOЩИХ вызовах используется сохраненное ранее значение. Созд адим функц шо со статической переменной. Внутри функции увеличим значение переменной на единицу, а зате м выведем значение в окно консоли. Д але е вызовем эту функцию несколько раз: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  17  1712.10 #incl ude <io st re am> void func () ; int main () func (1 ; func (1 ; func (1 ; { / / 1 // 2 // 3 std: :cin.get(l; return о; void func (1 static int х = о; 11 Статическая переменная ++Х; 11 Увеличиваем значение на 1 std::cout « х « std: :endl; При кажд ом вызове функции func (1 зн ачение статической переменной х будет увеличивать ся на единицу. Если убрать ключевое слово sta tic, то при каждом вызове будет ВЫВОДИТЬСЯ число 1, так как локальные переменные инициалИЗИРJ'lOТСЯ при входе в функцию и уничтожаются при выходе из нее. Если ключ евое слово s tat ic указан о перед rло6альной переменной, ТО ее значение буд ет видимо только в пределах файла. Вместо статических rлобальных переменных лучше использовать неименованные пространства имен.   ОолаСТII ВIIДIII\ЮСТII переменных Прежде чем использовать переменную, ее необходимо предварительно объявить. До объявления переменной, она не видна в проrpамме. Объявить переменную можно rлобально (вне функций) или локально (внутри функции или блока). тло6алыiеe перемеliliые  это переменные, объявленные в проrpамме вне функций. lлобальные переменные видны в любой части проrpаммы, включая функции. Инициализация таких переменных про изводится только один раз. Если при объявлении Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  18  1712.10 переменной не было присвоено начальное значение, то ПРОИЗВОДИТСЯ автоматическая инициализация нулевым значением. Локальные переменные  это переменные, которые объявлены внутри функции или блока (области, оrpаниченной Ф иryрными скобками). Локальные переменные видны только внутри функции или блока. Инициализация таких переменных производится при каждом вызове функции или входе в блок. После выхода из функции или блока локальная переменная уничтожается. Если при объявлении переменной не было присвоено начальное значение, то переменная 6уд ет содержать произвольное значение, так называемый "мусор". Исключением являются статические локальные переменные, которым автоматически присваивается нулевое значение и которые сохр аня::ют значение при выходе из функции. Если и:мя локальной переменной совпадает с именем rло6альной переменной, ТО все операции внутри функции осуще ствля::ются с локальной переменной, а значение rло6альной не изменяется. Чтобы в этом случае получить доступ к rло6альной переменной, необходимо перед названием переменной указать два двоеточия, например, : : х. Область видимости rлобальных и локальных переменных показ ана в листинrе 2. s. I .1IИСТIПП 2.5. Об:rmст ъ видиюсти rrepеreииых #include <iostream> int х = 10; 11 rлобальная переменная void func (1 ; int main (1 func (1; 11 Переменные х И у из фуНl'ЩИИ func () здесь не видны 11 Вывод значения rлобальной переменной х std: : cout « х « std:: end1; / / 10 // Блок int z = 30; std::cout « z «std::end1; //30 { 11 Переменная z здесь уже не видна!!! for (int i=O; i<10; ++i) Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  19  1712.10 std::cout «i« std::endl; { 11 Переменная i здесь уже не видна! I I std: : cin. get (1 ; return о; { void func (1 11 lleременная z здесь не видна int х = 5, У = 20; 11 Локальные переменные 11 ВЫВОД значения локальной переменной х std: : cout « х « std:: endl; 11 5 11 ВыВОД значения rлобальной переменной х std: : cout « :: х « std:: end1; / / 10 Очень важно учитывать, что переменная, объявленная внутри блока, видна только в пределах блока (внутри фиrурных скобок). Налример, присвоим значение переменной в зависимосТ1l ОТ HeKOToporo условия: 11 Reправильно!!! if (х == 101 { / / Kaкoe то УСJЮвие int У; у 5; else int У; у = 25; { 11 Переменная у здесь не определена! ! ! В этом примере переменная у видна только внутри блока. По сле условноrо оператора if переменной не суще ствует. Чтобы переменная была видна внутри блока и после выхода из Hero, необходимо поместить объявление переменной перед блоком: / / Правильно int У; if (х == 101 { / / Kaкoe то УСJЮвие у = 5; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  20  1712.10 else у = 25; Если обращение к переменной внутри функции или блока производится до объявления одноименной локальной переменной, ТО ДО объявления будет использоваться rлобальная переменная, а после объявления  локальная переменная (листинr 2. б). Если rлобальной переменной с таким названием не суще ствует, то будет ошибка при компиляции. .1IИСТIПП 2.6. Обрnш;ение к rrepе"НlЮЙ l1fJ объявления ви:при ф)...к.ЦlШ #include <iostream> int х = 10; 11 rлобальная переменная int main (1 11 ВыВОДИТСЯ значение rлобальной переменной std: : cout « х « std:: end1; / / 10 int х = 5; 11 Локальная переменная 11 ВЫВОДИТСЯ значение локальной переменной std: : cout « х « std:: endl; 11 5 std: : cin. get (1 ; return о; Пространства III\IeH Пространства имен предназначены для предотвращения конфликтов идентификаторов внутри проrpаммы. Например, в вашей проrpамме объявлена функция с названием sum ( 1. В один прекрасный момент вам понадобились возможности библиотеки CTopoHHero разработчика, а в этой библиотеке также объявлена функция с названием sum ( 1. При подключении библиотеки произойдет кон фликт имен. Чем меньше идентификатор ов в rлобальной области видимости, тем меньше конфликтов будет в проrpамме. Подо бные конфликты возникали и при использовании стандарной библиотеки. Поэтому идентификаторы стандартной библиотеки С++ раз мещаются в пространстве имен st d. Чтобы получить доступ к этим идентификаторам необходимо указ ать название Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  21  1712.10 пространства имен перед иденти фикатором. Между названием пространства имен и идентификатор ом указывается оператор : : . Пример : std:: cout « rrTeKcT, ВЫВОДИМЫЙ В ОКНО :консоли,r; Следует уч итывать, что зarоловочные файлы из стандартиой библиотеки, имеющие расширение h, попрежнему помещают все идентификаторы в rлобальное пространство имен. Для объявления пространства имен предназначено ключевое слово names расе. Формат объявления пространсmа имен: namespace <Название пространства имен> { 11 Объявления идентификаторов Обратите внимание на то, что пространство имен должно быть объявлено в rло бальной области видимости. Пример объявления пространства имен NS и переменной х внутри: namespace м:::; { int х = 10; Для доступа к переменной х из проrpаммы необходимо перед названием переменной указ ать название пространства имен и оператор : : . Пример: std: : cout « NS:: х « std:: endl; Допускается объявление одноrо пространства имен несколько раз, а также вложение одноrо пространства имен в дрyrое. Пример : namespace м:::; { namespace NS2 { int у = 30; Если необходимо получить доступ к идентификаторам, объявленным во вложенном пространсmе имен, ТО перед названием идентификатора перечисля::ются названия нескольких пространсТБ имен: std::cout «NS::NS2::y «std::endl; Чтобы получить доступ к идентификаторам, объявленным в rлобальном пространстве имен, то перед идентификатором указывается только оператор : : . Пример: std::cout « ::z «std::endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  22  1712.10 с помощью ключевоrо слова using можно импортировать все или только определенные идентификаторы из пространства имен в rлобальную или локальную область видимости. Импорт всех идентификаторов вblrлядит так: using namespace <Название пространства имен>; При импортировании отдельных идентификаторов используется следующий формат using <Название пространства имен>::<Идентификатор>; П ример использования пространств имен приведен в листинrе 2.7. I .1IИСТIПП 2.7. Про" тр nH" TBn НI>reH # include <iostream > namespace м:::; { int х = 10; void pr int (1 1* Перед х указывать название пространства имен * не нужно, так как х нахОдИТСЯ в той же области ВИДИМОСТИ * */ std:: cout « х « std:: endl; namespace м:::; { 11 Пространство объявлено дважды int у = 20; 11 Бложенное пространство имен namespace NS2 { int z = 30; int main (1 std::cout «NS::x «std::end1; // 10 NS : : pr int (1; / / 10 11 Доступ к идентификаторам вложенноrо пространства имен std: : cout « IIS:: NS2: : z « std:: end1; / / 30 11 Импорт только дцентификатора у Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  23  1712.10 using иs:: У; std::cout «у« std::end1; //20 11 Импорт всех дцентификаторов using narrespace NS; std: : cout « х « std:: end1; / / 10 pr int (1; / / 10 std: : cin. get (1 ; return о; { в языке С++ суще ствуют такж е неименованные пространства имен. пд енти фикаторы, объявленные в таком пространстве имен, видны только в пределах файла. Формат объявления неименованноrо пространства имен: narrespace 11 Объявления идентификаторов Обраще ни е к идентификаторам неименованноrо пространства имен осуществляется также как к rло бальным идентификаторам. Пример использования неименованноrо пространства имен приведен в листинrе 2.8. I-тшст IПП' 2.8. НеmrleНОВtlИ:ньre :прострn HCTB;[I IOrreH # include <iostream > 11 Неименованное пространство имен 11 Область ВИДИМОСТИ оrраничена файлом narrespace { int х = 10; int main (1 std::cout «х «std::end1; // 10 std: : cin. get (1 ; return о; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  24  1712.10 l\IаССIIВЫ Массив  это нумерованный набор переменных одноrо Т1Iпа. Переменная в массиве называется элементом, а ее позиция в массиве задается индексом. Все элементы массива рас п ол araIOTC я в с ме ж н ых яч е йках п а:мяти. Напр и мер, е ел и о бъявл е н мае с ив из тр ех элементов, имеющих тип 10 ng in t (занимает 4 байта), то адрес первоrо элемента массива (в 32битной операционной системе) будет ОхО041А040, BToporo  Ох 00 41АО 4 4, а тpenero  О хО 041А04 8. Объем памяти (в байтах), занимаемый мае с ив о М, о пр ед еляется так: <Объем памяти> = sizeof «Тип» * <Количество элементов> Объявление мас сива выrлядит следующи м образо м: <Тип> <Переменная>[<Количество элементов>]; Пример объявления массива из трех элементов, имеющих тип 10 ng int: 10ng ап[3]; При объявлении элементам массива можно присвоить начальные значения. Для этоrо после объявления указывается оператор =, а далее значения через запятJ'lO внутри фиryрных скобок После закрывающей фиryp ной скобки обязательно указывается точка с запятой. Пример инициализации массива: 10ng ап [3] = {10, 20, 30{; КоличеС1БО значений внутри фиrурных скобок может быть меньше количеС1Ба элементов массива. В этом случае значения присваивaIOТСЯ соответствJ'lOЩИМ элементам с начала массива. Пример: 10ng ап[3] = {10, 20{; В этом примере первому элементу массива присваивается значение 10, второму  значение 2 О, а третьему элементу будет присвоено значение о. Есл и пр и о бъявл е н ии мас с ив а указ ыв aIOтся нач аль н ы е з н ач е н ия, элементов внутри maдpaTHblX скобок можно не указ ывать. соответствовать количеству значений внутри фиryp ных скоб ок. Пример: 10ng ап[] = {10, 20, 30{; Если при объявлении массива начальные значения не указ аны, то: -+ элементам rлобальных мас сивов автоматически присваивается значение о; -+ элементы локальных массивов будут сод ер жать произвольные значения, так то количество Размер будет называемый "мусор" Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  25  1712.10 06раще ни е к элементам мае сива осуще ствляется с ПОМОЩЬЮ maдpaTHblX СКО бок, В которых указывается индекс элемента. 06раште внимание на то, что нумерация элементов массива начинается с О, а не с 1, поэтому первый элемент имеет индекс о. С помощью индексов можно присвоить начальные значения элементам массива уже после о бъявл е н ия: 10ng ап[3]; arr [О] 10; 11 ПерВЫЙ элемент имеет индекс О!!! arr [1] 20; 11 Второй элемент arr[2] зо; 11 третий элемент Следует учитывать, что проверка выхода указанноrо индекса за пределы диапазона на этапе компиляции не производится. Таким образом, можно перезаписать значение в смежной ячейке па:мяти и тем с амым нарушить работоспособность проrpаммы или даже повредить операционную систему. Помните, что контроль корректности индекса входит в обязанности проrpам:миста. После определения массива выделяется необходимый размер па:мяти, а в переменной сохраняется адре с первоrо элемента массива. При указании индекс а внутри maдpaTHblx ско бок производится вычисление адрес а соотвеТСТВJ'lOщеrо элемента массива. Зная адрес элемента массива можно получить значение или перезаписать ero. Иными словами, с элементами массива можно производить такие же операции, как и с обычными переменными. Пример: 10ng ап[3] = {10, 20, 30{; long х = о; х = ап[1] + 12; arr[2] = х  arr[2]; std: : cout « х « std:: end1; / / 32 std::cout «arr[2] «std::end1; //2 Массивы в языке С++ Moryт быть мноrомерными. Объявление MHoroMepHoro массива имеет следующий фор мат <Тип> <Переменная>[<Количество элементовl>]...[<Количество элементов М>]; На практике наиболее часто использJ'loтся двух мерные массивы, позволяющие хранить значения ячеек таблицы, содержаще й определенное количество строк и столбцов. Объявление двухмерноrо массива выrлядит так: <Тип> <Переменная>[<Количество строк>] [<Количество столбцов>]; Пример объявления двухмерноrо массива, содержащеrо две строки и четыре столбца: int arr[2][4]; 11 Две строки из 4x элементов каждая Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  26  1712.10 Вс е элементы двухмерноrо массива располarаются в памяти друr за друrом. Вначале элементы первой строки, затем второй и т. д. При инициализации двухмерноrо массива элементы указываются внутри Ф иryрных ско бок через залятую. Пример: int ап[2] [4] = 1, 2, 3, 4, 5, 6, 7, 8 {; Чтобы сделать процесс инициализации нarлядным мы расположили элементы на отдельных строках. Количество элементов на строке совпадает с количеством столбцов в массиве. Если элементы одной строки разместить внутри фиrурных ско бок, то процесс станет еще нarляднее: int arr[2][4] = { {1, 2, 3, 4}, {5, 6, 7, 8 { {; Если при объявлении ПРОИЗВОДИТСЯ инициализация, ТО количество строк можно не указыв ать, оно будет определено автоматически: int ап[][4] = { {1, 2, 3, 4}, {5, 6, 7, 8 { {; Получить или задать значение элемента можно указав два индекс а (не забывайте, что нуме рация нач и н ается с нуля): std::cout «arr[O][O] «std::end1; // 1 std::cout «arr[l][O] «std::end1; //5 std: : cout « ан[ 1] [3] « std:: end1; / / 8 СТрОКII Строка является массивом символов, последний элемент KOToporo содержит нулевой символ (\ О). Обратите внимание на то, что нулевой символ (нулевой байт) не имеет никакоrо отношения к числу о. Коды ЭТИХ символов разные. Такие строки достались в " н аследство 11 ОТ языка С, поэтому их часто назЫВaIOт Сстроками. В языке С++ помимо CCтpOK можно также использовать экземпляры класса str ing. Класс string мы рассмотрим HeMHoro позже. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  27  1712.10 Объявляется CCтpOKa также как и массив элементов: char str [7]; При инициализации можно перечислить символы внутри фиrурных скобок: char str[7] = {ISI, It l , Ir l , 'i ' , In l , Igl, I\OI}; или указ ать строку внутри ДВОЙНЫХ кавычек: char str [7] = rrStr ingrr; При использовании ДВОЙНЫХ кавычек следует уч итывать, что длина строки на один символ больше, так как в конец будет автоматически вставлен нулевой символ. Если это не предусмотреть и объявить мае сив из шести элементов, вместо семи, то при ко мпиляции будет выведено сообщение об ошибке. Если размер массива при объявлении не указать, то он буд ет определен автоматически в соответствии с ДЛИНОЙ строки: char str [] = rrStr ingrr; Обратите внимание на то, что присваивать строку в ДВОЙНЫХ кавычках можно только при инициализации. Попытка присвоить строку позже приведет к ошибке: char str[7]; str = rrStr ingrr; 11 Ошибка! ! ! Внутри строки в двойных кавычках можно указ ыв ать специальные символы (например, \n, \r И др.), которые мы уже рассматривали в разделе "Инициализация переменных". Если внутри строки встречается кавычка, то ее нео6ходи МО экранировать с помощью обратноrо слэша: char str [] = rrrруппа \ rrКино\ rr\ n rr ; Объявить массив строк можно следующи м образом: char str [] [2 О] = {rrStr ingl rr, rrStr ing2 rr, rrStr ing3 rr} ; std::cout «str[O] «std::end1; // String1 std::cout «str[l] «std::end1; // String2 std::cout «str[2] «std::end1; // String3 1> 'ка з ;пелп Указатель  это переменная, которая предназначена для хранения адреса дрyrо й переменной. В языке С++ указатели часто используются в следующих случаях: -+ для управления динамиче ской па:мятью; -+ чтобы иметь возможность изменить значение переменной внутри функции; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  28  1712.10 -+ для э фф ективной работы с массивами и др. Объявление указ ателя имеет следующий фор мат <Тип> * <П=ременная>; Пр и мер о бъявл е ния указ ателя н а тип in t : int *р; Очень часто символ * указывается после типа, а не перед именем переменной: int* р; С точки зрения компилятора эти два объявления ничем не ОТЛИЧaIOТСЯ. Однако следует уч итывать, что при объявлении нескольких переменных в ОДНОЙ инструкции, символ * ОТНОСИТСЯ К переменной, перед которой он указан, а не к шпу данных. Например, следующая инструкция объявляет указатель и переменную, а не два указ ателя: int* р, Х; 11 Переменная х указателем не является!!! Поэтому более лоrично указывать символ * перед именем переменной : int *р, Х; Чтобы указателю присвоить адрес переменной, необходимо при присваивании значения перед названием переменной указать оператор &. Типы данных переменной и указателя должны совпадать. Это нужно, чтобы при адресной ариф метике был известен размер данных. Пример присвоения адреса: int *р, х = 10; Р = &Х; Чтобы получить или изменить значение, расположенное по адре су на который ссылается указатель, необходимо выполнить операцию разыменования указателя. Для этоrо перед названием переменной указыв ается оператор * . Пример: std::cout «*р «std::end1; // 10 *р = *р + 20; std::cout «*р «std::end1; //30 О сновные операции с указателями показаны в листинrе 2.9. l-тшстIПП 2.9. Укnзnте.тш #include <iostream> int х = 10; int *р = о; 11 Нулевой указатель Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  29  1712.10 int main (1 11 Присваивание указателю ацреса переменной х р = &Х; / / ВЫВОД адреса std::cout «р «std::end1; // Например: 0041АО1С 11 ВЫВОД значения std::cout «*р «std::end1; // 10 std: : cin. get (1 ; return о; { в этом примере при объявлении указателя ему присваивается значение о. В данном случае это можно было и не делать, так как rло6альные и статические локальные указ атели автоматически получmoт значение о. Однако указатели, которые объявлены в локальной области ВИДИМОСТИ, будут иметь произвольное зн ачение. Если попытаться записать какоели60 значение через такой указ атель, ТО можно повредить операционнJ'lO систему. Поэто му соrласно соrлаше нию, указатели, которые не на что не указыв aIOT, ДОЛЖНЫ иметь значение о. Указатель, которому присвоено значение О, называется нулевы..М: указателем. Вместо числовоrо значения О можно указать макрос NULL, который определен в зarоловочном файле stdio.h. Определение макрос а выrлядит так: # def ine NULL О Пример использования макроса: int *р = NULL; 11 Эквивалентно int *р = о; Значение одноrо указателя можно присвоить дрyrому указателю. При этом важно уч итывать, что типы указ ателей должны совпадать. Пример: int *рl = О, *р2 = О, х = 10; рl = &х; р2 = рl; 11 Копирование адреса переменной х std::cout «*р2 «std::end1; // 10 *р2 = 40; 11 Изменение значения впеременной х std::cout «*р1 «std::end1; //40 В этом при мере мы просто скопировали адрес переменной х из одноrо указ ателя в друrой. Помимо копирования адреса можно создать указ атель на указатель. Для этоrо при объявлении перед названием переменной указЫВaIOтся два оператора *: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  30  1712.10 int ** р = о; Чтобы получить адре с указателя используется оператор &, а для получения значения переменной, на KOTOpJ'lO ссылается указатель, применя::ются два оператора *. Пример: int *рl = О, **р2 = О, х = 10; рl = &Х; р2 = &рl; 11 Указатель на указатель std::cout «**р2 «std::endl; 11 10 **р2 = 40; 11 Изменение значения в переменной х std::cout «*р1 «std::end1; //40 КоличеС1БО вложений указателей неоrpаничено. При каждом вложении указывается дополнительная :звезд очка: int *рl = О, **р2 = О, ***р3 = О, х = 10; рl &Х; р2 = &р1; р3 = &р2; std::cout «***р3 «std::endl; 11 10 ***р3 = 40; 11 Изменение значения в переменной х std::cout «**р2 «std::endl; 1140 Подо бный синтаксис трудно понять и очень просто сделать ошибку, поэтому обычно оrpаничиваются использованием указателя на указатель. При инициализации указ ателя ему можно присвоить не только числовое значение, но и строку. Пример: char * str = rrStr ingrr; std::cout «str «std::endl; 11 String Указатели можно сохр анять в массиве. При объявлении массива указ ателей и с пользует ся сл едJ'!O щи й с и нтакс и с: <Тип> *<Название массива>[<Количество элементов>]; Пример использования массива указ ателей: int *р[3]; 11 Массив указателей из трех элементов int х = 10, У = 20, z = 30; р[О] &Х; р[l] = &у; р[2] = &Z; std::cout «*р[О] «std::end1; // 10 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  31  1712.10 std: : cout « *р [1] « std:: end1; / / 20 std: : cout « *р [2] « std:: end1; / / 30 Объявление мае сива строк и ВЫВОД значений выrлядит так: const char * str [] = {rrStr ingl rr, rrStr ing2 rr, rrStr ing3 rr} ; std::cout «str[O] «std::end1; // String1 std::cout «str[l] «std::end1; // String2 std::cout «str[2] «std::end1; // String3 Указатели очень часто ИСПОЛЬЗJ'lOТСЯ ДЛЯ обращения к элементам массива, так как адресная ариф метика выполяется эф фективнее, чем доступ по индексу. В кач естве п римера создадим массив из трех элементов, а затем выведем значения (листинr 2.1 О). I .1IИСТIПП 2.10. Перебор 'леreнrов mссив n #include <iostream> int main (1 const short SIZE = 3; int i, *р = О, arr[SIZE] {10, 20, 3О}; 11 Устанавливаем указатель на первый элемент массива р = arr; 11 Оператор & не указывается! I I for (i=O; i<SIZE; ++i) std::cout «*р «std::endl; ++р; 11 Перемещаем указатель на слующий элемент р = arr; 11 Восстанавливаем положение указателя 11 Выполняем какиелибо ИНСТРУКЦИИ std: : cin. get (1 ; return о; { в первой строке внутри функции main (1 объявляется константа S I ZE, в которой сохраняется количество элементов в массиве. Если массив используется часто, то лучше сохранить ero размер как константу, так как количество элементов нужно будет указыв ать при каждом переборе массива. Если в каждом цикле указывать конкретное число, то при изменении размера массива придется вручнJ'lO вносить изменения во всех циклах. При объявлении константы достаточно будет изменить ее значение один раз при инициализации. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  32  1712.10 в следующе й строке объявляется переменная i, предназначенная для использования внутри цикла for. Эту переменную можно объявить в первом параметре цикла. В этом случае она будет видна только внутри цикла f or. Пример объявления: for (int i=O; i<SIZE; ++i) {/* Инструкции *1 } Далее объявляется указатель на тип in t и массив. Количество элементов массива задается константой S 1: Е. При объявлении массив инициализируется начальными значениями. После объявления переменных указателю присваивается адрес первоrо элемента массива. Обратите внимание на то, что перед названием массива не указыв ается оператор &, так как название переменной содержит адрес первоrо элемента. Если использовать оператор &, ТО необходимо дополнительно указ ать индекс внутри квадр атных ско бок: р = &arr[O]; 11 Эквивалентно: р = arr; Для перебора элементов массива используется цикл f or. В первом параметре цикла задается начальное значение (i=O), во втором  условие (i<SIZE), а в третьем  приращение на единицу (++i) на кажд ой нтерации цикла. Инструкц ии внутри цикпа будут выполняться пока условие является истинным (значение переменной i меньше количе ства элементов массива). Внутри цикла выводится значение элемента на который ссылается указатель, а затем значение указателя ув еличивается на единицу (++р;). Обратите внимание на то, что изменяется адрес, а не значение элемента массива. При увеличении значения указ ателя используются правила адресной арифметики, а не правила обычной ариф метики. Увеличение значения указателя на единицу означает, что значение буд ет увеличено на размер Т1Iпа. Например, если тип in t занимает 4 байта, то при увеличении значения на единицу указ атель вместо адр еса ОхО О 12 FF 3 О буд ет содержать адре с ОхО О 12 F F 3 4. Значение ув еличилось на 4, а не на 1. В нашем при мере вместо двух инструкций внутри цикла можно использовать одну: std::cout «*р++ «std::endl; Выраж ение р++ возвращает текущи й адрес, а затем увеличивает ero на единицу. Символ * позволяет получить доступ к значению элемента по указанному адресу. Последовательность выполнения соответствует слеДJ'lOщей расстановке скобок: std::cout «*(р++) «std::endl; Если скобки расставить так: std::cout « (*р)++ «std::endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  33  1712.10 то, вначале будет получен доступ к элементу массива и выведено ero текуще е значение, а затем ПРОИЗВОДИТСЯ ув еличение значения элемента массива. Перемещение указателя на следJ'lOЩИЙ элемент не производится. Получить доступ к элементу массива можно несколькими способами. Первый способ заключается в указ ании индекса внутри Iffi адратных скобок Во втором способе используется адресная ариф метика совместно с разыменованием указателя. В третьем способе внутри maдpaTHblX СКО бок указывается название массива, а перед Iffiадратными СКО 6ками  индекс элемента. ЭтОТ способ может показаться странным. Однако, если уч есть, что выражение 1 [ar r] воспринимается компилятором как * (1 + arr), то все встанет на свои ме ста. Таким 06разо м, все эш инструкции являются Эlffiивалентными: int ап[3] = {10, 20, 30{; std::cout «arr[l] «std::endl; std::cout «*(arr + 1) «std::endl; std::cout «*(1 + arr) «std::endl; std::cout « l[arr] «std::endl; С указателем можно выполнять следующие / / 20 / / 20 / / 20 / / 20 ари фметические и лоrические операции: -+ прибавлять целое число. Число умножается на размер базовоrо типа указателя, а з ате м резуль тат пр и б авля ет ся к адр е су; -+ вычитать целое число. Вывести значения элементов массива в обратном порядке можно так: р = &arr[2]; 11 Устанавливаем указатель на последний элемент for (i=SIZE 1; i>=D; i) std::cout « *p « std: :endl; -+ вычитать один указатель из друrоrо. Это позволяет получить количество элементов базовоrо типа между двумя указателями; -+ сравнивать указатели между собой. При использовании ключевоrо слова с ons t применительно к указ ателям важно уч итывать местоположение ключевоrо слова со ns t. Например, слеДJ'lOщие объявления не Эlffiивалентны: const char * р str; char const * р str; char * const р = str; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  34  1712.10 const char * const р = str; Первые два объявления являются Эlffiивалентными. В ЭТОМ случае изменить значение, на которое ссылается указ атель, нельзя, но указ ателю можно присвоить дрyrой адрес: char strl [] = rrStr ing rr , str2 [] = rrNew rr ; const char * р = strl; р = str2; 11 Нормально р [О] = 's'; / / Ошибка При третьем объявлении изменить значение, на которо е ссылается указатель, можно, но указ ателю нельзя присвоить дрyrой адрес: char strl [] = rrStr ing rr , str2 [] = rrNew rr ; char * const р = strl; р = str2; р[О] = 1;з 1; Четв ерто е о бъявл е н и е з апр ещ ает и присвоение дрyrоrо адреса: char strl [] = rrStr ing rr , str2 [] const char * const р = strl; / / Ошибка / / но рмаль но изменение значения, на которое ссылается указатель, rrИew rr ; р = str2; р [О] = 1;з 1; / / Ошибка / / Ошибка ССЫЛКII Ссылка  это переменная, котор ая является псевдонимом друrой переменной. Присвоить значение ссылке можно только при ее объявлении. Тип ссылки должен совпадать с типом переменной. Объявление выrлядит следующи м обр азом: <Тип> &<Название ссылки> = <Переменная>; После созд ания ссылки ее название можно использовать в выражениях вместо названия переменной. Пример использования независимых ссылок приведен в листинrе 2.11. I .1IИСТIПП 2.11. НезnвнсНI>1Ыe ССЫЛКН # include <iostream > int main () int х = 10; int & ref = х; 11 Объявление ссылки Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  35  1712.10 ref = 20; std: : cout « х « std: : endl; // 20 х = 30; std: : cout « ref « std: : endl; // 30 std: : cin. get (1 ; return о; Oco6oro смысла в применении независимых се ьток нет. Ве е удобство использования ссылок проявляется при передаче параметров в функцию. Пре жде чем рассматривать передачу параметров с помощью ссылок вначале необходимо продемонстрировать и спользование указателей (листинr 2.12). I .1IИСТIПП 2.12. ПереД<l'ffi rmpnreTpoB IЮ се ылке # include <iostream > void fUnC(int *х); int main (1 int у = 10; func (& yl; std: : cout « у « std:: endl; std: : cin. get (1 ; return о; 11 передаем ацрес, а не значение / / 20 void fUnC(int *х) *х=*х*2; в этом примере объявлена функция func (1 , внутри которой про изводится увеличение значения переменной в два раза. Если использовать передачу по значению (применяется по умолчанию), то создается копия значения и все операции ПРОИЗВОДЯТСЯ с этой копией. Так как локальные переменные ВИДНЫ только внутри тела функции, после завершения выполнения функции копия уд аляется. Любые изменения зн ачения копии не затронут значения ориrинала. Чтобы изменить значение самой переменной используется передача значения по ссылке. В этом случае в функц ию перед ается адрес переменной : Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  36  1712.10 func (& уl ; Внутри функции адрес присваивается указателю. Используя операцию разыменования указ ателя можно изменить знач ение самой переменной, а не значение копии. Достиrается это с помощью следующей инструкции: *х=*х*2; При использовании ссылки оператор & указ ывается перед параметром в объявлении функции. В этом случае при вызове функции передается не адрес, а значение. Таким образом внутри функции мы работаем с псевдонимом переменной, а не с указателем, поэтому выполнять разыменование указателя не нужно. Пример использования ссылок приведен в листинrе 2.13. .1IИСТIПП 2.13. ПереД<l'ffi rmpnreTpoB с IЮЮШ;ЬЮ ссылок #include <iostream> void func (int &х); int main (1 int у = 10; func (yl; std: : cout « у « std:: endl; std: : cin. get (1 ; return о; 11 передаем значение, а не ацрес / / 20 void fUnC(int &х) х = х * 2; Соrласитесь, что инструкция х = х инструкция *х = *х * 2;. * 2; выrлядит более привлекательно, чем Дпнаl\lIIческое выделенпе памятп Как вы уже :знаете, при объявлении переменной необходимо указ ать тип данных, а ДЛЯ массива дополнительно задать точное количество элементов. На основе этой информации при запуске проrpаммы автоматически выделяется необходимый объем па:мяти. После завершения проrpаммы память автоматически освобождается. Иными словами, объем па:мяти необходимо знать до выполнения проrpаммы. Во вре:мя Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  37  1712.10 выполнения проrpаммы созд ать новую переменную или увеличить размер суще ствующеrо массива нельзя. Чтобы произвести увеличение массива во вре:мя выполнения проrpаммы необходимо выделить достаточный объем па:мяти с помощью оператора new, перенести суще ствующие элементы, а ЛИШЬ затем добавить новые элементы. Управление динамической па:мятью полностью лежит на rшечах проrpаммиста, поэтому после завершения работы с па:мятью необходимо самим возвратить па:мять операционной системе с помощью оператора dele te. Если па:мять не возвратить операционной системе, то УЧ асток па:мяти станет недоступным для дальнейшеrо использования. Подо бные ситуации приводят к утечке памяти. Сделать эти участи опять доступными МОЖНО только после перезarpузки компьютера. Для выделения памяти под один объект предназначен следующий синтаксис: < Указ а те ль > = new <Тип данных> ( < Началь но е значе ние » ; Оператор new выделяет объем па:мяти, необходимый ДЛЯ хранения значения указ aHHoro типа, записывает в эту па:мять начальное значение (если оно задано) и возвращает адрес. Работать в дальнейшем с этим участом па:мяти можно с помощью указателя. Пример выделения па:мяти: int * р = new int; 11 Без начальноI"О значения int * р = new int (10); 11 С начальным значением При выделении па:мяти может возникнуть ситуация нехватки па:мяти. В ранних версиях С++ в этом случае возвращался нулевой указатель. Соrласно новой версии стандарта в случае ошибки оператор new долж ен возбуждать исключение bad a110c (о бъект исключения определ ен в файле new). Обработать это исключение можно с помощью конструкции tr у. . . са t ch. Пример выделения памяти с обраб откой исключения: # include <new> 11 ... Фрarмент опущен int *р = о; 11 Со=щаем указатель try р = new in t; 11 Быд е ляем память catch (std:: bad alloc err) 11 Обработка исключения Выдел ение памяти производится внутри исключение Ь ad  alloc, то управление блока будет try. Если передано в при этом возникнет блок cat ch. После Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  38  1712.10 выполнения инструкций в блоке са tc h управление передается инструкции, расположенной сразу после блока. Иными словами, компилятор считает, что вы обработали исключение и можно продолжить выполнение проrpаммы. Следует уч итывать, что пользоваться указ ателем после обработки нельзя, поэтому внутри блока са tc h обычно ВЫВОДЯТ сообщение 06 оши 6ке и завершaIOТ выполнение проrpаммы. Если исключение не обработать, то проrpамма аварийно завершится. Если исключение не возникло, ТО инструкции внутри блока са tc h не выполняются. Обратите внимание на то, что объявление указателя про изводится вне блока try. Если объявление раз местить внутри блока, то область видимости переменной будет оrpаничена этим блоком. После выхода из блока переменная автоматически уничтожается, а выделенная память операционной системе не Бозращается. Поэтому, объявление указателя ДОЛЖНО нахОДИТЬСЯ перед блоком, а не внутри Hero. Во:звр ашть ранее выделеннYIO па:мять операционной системе позволяет оператор de 1e te. Оператор имеет следующи й формат: delete <Указатель>; После использования оператора de1ete указатель попрежнему будет содержать прежний адрес. Поэтому после использования оператора delet е указ атель принято обнулять. Пример выделения памяти под один объект приведен в листинrе 2.14. .1IИСТIПП 2.14. Дшmшческое выделение шшяти IЮд оДШI объект # include <iostream > #inc1ude <cstd1ik> # inc 1 ude <new> / / Для exit (1 / / Для bad a110c int main () int * Р = о; try { р = new int; 11 Создаем указатель 11 Выделяем память catch (std:: bad  a110c енl std::cout « rrError rr «std::endl; std:: exit (11; 11 Выходим при ошибке * р = 20; std: : cout « *р « 11 Пользуемся памятью std: : end1; / / 20 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  39  1712.10 delete р; р = о; std: : cin. get (1 ; return о; 11 Во з вращаем память 11 Обнуляем указатель Выдел ение памяти под массив производится следующим образом: <Указатель> = new <Тип данных>[<Количество элементов>]; Освободить выделенную память можно так delete [] <Указатель>; Обратите внимание на то, что при освобождении па:мяти количество элементов не указыв ается. Пример выделения памяти под массив приведен в листинrе 2.1 s. I-тшст IПП' 2.15. Д:mml'rllfЧeское вьщелеmre ШlI'r1ЯТИ под I'rrn ссив #include <iostream> #inc1ude <cstd1ik> # inc 1 ude <new> / / Для exit (1 / / Для bad a110c int main (1 const short S IZE 3 . , 11 Размер массива 11 Со=щаем указатель int *р о. , try р = new int[SIZE] ; 11 Выделяем память catch (std:: bad  a110c енl std::cout « rrError rr «std::endl; std:: exit (11; 11 ВЫХОДИМ при ошибке { р[О] Р [1] р[2] 10; 20; 30; (int i=O; i<SIZE; ++i) std::cout «p[i] «std::endl; // Пользуемся памятью for de1ete [] р; р = о; 11 Во з вращаем память 11 Обнуляем указатель Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  40  1712.10 std: : cin. get (1 ; return о; в ранних версиях С++ при нехватке памяти возвращался нулевой указ атель. Такая же ситуция возникает в языке С при использовании функции ma110 с ( 1 . Чтобы оператор new, соответствYIOЩИЙ современному стандарту, возвращал нулевой указ атель, а не rенерировал исключение используется следJ'lOЩИЙ синтаксис: <Указатель> = new (std::nothrow) <Тип данных>«Начальное значение»; <Указатель> = new (std::nothrow) <Тип данных>[<Количество элементов>]; Для использ ования not hr ow требуется ПОДКЛЮЧИТЬ файл new. После выделения па:мяти следует проверить указатель на отсутствие нулевоrо значения Пример выделения памяти без rенерации исключения приведен в листинrе 2.1 б. .1IИСТIПП 2.16. Дшmшческое выделение шшяти без rеиерnЦlШ ИСКJпочеиия #include <iostream> #inc1ude <cstd1ik> # inc 1 ude <new> / / Для exit (1 / / Для nothrow int main (1 int *р = new if (' рl std: : cout (std::nothrow) int; 11 Выделяем память 11 Проверяем на корректность « rrError rr « std:: endl; std:: exit (11; 11 ВЫХОДИМ при ошибке * р = 20; std: : cout « *р « delete р; р = о; std: : cin. get (1 ; return о; 11 Пользуемся памятью std: : end1; / / 20 11 Во з вращаем память 11 Обнуляем указатель Язык С++ поддерживает также функции ma110 с (1 и f ree (1 из языка С. Функция ma110c (1 предназначена для динамическоrо выделения памяти, а функция fr ее (1  для освобождения ранее выделенной памяти. Для использования функций необходимо подключить файл cstd1ib (или std1ib. h). Прототипы функций: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 41  1712.10 #inc1ude <cstd1ik> void *malloc(sizet Size); void free(void *Memory); Функция ma110 с ( 1 принимает в качестве параметра размер памяти в байтах и возвращает указатель, имеющий Т1IП void *. Если па:мять выделить не удалось, ТО функция возвращает нулевой указатель. В языке С++ перед присвоением значения указ ателю необходимо выполнить явное приведение к используемому типу. Кроме Toro, чтобы проrpамма была машинонезависимой следует применять оператор si zeo f для вычисления размера памяти, требуемоrо для определ eHHoro типа. Пример: int *р = (int *) std::malloc(sizeof(int)); Функция f re е (1 принимает в качестве параметра указ атель на ранее выделенную память. Важно учитывать, что указ атель должен быть корректным. Пример использования функций ma110c (1 и free (1 приведен в листише 2.17. .1IИСТIПП 2.17. Дшmшческое выделение шшяти с IЮЮШ;ЬЮ ф)"икций 1flalloc О и fl'eeO #include <iostream> #inc1ude <cstd1ik> // Для exit(l, malloc(1 и free(1 int main () 11 Выделяем память int *р = (int *) std::malloc(sizeof(int)); if (!р) 11 Проверяем на корректность std: : cout « rrError rr « std:: endl; std:: exit (11; 11 ВЫХОДИМ при ошибке * р = 20; std: : cout « *р std: : free ( (void Р = о; std: : cin. get (1 ; return о; 11 Пользуемся памятью « std:: end1; // 20 *) р) ; 11 Возвращаем пaм.qть 11 Обнуляем указатель Следует учитывать, что функции ma110 с (1 и f re е (1 применяются в языке С Хотя их можно использовать и в языке С++, тем не менее стоит отд ать предпочтение оператору new И явной обработке исключения. Описание функций ma110c (1 и f re е ( 1 , а также Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  42  1712.10 ключевоrо слова по thr OW, приведено в этой книrе ЛИШЬ для Toro, чтобы вы моrли разобраться в чужом коде. Необходимо также заметить, что в одной проrpамме не стоит одновременно использовать оператор new И функцию ma110 с ( 1 . Структуры Структура  ЭТО совокупность переменных (называемых членами, элементами или полями), объединенных под одним именем. Объявление структуры выrлядит следующим образом: struct [<Название структуры>] <Тип данных> <Название поляl>; < Тип данных> < Название по ляN >; [<Объявления переменных через запятую>]; Допустимо не задавать название структуры, если после закрывающей фиrурной ско бки указано объявление переменной. Точка с запятой в конце объявления структуры является обязательной. Объявление структуры только описывает новый тип данных, а не определяет переменную, поэтому память под нее не выделяется. Чтобы объявить переменную, ее название указывается после закрывающей Ф иryрной скобки при объявлении структуры или отдельно, используя название структуры в качестве типа данных: [struct ]<Название структуры> <Названия переменных через запятую>; В языке С++ ключевое слово str ис t при объявлении переменной можно не указывать. После объявления переменной компилятор выделяет необходимый размер памяти. Для получения размера структуры внутри проrpаммы следует использовать оператор sizeof: <Размер> = sizeof <Переменная>; <Размер> = sizeof «Название структуры»; Пример одновременноrо объявления структур ы и переменной: struct Point int Х; int У; point 1; Пример отдельноrо объявления переменной: Point point 2; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  43  1712.10 Присвоить ИЛИ получить значение поля можно с помощью точечной нотации: <Переменная>.<Название поля> = <Значение>; <Значение> = <Переменная>.<Название поля>; Пример: point 1. х о; point 1. У 100; Одну структуру можно присвоить друrой структуре с помощью оператора случае копируются значения всех полей структуры. Пример : point2 = point 1; Структуры можно вкладывать. При обращении к полю вложенной структуры дополнительно указывается название структуры родителя. В качестве примера объявим структуру р oin t (точка), а затем используем ее для описания ко ординат прямоуrольника (листинr 2.18). Структуру, описывающую прямоуrольник, объявим без н азв ания. в этом I .1IИСТIПП 2.18. ИСIЮЛЪЗОВnние ВJIO,""HНЫX Cтp)'](T)l' # include <iostream > struct Point { 11 Объявление именованной структуры int Х; int У; {; struct 11 Объявление структуры без названия Point top left; Point bottomright; rect; int main (1 rect.top left.x = о; rect.top left.y = о; rect.bottomright.x = 100; rect.bottomright.y = 100; std::cout «rect.top left.x « rr rr «rect.top left.y «std::endl « rect.bottomright.x « rr rr Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 44  1712.10 «rect.bottom rlght.y «std::endl; std: : cin. get (1 ; return о; { Адр ес структуры можно с охранить в указателе. Объявление указателя на структуру производится также как и на любой дрyrой тип данных. Для получения адре са структуры используется оператор &, а для доступа к полю структуры вместо точки при меняется оператор >. Пример использования указателя на структуру приведен в листинrе 2.19. -ТШСТIПП 2.19. ИспользовnIOre :'r"К;[IЗnТeJIЯIffi СТР:'r"КТ:'r'JI:'r # include <iostream > struct Point int Х; int У; point 1; Point *р = &pointl; 11 Объявление указателя 11 Объявление структуры и переменной int main (1 p>x = 10; p>y = 20; std: : cout « p>x « rr rr « p>y « std:: endl; std: : cin. get (1 ; return о; { в языке С++ структуры имеют функционал, аналоrичный классам. Единственное отличие состоит в ТОМ, что доступ к членам структуры является открытым, а доступ к членам кл асса по умолчанию является закрЫТЫМ. И в ТОМ и друrом случае поведение по умолчанию можно изменить. Например, объявление класса Point с отрытым доступо м к чл е н ам в ыrляд ит так: class Point { 11 Объявление класса и переменной р uk1ic : int Х; int У; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  45  1712.10 } point; Как видно из примера, объявление класса ПРОИЗВОДИТСЯ также как и объявление структуры, только вместо ключевоrо слова str ис t используется слово с las s. Отличие только в указании ключевоrо слова public перед объявлением членов класса, которое открывает доступ к членам класса извне. Как уже rоворилось, по умолчанию доступ к членам класса извне закрыт. Классы мы рассмотрим подробно при изучении объектно ориентированноrо проrpаммирования Бптовые поля Лоrический тип данных bool может содержать только значения true (соответствует числу 1) или fa1se (соответствует числу О). Эти значения помещаются в один бит, однако тип данных Ьоо 1 занимает в памяти целый байт (восемь бит). Остальные семь бит не содержат значений. Язык С++ поддерживает битовые поля, которые предоставляют доступ к отдель ным битам, позволяя тем самым хранить в ОДНОЙ переменной несколько значений, занимaIOЩИХ указанное количеС1БО бит. Тем не менее следует учитывать, что минимальный размер 6итовоrо поля будет соответствовать типу in t (в 32битной операционной системе занимает 4 байта). Объявление битовоrо поля имеет следующий фор мат struct [<Название БИТQБоrо поля>] <Тип данных> [<Название поля1>]:<Длина в битах>; <Тип данных> [<Название поляМ>]:<Длина в битах>; } [<Объявления переменных через запятую>]; В одной структур е можно использовать одновременно битовые поля и обычные поля. Обратите внимание на то, что название битовоrо поля можно не указывать, кроме Toro, если длина поля составляет один бит, то перед названием поля следует указать ключевое слово unsigne d. Пример объявления битовоrо поля и переменной: struct Status { unsigned :3; unsigned а: 1; unsigned Ь: 1; unsigned с: 1; status; Доступ к полю осуще ствляется такж е как и к полю структур ы: status. а = 1; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  46  1712.10 status. Ь status . с о. , l' ,   ОоъеДIIнеНIIЯ 06ъ едине ние  это о бл асть п а:мяти, и сп ольз уе мая ДЛ я хр ан е ния Д ан ных р аз н ых ти П ОБ. В один момент времени в этой области Moryт хр аниться данные только одноrо типа. Размер объединения будет соответствовать размеру более сложноrо типа данных. Например, если внутри объединения определены переменные, имеющие типы in t, f 10a t и do uk1e, то размер объединения будет соответствовать размеру типа do uk 1e. Объявление объ единения имеет следующий формат: union [<Название объединения>] <Тип данных> <Название членаl>; <Тип данных> <Название членаМ>; [<Объявления переменных через запятую>]; Точка с запятой в конце объявления является обязательной. Объявление только описывает новый тип данных, а не определяет переменнJ'lO, поэтому па:мять ПОД нее не выделяется. Ч то6ы объявить переменнJ'lO, ее название указывается после заКРЫВaIOщей фиryрной скобки при объявлении объединения или отдельно, используя название объединения в кач естве типа данных: [union ]<Название объинения> <Названия переменных через запятую>; В яз ыке С++ ключевое слово union при объявлении пере мен ной можно не указывать. После объявления пере мен ной компилятор выделяет необходимый размер па:мяти. При мер объявления объ единения и пере мен ной : union Uni int х; float У; douk1e "; union1 ; Присвоить или получить значение можно с помощью точечной нотации: <Переменная>.<Название члена> = <Значение>; <Значение> = <Переменная>.<Название члена>; При мер: union1. х 152; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 47  1712.10 std::cout «unionl.x «std::endl; 11 152 В языке С++ объединения MOryт содер жать функции, а также конструктор и деструктор. Объявления функций раз мещаются внутри объявления объединения, а определения функций  вне объявления. Перед названием функции указывается название объединения и оператор ::. Внутри функции к членам объединения можно обращаться без указания н«звания объединения. Пример использования объединений приведен в листинrе 2.20. I .1IИСТIПП 2.20. Объединения # include <iostream > union Uni int Х; double У; void prl1lt х () ; void рПllt У (1 ; {; void Unl:: pr lnt х () std::cout «х «std::endl; void Unl:: pr lnt у (1 std::cout «у« std::endl; int main (1 Uni unionl; unionl. х = 152; unlOn1. prlnt х (1; / / 152 unionl. у = 1. 5e5; unlOn1.prlnt y(l; // 1.5e005 std: : cin. get (1 ; return о; д о пус кается переменных. не задавать одновременно название объединения и объявления В этом случае объединение называется 6еЗЫМ,ЮiНЫ..М: или aHoН,u.мн,Ы..M:. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  48  1712.10 Доступ к членам 6езы:мянных объединений осуществляется непосредственно по именам членов. Таки м образом, названия членов объединений не ДОЛЖНЫ кон фликтовать с именами переменных, объявленных в том же пространстве имен. Безы:мянные объединения расположенные в rло6альной области ВИДИМОСТИ или внутри пространства имен ДОЛЖНЫ объявляться с помощью ключевоrо слова sta tic. Пример использования б ызымянных объединений приведен в листише 2.21. I .1IИСТIПП 2.21. Безымянные (nlЮННI>mыe) объединения #include <iostream> static union { 11 static указывать обязательно int Х; double У; {; int main(1 { unio n { // с лова int а' , douk1e Ь' , static не указывается {; х = 12 ; std: : cout « х « std: : endl; // 12 У = 11.5; std: : cout « у « std: : endl; // 11.5 а = 458; std: : cout « а « std: : endl; // 458 ь = 1.7е5; std::cout «Ь «std::end1; // 170000 std: : cin. get (1 ; return о; Пер еЧIIслен IIЯ ПереЧ,uсленuе  ЭТО совокупность допусТ1l мые значения переменной. целочисленных констант, ОПИСЫВaIOщих Если переменной присвоить значение все не Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  49  1712.10 совпадmoщее с перечисленными константами, ТО КО мпилятор выведет сообщение 06 ошибке. Объявление перечисления имеет следующий формат: еnит [<Название перечисления>] <Список констант через запятую> [<Объявления переменных через запятую>]; Точка с запятой в конце объявления является обязательной. Чтобы объявить переменную, ее название указыв ается после закрывающей фиrурной ско бки при объявлении перечисления или отдельно, используя название перечисления в кач естве типаданных: [еnит ]<Название перечисления> <Названия переменных через запятую>; В языке С++ ключевое слово е пит при объявлении переменной можно не указывать. Пример одновременноrо объявления перечисления и переменной: enum Color { red, blue, green, black } color 1; Пример отдельноrо объявления переменной: Color color2; Константам re d, blue, gre еn И black автоматически присваивaIOТСЯ целочисленные значения, начиная с нуля. Значение каждой послеДJ'lOщей константы будет на единицу больше предыдущей. Нумерация производится слева направо. Таким образ ом, константа r ed будет иметь значение О, Ыие  1, gr ее n  2, а black  3. При объявлении перечисления константе можно присвоить друтое значение. В этом случае последующая константа будет иметь значение на единицу больше этоrо друrоrо значения. Пример: enurn Color { red=3, Ыие, green=7, black } color 1; В этом примере, константа r ed будет иметь значение 3, а не О, Ыие  4, gre еn  7, а Ыас k  8. Присвоить значение переменной можно так color 1 = black; Допустимо не зад авать одновременно название перечисления и объявление переменной. В этом случае переменные, указан ные внутри фиryp ных скобок, используются как константы. Пример: enurn { Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  50  1712.10 red, Ыие = 10, green, black {; std: : cout « Ыие « std:: end1; / / 10 П ример использования перечисления приведен в листинrе 2.22. I Лист ИIП' 2.22. Перечисления # include <iostream > еnит Color { 11 Объявление перечисления red, Ыие, green=5, black {; int main () Color color; 11 Объявление переменной color = black; std::cout «color «std::endl; 11 6 if (co1or == blackl { // Проверка значения std: : cout « rrcol or == black rr « std:: endl; std: : cin. get (1 ; return о; Прпведенпе тппов Как вы уже :знаете, при объявлении переменной необходимо указать определенный тип данных. Далее над переменной можно производить операции, предназначенные для этоrо типа данных. Если в выражении ИСПОЛЬЗJ'lOТСЯ переменные, имеющие разный тип данных, то тип результата выражения будет соответствовать наиболее сложному типу. Например, если ПРОИЗВОДИТСЯ сложение переменной, имеющей тип in t, с переменной имеющей тип do uble, то целое число 6уд ет автоматически прео6разовано в веще ственное. Результатом этоrо выражения будет значение, имеющее Т1Iп double. При попытке присвоитъ переменной значение, имеюще е несовместимый тип, компилятор выведет сообщение об ошибке (если автоматическое преобразование невозможно) или предупрежд aIOщее сообщение (при усечении значения). Например, попытка присвоить целочисленной переменной строку (int х = rrstr ing rr ;) приведет Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  51  1712.10 к неисправимой ошибке: "error С2440: инициализация: невозможно преобразовать 11 const char [7 ]11 в "int llll . Попытка присвоить вещественное число целочисленной переменной (in t х = 1 0.5;) приведет к следующе му предупреждающему сообщению: "warning С4244: инициализация: прео6разование "double " в "int", возможна потеря данных". В ЭТОМ случае дробная часть просто отбрасывается, переменной присваивается число 1 О, а выполнение проrpаммы будет продолжено. Подобное сообщение будет выведено даже е ели после точки стоит нуль. Чтобы избавиться от предупреждающих сообщений необходимо выполнить явное прueедеiiие тите. В этом случае компилятор считает, что вы :знаете что делаете. Для приведения типов в языке С++ используются следующие операторы: -+ st at ic с as t  применяется для стандартноrо приведения ТИПОВ. Формат о п ер атор а: static cast< <Тип результата> > «Выражение» Например, деление целых чисел возвращает целое число. Дробная часть при этом просто отбрасывается. Чтобы деление целых чисел возвращало вещественное число, необходимо прео6разовать одно из целых чисел в веще ственное: int х = 10, У = 3; std: : cout « х / у « std: : endl; // 3 std: : cout « static cast<double> (хl / у « std: : endl; // 3.ЗЗЗЗ3 -+ re ln te rp re t с ast  используется для приведения указателя одноrо типа в абсолютно дрyrой, даже в несовместимый. Формат оператора: relnterpret cast< <Тип результата> > «Выражение» -+ со ns t cast  отменяет действие ключевых слов с ons t и vo la tile. Формат о п ер атор а: const cast< <Тип результата> > «Выражение» Пример приведения KOHcTaHTHoro указателя в обычный внутри функции: void func(const int *х) lnt *р = const cast<lnt *> (х); / / * х = 50; / / Ошибка' , , *р = 30; 11 Теперь можно изменить значение Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  52  1712.10 Пример уд аления действия ключевоrо слова с ons t у ссылки внутри функции: void func(const int &х) //х = 50; // Ошибка'" 11 Теперь можно изменить значение const cast<int &> (х) = 30; -+ dynamlc cas t  выполняет приведение типов указателей или ссылок Применяется для приведения поли мор фных типов. Если приведение указателя окончилось неудачей, оператор возвращает нулевой указ атель, а если проблема с о ССЫЛКОЙ, то re нерируется исключение bad  cast (объект исключения объявлен в файл е typeinfo). Формат оператора: dynamlc cast< <Тип результата> > «Выражение» Более подробно оператор d ynamlc с as t мы рассмотрим при изучении объектно ор иентир ов ан н oro пр orp аммир ов ания. Язык С++ поддерживает также приведение типов, используемое в языке С Формат пр ивед е н ия: «Тип результата»<Выражение> Пример преобразования целоrо числа в вещественное, имеющее тип do uk 1e: int х = 10, У = 3; std::cout «х / у« std::end1; //3 std::cout « (douk1elx / у« std::end1; //3.33333 Кроме Toro, можно указ ать выражение внутри крyrлых скобок после названия типа: std::cout «douk1e(101 / 3 «std::end1; //3.33333 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  2  1712.10 Операторы позволяют выполнить определенные действия с данными. Например, операторы присваивания служат для сохранения данных в переменной, математические операторы предназначены для арифметических вычислений, а условные операторы позволяют в зависимости от значения лоrическоrо выражения выполнить отдельный уч асток проrpаммы или наоборот не выполнять ero. l\Iатеl\Iaтпческпе операторы Производить арифметические вычисления позволяют следующи е операторы: -+ +  сложение: std::cout « 10 + 15 « std: :endl; / / 25 -+  вычитание: std::cout « 35  15 « std: :endl; / / 20 -+   унарный минус: int х = 10; std::cout « x « std: :endl; -+ *  умножение: std: :cout « 25 * 2 « std::endl; / /  10 // 50 -+ I  деление. Если ПРОИЗВОДИТСЯ деление целых чисел, то остаток отбрасывается и возвращается целое число. Деление вещественных чисел ПРОИЗВОДИТСЯ клас сическим способом. Если в выражении уч aCТEJ'lOT веще ственное и целое числа, то целое число автоматически преобразуется в вещественное. Пример: std::cout « 10 / 3 « std::end1; // 3 std::cout« 10.0/3.0« std::end1; // 3.ЗЗЗЗ3 std::cout « 10.0 / 3 «std::end1; // 3.33333 -+ % остаток от деления. О бр атите внимание на то, что этот о пер атор нельзя применять к вещественным числам. Пример: std: : cout « 10 % 2 « std: : endl; // о (10  10 / 2 * 21 std: : cout « 10 % 3 « std: : endl; // 1 (10  10 / 3 * 31 std: : cout « 10 % 4 « std: : endl; // 2 (10  10 / 4 * 41 std: : cout « 10 % 6 « std: : endl; // 4 (10  10 / 6 * 61 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  3  1712.10 -+ ++  оператор инкремента. Увеличивает значение переменной на 1: int х = 10; ++Х; 11 Эквивалентно х std::cout « х « std::end1; // 11 -+  оператор декремента. Уменьшает знач ение переменной на 1: х + 1; int х = 10; X; 11 Эквивалентно х std::cout « х « std::endl; 11 9 Операторы инкремента и декремента MOryт использоваться в постфикс ной или префиксной фор мах: х  1; х++; x; 11 Постфиксная форма ++Х; X; 11 Префиксная форма При постфиксной форме (х ++) возвращается значение переменной перед операцией, а при префиксной форме (++х)  вначале производится операция и только потом в озвращается значение. Продемонстрируем это на примере (листинr 3.1). I .1IИСТIПП 3.1. по стф ик СlffiЯ И преф иксиnя форm #include <iostream> #include <clocale> int main (1 int х = О, У = о; std: : setlocale (LC  ALL, rrRussian  Russia. 1251 rr) ; Х = 5; У = х++; // у = 5, х = 6 std: : cout « rrПостфиксная форма (у = х++;) . rr « std:: endl «rr y rr« у « std:: endl « rr x rr « х « std:: endl; х = 5; У = ++х; // у = 6, х = 6 std: : cout « rrПрефиксная форма (у = ++Х;) . rr « std:: endl «rr y rr« у « std:: endl « rr x rr « х « std:: endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  4  1712.10 std: : cin. get (1 ; return о; В итоrе получим следующий результат: Постфиксная форма (у = х++;): у = 5 х = 6 Префиксная форма (у = ++Х;): у = 6 х = 6 Если операторы инкремента идекреме нта ИСПОЛЬЗJ'lOТСЯ в сложных выражениях, то понять, каким будет результат выполнения выражения становится сложно. Например, каким будет значение переменной у после выполнения этих инструкций? int х = 5, У = о; у = ++х + ++Х; Думаете, что число 13 (у = 6 + 7;)7 После выполнения этих инструкций в VC++ 201 О переменная у будет содержать число 14 (у = 7 + 7;). Вначале вычисляется первое выражение ++х. Значение переменной х становится равным 6 (5 + 1). Далее вычисляется второе выражение ++х. Значение переменной х становится равным 7 (6 + 1). В результате инструкция примет следующий вид: х = 7; у = х + Х; Так как переменная х содержит значение 7, то вычисляется выражение 7 + 7. Результато м будет число 14. Следует учитывать, что результат выполнения при использовании друrоrо компилятора может быть дрyrим, так как поведение ко мпилятора в ЭТОМ случае в стандарте языка С++ не определено. Чтобы облеrчить жизнь себ е и всем дрyrим проrp аммистам, которые будут разбираться в проrpамме, операторы инкремента и декремента лучше использовать отдельно от друrих операторов в пре фиксной форме. Соrласитесь, что после выполнения этих инструкций, значение переменной у не вызывает никаких сомнений: int Х = 5, У = о; ++Х; ++Х; У = Х + Х; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  5  1712.10 Побптовые операторы Побитовые операторы предназначены для манипуляции отдельными битами. Эти операторы нельзя применять к вещественным числам, лоrическим значениям и дрyrим более сложным типам. Язык С++ поддерживает следующие побитовые операторы: -+   двоичная инверсия. Значение каждоrо бита заменяется на противоположное: char х = 100; х = X; // 01100100 // 10011011 // 01100100 // 01001011 // 0100000 о // 01100100 // 01001011 // 01101111 // 01100100 // 11111010 // 10011110 -+ &  двоичное И char х = 100; char у = 75; char z = х & У; -+ I  двоичное ИЛИ char х = 100; char у = 75; char z = х I у; -+ л  двоичное исключающее ИЛИ unsigned char х = 100; unsigned char у = 250 ; unsigned char z = х л у; -+ « сдвиr влево  сдвиrает двоичное представление числа влево на один или более разрядов и заполняет разряды справа нулями: char х = 100; / / 01100100 / / 11001000 / / 10010000 / / 01000000 х = х « l' , х = х « l' , х = х « 2 . , Прu.мечанuе Опер ат ар < <, исполыуемый ДЛЯ выв о да данных в OIO:IO коне ОШl, не имеет никако r о отн ошения к по бито в ому опера тор у < <. -+ » сдвиr вправо  сдвиrает двоичное представление числа вправо на один или более разрядов и заполняет разряды слева нулями, если число положительное: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  б  1712.10 char х = 100; // 01100100 х = х » l' // 00110010 , х = х » l' // 00011001 , х = х » 2 . // 00000110 , Если число отрицательное, то разряды слева заполняются единицами: char х = 127; х = х » l' , х = х » 2 . , х = х « l' , х = х » l' , // 10000001 // 11000000 // 11110000 // 11100000 // 11110000 Прu.мечанuе Опер ат ар > >, исполыуемый для вв О да данных, не :им:еет никак or о о П:IО шения к побитовому оператору ». Операторы ПрIIсваIIваНIIЯ Операторы присваивания предназначены для сохранения значения в переменной. Перечислим операторы присваивания доступные в языке С++: -+ =  присваивает переменной значение. Обратите внимание на то, что хотя оператор похож на математический знак равеНСТБа, смысл у Hero в языке С++ совершенно дрyrой. Справа от оператора присваивания может располarаться константа или сложное выражение. Слева от оператора присваивания может располarаться переменная, указатель ипи объект (у KOToporo переrpужен оператор =), но не константа. Пример присваивания значения: int Х; Х = 10; х = 12 * 10 + 45 / 5; 12 + 45 = 45 + 5; 11 Так не льз я ! ! ! В ОДНОЙ инструкции МОЖНО присвоить значение сразу нескольки м переменным: x=y=z=2; -+ +=  увеличивает значение переменной на указ aHHJ'lO величину: х += 10; 11 Эквивалентно х = х + 10; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  7  1712.10 -+ =  уменьшает значение переменной на указаннJ'lO величину: х = 10; 11 Эквивалентно х = х  10; -+ *=  умножает значение переменной на указаннJ'lO величину: х *= 10 + 5; 11 Эквивале нтно х = х * (10 + 5); -+ /=  делит значение переменной на указанную величину: х 1= 2; 11 Эквивалентно х = х 1 2; -+ %=  делит значение переменной на указанную величину и возвращает остаток: х %= 2; 11 Эквивалентно х = х % 2; -+ &=, 1=, .....=, «= и >>=  побитовые операторы с присваиванием. Оператор запятая Оператор запятая позволяет разместить сразу несколько выражений внутри одной инструкции. Например, в предыдущих примерах мы использовали этот оператор для объявления нескольких переменных в одной инструкции: int х, У; Результат вычисления последнеrо выражения можно присвоить какойлибо переменной. При этом выражения должны быть расположены внутри крyrлых ско бок, так как приоритет оператора запятая меньше приоритета оператора присваивания. Пример: int х = о, у = о, z = о; х = (у = 10, z = 20, У + zl; std::cout «х «std::end1; //30 std::cout «у« std::end1; // 10 std::cout « z «std::end1; //20 В этом примере после объявления и инициализации переменных переменной у присваивается значение 10, затем переменной z присваивается значение 2 О, далее вычисляется выражение у + z и ero результат присваивается переменной х. Операторы сравнеНIIЯ Операторы сравнения используются в лоrических выражениях. Перечислим операторы сравнения, доступные в языке С++: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  8  1712.10 -+ ==  равно; -+ ,=  не равно; -+ <  меньше; -+ >  больше; -+ -с=  меньше или равно; -+ >=  больше или равно. Лоrические выражения БОЗВращmoт только два значения true (истина, СООТБетствует числу 1) или fa1se (ложь, соответствует числу О). Пример вывода значения лоrическоrо выражения: std: : cout « (10 101 « std: : endl; // 1 (truel std: : cout « (10  51 « std: : endl; // О (falsel std: : cout « (10 ,= 51 « std: : endl; // 1 (truel std: : cout « (10 < 51 « std: : endl; // О (falsel std: : cout « (10 > 51 « std: : endl; // 1 (truel Лоrическое выражение может не содержать операторов сравнения вообще. В этом случае число О автоматически преобразуется в ложное значение (fa1se), а любое ненулевое значение (в том числе и отрицательное)  в истинное значение (true): std::cout « (boo1110 «std::end1; // 1 (truel std::cout « (boo1110 «std::end1; // 1 (truel std::cout « (boolI12.5 «std::end1; // 1 (truel std::cout « (boo110.1 «std::end1; // 1 (truel std::cout « (boo110.0 «std::end1; //0 (falsel std::cout « (boo110 «std::end1; // О (falsel В этом при мере мы воспользовались приведением к типу Ьо 01. Внутри лоrическоrо выражения приведение типов выполнять не нужно, так как оно ПРОИЗВОДИТСЯ авто матич е СКИ. Следует учитывать, что оператор проверки на равенство с одержит два символа =. Указание одноrо символа = является лоrической ошибкой, так как этот оператор используется для присваивания значение переменной, а не для проверки уел ОБИЯ. Использ овать оператор присваивания внутри лоrическоrо выражения допускается, поэтому компилятор не выведет сообщение об оши бке, однако проrpамма может выполняться некорректно. Подобную ошибку часто допускают начинающие Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  9  1712.10 проrpаммисты. Например, в следующем примере вместо проверки равенства числу 11, ПРОИЗВОДИТСЯ операция присваивания: int х = 10; if (х = 111 std: : cout « rr x 11" «std::endl; { Любое число не равное О трактуется как лоrическое значение true, поэтому ПРОИЗВОДИТСЯ проверка условия tr ие == tr ие, которое является ИСТИНЫМ. Значение лоrическоrо выражения можно инвертировать с помощью оператора !. В этом случае если лоrическое выраж ение возвращает false, ТО ! f alse вернет значение t rue. Пример: std: : cout « std: : cout « (10 , (10 51 « std:: end1; 51 « std:: end1; / / о (falsel / / 1 (truel Несколько лоrических выражений можно объединить в одно большое с помощью следующих операторов: -+ &&  лоrическое и. Лоrическо е выражение вернет tr ие ТОЛЬКО В случ ае, если оба подвыражения вернут tr ие. Пример: std::cout« (10 == 101 && (5 ,= 31 « std: : end1; / / 1 (truel std::cout« (10 == 101 && (5 == 31 « std: : end1; / / о (fa1se 1 -+ 1 1  лоrическое ИЛИ Лоrическо е выражение вернет tr ие, если хотя бы одно из подвыражений вернет t rue. Следует учитывать, что если подвыражение вернет значение true, то следующие подвыражения вычисляться не будут. Например, в лоrическо м выражении f 1 (1 1 1 f 2 (1 1 1 f3 (1 функция f2 (1 будет вызвана только если функция f 1 (1 вернет fa1s е, а функция f 3 (1 будет вызвана только если функц ии f 1 (1 и f 2 (1 вернут f a1s е. Пример использования оператора: std: :cout« (10 == 101 11 (5 ,= 31 «std::end1; // 1 (truel std::cout« (10 == 101 11 (5 == 31 « std: : end1; / / 1 (truel Результаты выполнения операторов && и 1 1 показаны в табл. 3.1. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  10  1712.10 ТаблlШp 3.1. Операторы && u 11  ь  &&Ь lIb true true true true true fals е false true false true false true false fals е false false Прпорптет выполненпя операторов Вс е операторы выполняются в порядке приоритета (табл. 3.2). Вначале вычисляется выражение, в котором оператор имеет наивысший приоритет, а затем выражение с меньшим приоритетом. Например, выражение с оператором умножения будет выполнено раньше выражения с оператором сложения, так как приоритет оператора умножения выше. Если приоритет операторов одинаковый, то используется ПОРЯДОК вычисления, определенный для KOHкpeTHoro оператора. Операторы присваивания и унарные операторы выполняются справа налево. Мате матические, побитовые и операторы сравнения, а также оператор запятая выполняются слева направо. lЬменить последовательность вычисления выражения можно с помощью круrлых СКО бок Пример: int х = о; х = 5 + 10 * 3 I 2; 11 Умножение > деление > сложение std::cout «х «std::end1; //20 х = (5 + 10) * 3 1 2; 11 Сложение > умножение > деление std::cout «х «std::end1; //22 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 11  1712.10 Таблица 3.2. Прuорuтеты операторов П"IЮl'пrТ ОШ'lЙТОI'Ы 1 (высший) (1 [] . > 2 ++    ! * (разыменование) & (взятие адреса)  (унарный минус) 3 . * >* 4 * / % 5 +  (минус) б « » 7 < > <= >= 8  ,= 9 & (побитовое и) 10 л 11 1 12 && 13 11 14 = *= /= %= += = >>= «= &= .....= 1= 15 (ни:Jший) , (запятая) Оператор ветвлеНIIЯ if Оператор ветвления i f позволяет в зависимости от значения лоrиче CKoro выражения выполнить отдельный блок проrраммы или наоборот не выполнять ero. Оператор имеет следующи й формат if «Лоrическое выражение>1 <Б ло к, ВЫПО лняе:м:ый е с ли ус ло вие ис тинна> { [еЬе { <Б ло к, ВЫПО лняе:м:ый е с ли ус ло вие ло;:n:rо> Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  12  1712.10 {] Если лоrическое выражение возвращает значение tr ие (истина), то выполняются инструкции, расположенные внутри фиrурных скоб ок, сразу после оператора Н. Если лоrическое выражение возвращает значение false (ложь), ТО ВЫПОЛНЯЮТСЯ инструкции после ключевоrо слова else. БлОК els е является нео6язательным. Допускается не указыв ать фиrурные скобки, если блоки состоят из одной инструкции. В каче стве примера проверим ЧИСЛО, введенное пользователем, на четность и выведем с оответствующее сообщение (листинr 3.2). I .1IИСТIПП 3.2. Проверкn ЧИСJm lffi чеТIЮС ТЪ #include <iostream> #include <clocale> int main (1 int х = о; std::setlocale(LCALL, std: : cout « rrВведите rrRussian  Russia. 1251 rr) ; число: ". , std: : cin » Х; if ('std: :cin.good(11 std: : cout « std:: endl « std:: cin.clear (); std: : cin. ignore (255, I\n 1) rrBbl ввели не ЧИСЛО rr « std:: endl; 11 Сбрасываем флаr ошибки .get(l; e1se { if (х % 2 == 01 std:: cout « х « rr  четное число,r « std:: endl; else std: : cout « х « rr  нечетное число" « std:: endl; std: :cin.ignore (255, I\n l ) .get (); return о; { Как видно из при мера, один оператор ветвления можно вложить в друrой. Первый оператор if проверяет отсутствие ошибки при вводе числа. Метод go od (1 возвращает лоrическое значение tr ие, если ошибок не произошло, или значение false  в Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  13  1712.10 противном случае. Обратите внимание на то, что лоrиче ское выражение не содержит операторов сравнения (кроме оператора', который инвертирует значение): if ('std: :cin.good(11 Проверка соотвеТС1БИЯ условия значению t rue ПРОИЗВОДИТСЯ по умолчанию. Так как при ошибке метод goo d () вернет значение fals е, следовательно условие ! fal.se tr ие будет ИСТИННЫМ. ЭТО лоrическое выражение можно было записать так: if (std:: cin. good (1 == falsel или так: if (std:: cin. good (1 ,= truel Однако подобные проверки в этом случае являются излишними. Достаточно указ ать название функции и при необходимости инвертировать значение. Если ошибки при вводе числа нет, то выполняется блок else. В этом блоке нахОДИТСЯ вложенный оператор ветвления, который проверяет число на четность. В зависимости от условия х % 2 == О ВЫВОДИТСЯ соответСТВJ'lOще е сообщение. Если число делится на 2 без остатка, то оператор % вернет значение О, в противном случае  число 1. Обратите внимание на то, что оператор ветвления не содержит фиrурных скобок: if (х % 2 == 01 std: : cout « х « rr  четное число rr « std:: endl; else std: : cout « х « r,  нечетное число" « std:: endl; std: :cin.ignore (255, I\n l ) .get (); в этом случае считается, что внутри блока содержится только одна инструкция. Поэтому последняя инструкц ия к блоку e1s е не относится. Она буд ет выполнена в любом случае, вне зависимости от условия. Чтобы это сделать наrлядным, перед инструкциями, расположенными внутри блока, добавлено одинаковое количество пробелов. Если записать следующи м образо м, то ничеrо не изменится: if (х % 2 == 01 std:: cout « х « "  четное число" « std:: endl; else std:: cout « х « "  нечетное число" « std:: endl; std: :cin.ignore (255, I\n l ) .get (); Однако в дальнейшем разбираться в таком коде будет неудобно. Поэтому перед инструкциями внутри блока всеrда следует размещать одинаковый отступ. В качестве отступ а можно использовать пробелы или символ табуляции. При использовани пробелов размер отступа равняется трем или четырем пробелам для блока первоrо Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  14  1712.10 ур овня. Для вложенных блоков количество пробелов умн ожают на ур овень вложенности. Если для блока первоrо уровня вложенности использовалось три пробела, то ДЛЯ блока BToporo ур ОВНЯ вложенности ДОЛЖНО использоваться шесть пробелов, ДЛЯ тpenero уровня  девять пробелов и т. д. В одной проrpамме не следует использовать и пробелы и табуляцию в качестве отступа. Необходимо выбрать чтото одно и пользоваться этим во всей проrpамме. Если блок состоит из нескольких инструкц ий, то следует указать фиrурны е скобки. Существует несколько стипей размещения скобок в операторе Н: / / Стиль 1 if «Лоrическое ЕЫражение>1 // Инструкции e1se { // Инструкции { / / Стиль 2 if «Лоrическое ЕЫражение>1 // Инструкции e1se { // Инструкции { / / Стиль 3 if «Лоrическое выражение» // Инструкции else // Инструкции Мноrие проrpам:мисты СЧИТaIOТ Стиль 3 наиболее прие:мrIе МЫМ, так как ОТКРЫВaIOщая и закрывающая ско бки расположены дрyr под дрyrом. На мой же взrляд образуются лишние пустые строки. Так как размеры экрана orp аничены, при наличии пустой строки на экр ан помещается меньше кода и ПРИХОДИТСЯ чаще пользоваться полосой про крутки. Если размещать инструкции с равным отступом, то блок кода выделяется визуально и следить за положением Ф иryрных скобок просто излишне. Тем более, что редактор кода Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  15  1712.10 позволяет подсвешть парные скобки. Какой СТ1lЛЬ использовать, зависит ОТ личноrо предпочтения проrp аммиста или от правил о формпения кода, принятых в определенной фирме. lлавное, чтобы стиль оформпения внутри одной проrpаммы был одинаковым. В этой книrе мы будем пользоваться Стилем 1. В листинrе 3.2 при вложении операторов мы воспольз овались слеДJ'lOщей схемой: if «Условие 1» / / Ине трукции e1se { if «Условие 2» // Инструкции e1se { // Инструкции Чтобы проверить несколько уел овий эту схему можно изменить так: if «Условие 1» / / <Блок 1> else if «Условие 2» / / <Блок 2 > { 11 ... Фраrмент опущен ... else if «Условие М» / / <Блок N> e1se { 11 <Блок else> Если <Условие 1> ИСТ1lННО, ТО выполняется <Блок 1>, а и все остальные условия про пускаются. Если <Условие 1> ложно, то проверяется <Условие 2>. Если <Условие 2> истинно, то выполняется <Блок 2>, а все остальные условия про пускаются. Если <Условие 2> ЛОЖНО, ТО точно также проверя::ются остальные Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  16  1712.10 условия. Если все условия ЛОЖНЫ, то выполняется <Блок else>. В качестве примера о пределим какое число от О до 2 ввел пользователь (листинr 3.3). I .1IИСТIПП 3.3. Проверкn нескольких ).С ЛОВlIЙ # include <iostream > #include <clocale> int main (1 int х = о; std: : setlocale (LC ALL, rrRussian  Russia. 1251 rr) ; std: : cout « rrВведите число ОТ О до 2: rr; std: : cin » Х; if ('std: :cin.good(11 std:: cout « std:: endl « rrBbl ввели не число,r « std:: endl; std::cin.clear (); 11 Сбрасываем флаr ошибки e1se if (х == 01 std:: cout « rrBbl ввели число orr « std:: endl; e1se if (х == 11 std: : cout « rrBbl ввели число 1 rr « std:: endl; e1se if (х == 21 std: : cout « rrBbl ввели число 2 rr « std:: endl; e1se { std: : cout « rrBbl ввели друrое число rr « std:: endl; std: : cout « rr x = rr « х « std:: endl; std: :cin.ignore (255, I\n l ) .get (); return о; Оператор ?: Для проверки усл овия вместо оператора if можно использ оватъ оператор? : . Оператор имеет следующий фор мат Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  17  1712.10 <Лоrическое выражение> ? <Выражение если Истина> <Выр аже ние е с ли Ло;:n. > ; Если лоrиче ское выражение возвращает значение tr ие, то выполняется выражение, расположенное после вопросительноrо :знака. Если лоrиче ское выражение возвращает значение false, то выполняется выражение, расположенное после двоеточия. Результат выполнения выражений истановится результатом выполнения оператора. При мер проверки числа на четность и вывода результата: <Переменная> int х = 10; std: : cout « х « ((х % 2 == О) ? rr  четное число,r : rr  нечетное число"); Обратите внимание на то, что в качестве операндов указыв аются именно выражения, а не инструкции. Кроме Toro, выражения обязательно должны возвращать како елибо значение. Так как оператор возвращает 'Значение, ero можно использовать внутри выражений: int х, У; х о. , у 3 О + 10 / (' х ? 1 : х 1 ; std::cout «у« std::endl; х = 2; у = 3 О + 10 / (' х ? 1 : х 1 ; / / 3 О + 10 / 2 std::cout «у« std::end1; //35 В качестве операнда можно указать функцию, которая возвращает значение: int func1 (int хl std: : cout « х « "  четное число" « std:: endl; / / 3 О + 10 / 1 // 40 return о; int func2 (int х 1 std: : cout « х « "  нечетное число" « std:: endl; return о; { 11 ... Фрarмент опущен int х = 10; (х % 2 == 01 ? func1 (хl : func2 (хl ; Как видно из примера, значение, возвращаемое оператором, можно проиrнорировать. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  18  1712.10 Оператор выбора fЛ1-'itсll, Оператор выбора swit ch имеет следующий Ф ормат: switch «Выражение>1 { case <Константа 1>: <Ине трукции> break; [ .. . case <Константа М>: <Ине трукции> break; ] defau1t : <Ине трукции> ] Вме СТО условия оператор swi tc h принимает выражение. В зависимосТ1l ОТ значения выражения выполняется один из блоков case, В котором указано это значение. Значением выражения ДОЛЖНО быть целое число или символ. Если НИ одно из значений не описано в блоках case, то выполняется блок defau1t (если он указан). Обратите внимание на то, что зн ачения в блоках case не MOryт иметь одинаковые константы. Пример использования оператора swit с h приведен в листинrе 3.4. I-тшст IПП' 3.4. Не поль ЗОВ;[I mre опер tlTop;[l swi t с! h #include <iostream> #include <clocale> int main (1 int 05 = о; std: : setlocale (LC ALL, rrRussian  Russia. 1251 rr) ; std:: cout « rrкакой операционной системой вы пользуетесь?\ n\ XP\n\ Vista\n\ 1  Windows 2 3 4  Windows  Windows 7\ n\  Дрyrая\n\n\ Ввите ЧИСЛО, соответствующее ответу: std: : cin » 05; ". , Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  19  1712.10 if ('std: :cin.good(11 std:: cout « std:: endl « rrBbl ввели не число,r « std:: endl; std::cin.clear (); 11 Сбрасываем флаr ошибки std: : cin. ignore (255, I\n 1) . get () ; return о; std::cout «std::endl; switch (osl case 1: std: : cout « rrBbl выбрали  Windows Xprr; break; case 2: std: : cout « rrBbl выбрали  Windows Vista rr ; break; case 3: std: : cout « rrBbl выбрали  Windows 7 rr ; break; case 4: std: : cout « rrBbl :ЕЫбрали  Друrая rr ; break; defau1t : st d: : с о ut < < rrмы не СМО I" ли опр ед е лить В9:lIIY опе рационную rr « rrсистемуrr; std::cout «std::endl; std: :cin.ignore (255, I\n l ) .get (); return о; { Как видно из примера, в конце каждоrо блока с ase указ ан оператор bre ak. Этот оператор позволяет досрочно ВЫЙТ1l из оператора выбора swi tc h. Если не указ ать оператор bre ak, то будет выполняться следJ'lOЩИЙ блок case вне зависимосТ1l ОТ указ аииоrо значения. В некоторых случаях это может быть полезным. Например, можно выполнить одни и те же инструкции при разных значениях, разместив инструкции в конце диапазона значений. Пример: switch (ch 1 case I а I : Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  20  1712.10 case I Ь I : case I С I : std: : cout « rra, Ь или c rr ; break; case I d I : std: : cout « rrтолько d rr; ЦПКЛ fm' Операторы ЦИКЛОВ ПОЗВОЛЯЮТ ВЫПОЛНИТЬ ОДНИ И те же инструкции MHoroкpaTHO. Предп оложим, нужно вывести все числа от 1 до 10 О по одному на строке. Обычным способом пришлось бы писать 100 строк кода: std::cout « 1 «std::endl; std::cout «2 «std::endl; std::cout « 100 «std::endl; С ПОМОЩЬЮ ЦИКЛОВ то ж е деЙС1Бие можно выполнить ОДНОЙ строкой кода: for (int i=l; i<=100; ++i) std::cout «i« std::endl; ЦИКЛ for используется для выполнения выражений определенное число раз. Цикл имеет следующий фор мат for «Начальное значение>; <Условие>; <Приращение» <Ине трукции> Параметры имеют следующие значения: -+ <Начальное значение>  присваивает переменнойсчетчику начальное значение; -+ <Условие>  содержит лоrическое выражение. Пока лоrическое выражение возвращает значение t rue, ВЫПОЛНЯЮТСЯ инструкции внутри цикла; -+ <Приращение>  задает изменение переменнойсчетчика на каждой итерации. Последовательность работы цикла fo r: 1. Переменнойсчетчику присваивается начальное значение. 2. Проверяется усл овие, если оно ИСТ1lнно, выполняются выражения внутри цикла, а в ПРОТ1lвном случае выполнение цикла завершается. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  21  1712.10 3. Переменнаясчетчик изменяется на величину, указаннJ'lO в <Прираще ние >. 4. Переход к п. 2. Пере меннаясчетчик может быть объявлена как вне цикла fo r, так и в параметре <Начально е з наче ние>. Если переменная объявлена в параметре, ТО она 6уд ет видна только внутри цикла. Кроме Toro, допускается объявить переменную вне цикла и сразу присвоить ей начальное значение. В этом случае параметр <Началь ное значение> можно оставить пустым. Пример: int i; 11 Объявление вне цикла for (i=l; i-:::=20; ++i) std::cout «i« std::endl; { 11 Переменная i видна вне цикла std::cout «i« std::end1; //21 11 Объявление внутри цикла for (int j=l; j<=20; ++jl std::cout «j «std::endl; { 11 Переменная j НЕ видна вне цикла int k = 1; 11 Инициализация вне цикла for (; k<=2 о; ++kl std::cout «k« std::endl; ЦИКЛ выполняется ДО тех пор, пока <Условие> не вернет f als е. Если это не произойдет, то цикл будет бесконечным. Лоrическое выражение, указ анное в параметре <Условие>, вычисляется на каждой итерации. Поэтому, если внутри лоrическоrо выражения про изводятся какиели60 вычисления и значение не изменяется внутри цикла, то вычисление следует вынести в параметр <Начальное значение>. В этом случае вычисление указывается после присваивания значения переменнойсчетчику через запятую. Пример: for (int i=l, j=10+30; i<=j; ++i) std::cout «i« std::endl; Выраж ение, указ анное в параметр е <Прираще ние >, может не только увеличивать значение переменнойсчетчика, но и уменьшать ero. Кроме Toro, значение может изменяться на любую величину. Пример : Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  22  1712.10 11 ВЫВОДИМ числа от 100 до 1 for (int i=100; i>O; i) std::cout «i« std::endl; { 11 ВЫВОДИМ четные числа от 1 до 100 for (int j=2; j <=100; j +=21 std::cout «j «std::endl; Если переменнаясчетчик изменяется внутри цикла, то выражение в параметре <Прираще ние > можно вообще не указ ывать: for (int i=l; i-:::=10; ) std::cout «i« std::endl; ++i; 11 Приращение Вс е параметры цикла f or и инструкции внутри цикла являются необязательными. Хотя параметры можно не указывать, точки с запятой обязательно ДОЛЖНЫ быть. Если все параметры не указаны, то цикл будет бесконечным. Чтобы выйти из бесконечноrо цикла следует использовать оператор br eak. Пример : ++i; 11 <Начальное значение> 11 Бесконечный ЦИКЛ 11 <Условие> «i« std::endl; // <Приращение> int i = 1; for ( ; ; 1 { if (i<=101 std: : cout e1se { break; 11 Бых од им ИЗ цикла ЦПКЛ }1-'/Ше Выполнение выражений в цикле while продолжается до тех пор, пока лоrическое выражение истинно. Имеет следующи й фор мат <Начальное значение>; while «Условие» <Ине трукции> ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  23  1712.10 <Приращение>; Последовательность работы цикла whi1e: 1. Переменнойсчетчику присваивается начальное значение. 2. Проверяется условие, если оно истинно, выполняются инструкции внутри цикла, иначе выполнение цикла завершается. 3. Переменнаясчетчик изменяется на величину, указаннJ'lO в <Прираще ние >. 4. Переход к пункту 2. Выведем все числа от 1 до 10 О, используя цикл whi1e: int i = 1; while (i<=1001 std::cout «i« std::endl; ++i; 11 <Начальное значение> 11 <Условие> / / < Ине трукции > / / <Прнращение> Внимание! ЕсШl <Прираще ние > не указано, то цИКЛ будет бесконеч:н:ым:. ЦПКЛ {/II... }1-' /Ш е Выполнение выражений в цикле do... while продолжается до тех пор, пока лоrическое выражение истинно. В отличие от цикла while условие проверяется не в начале ЦИЮIа, а в конце. По этой причине инструкции внутри цикла do... while выполнятся минимум один раз. Цикл имеет следующий формат: <Начальное значение>; do <Ине трукции> ; <Приращение>; while «Условие»; Последовательность работы цикла do.. whi1e. 1. Переменнойсчетчику присваивается начальное значение. 2. Выполняются инструкции внутри цикла. 3. Переменнаясчетчик изменяется на величину, указаннJ'lO в <Прираще ние >. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  24  1712.10 4. Проверяется условие, если оно истинно, происходит переход к п. 2, а если нет  выполнение цикла завершается. Выведем все числа от 1 до 10 О, используя цикл do... whi1e: int i = 1; do 11 <Начальное значение> std::cout «i« std::endl; 11 <Инструкции> ++i; 11 <Приращение> whi1e (i<=1001; // <Условие> Внимание! ЕсШl <Прираще ние > не указано, то цИКЛ будет бесконеч:н:ым:. Оператор Сllпипuе. Переход на слеД)lОЩУЮ птерацпю цпкла Оператор сап tinue позволяет перейТ1l к слеДJ'lOщей итерации цикла до завершен ия выполнения всех выражений внутри цикла. В качеС1Бе примера выведем все числа от 1 до 100, кр оме чисел от 5 до 10 включительно: for (int i=l; i-:::=100; ++i) if (i > 4 && i < 11) continue; std::cout «i« std::endl; Оператор bl'eak. Прерыванпе цпкла Оператор bre ak позволяет прерватъ выполнение цикла досрочно. Для примера выведем все числа от 1 до 100 еще одним способом: int i = 1; while (11 { if (i > 1001 break; std::cout «i« std::endl; ++i; Здесь мы в условии указали значение 1. В этом случае инструкции внутри цикпа будут выполняться бесконечно. Однако использование оператора bre ak прерывает ero выполнение, как только 100 строк уже напечатано. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  25  1712.10 Обратите внимание Опер ат ар Ь r е ak пр ерыв ает выполнени е цикла, а не пр осраммы, то есть дзле е будет выполнена нис трукция, сле дующая сразу за циклом. Бесконечный цикл совместно с оператором br eak удобно использовать ДЛЯ получения неопределенноrо заранее количества данных от пользователя. В кач естве примера просуммируем неопределенное количество целых чисел (листинr 3.5). -Тшст IПП' 3.5. С:'r'1'rПrmp OBnIOre нео:np едеrnшro ro КОJШЧ'! CTB;[I чисел #include <iostream> #include <clocale> int main (1 int х = О, summa = о; std: : setlocale (LC  ALL, rrRussian  Russia. 1251 rr) ; std: : cout « rrВведите число О для получения результата,r « std:: endl; for ( ; std: : cout « rrВведите число: std: : cin » Х; if ('std: :cin.good(11 std: : cout « rrBbl ввели не число! rr « ". , std::cin.c1ear(l; // std::cin.ignore(255, continue; Сбрасываем I\n 1); флar std: : endl; ошиб ки if (! х) break; summa += Х; std: : cout « rrCyммa чисел равна: rr « s'l.1tLl1Lla « std:: endl; std: :cin.ignore (255, I\n l ) .get (); return о; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  26  1712.10 Оператор goto с помощью оператора безусловноrо перехода go to можно передать управление в любое место проrpаммы. Оператор имеет следующий фор мат go to <Ме тка> ; Значение в параметре <Метка> должно быть допустимым иденти фикатор ом. Место в проrpамме, в которо е передается управление, помечается одноименной меткой, после которой указывается двоеточие. В качестве примера имитируем цикл и выведем числа от 1 до 100: int i = 1; BLOCK  START: { if (i > 1001 goto BLOCKEND; std::cout «i« std::endl; ++i; goto BLOCK  START; BLOCK  END : ; Как видно из примера, фиryрные скобки можно использовать не только применительно к условным операторам, циклам, функциям, но и как отдельную конструкцию. Фрarмент кода, заключенный в фиryрные скобки, называется блоком. Переменные, объявленные внутри блока видны только в пределах блока. Совет Следу ет из б era ть исп ОЛ:ЬЗ ОБ ания опер ат ар а 9 о t о, так как er о пр :им:енени е дела ет пр осрамму слишком запутанно й и мож ет прив ести к не ожиданным р ""уль та там. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  2  1712.10 в языке С++ практически все элементарные Т1IПЫ данных (ь 001, char, wchar t, ln t, float и double) являются числовыми. Тип bool может принимать только значения 1 и О, которые cooweTCТEJ'!OT константам true и f alse Типы char и wc har t содерж ат КОД символа, а не сам символ. Поэтому значения этих типов можно использовать в одном выражении вме сте со значениями, имеющими типы int, f 10 at и do ub le. Пример: boo1 а = true; // 1 char ch = I w 1; 11 119 std::cout « (а + ch + 101 «std::end1; // 130 Для хр анения целых чисел предназначен тип in t. Диапазон значений типа in t зависит от разрядности операционной системы. В 1 ббитной операционной системе диапазон от  3 2 768 до 32 767. В 32битной операционной системе диапазон от  2 14 7 483 648 до 2 147 483 647. С помощью ключевых слов sho rt, 10 ng и 10 ng 10ng можно указ ать точный размер типа int. При использовании этих ключевых слов тип in t подразумевается по умолчанию, поэтому ero можно не указывать. Тип shor t занимает 2 байта (диапазон от 3 2 768 до 32 767), тип 10ng  4 байта (диапазон от  2 14 7 483 648 до 2 147 483 647), а тип 10ng 10ng занимает 8 байт (диапазон значений от 9 223 372 036 854 775 808 до 9 223 372 036 854 775 807). В VC++ вместо типов shor t, long и long 10 ng МОЖНО использовать типы int 16, in t3 2 и ln t 6 4 соответственно (перед типом указано два символа подчеркивания) По умолчанию целочисленные Т1Iпы являются знаковы:ми. Знак числа хранится в старшем бите: о соответствует положительному числу, а 1  отрицательному. С помощью ключевоrо слова unsigne d можно указать, что число является только положительным. Тип uns igne d s hor t может содержать числа в диапазон е от О до 65 535, тип unsigned 10 ng  от О до 4 294 967 295, а тип unsigned 10ng 10 ng  от О до 18 446 744 073 709 551 615. При преобразовании значения из типа signed в Т1Iп unsigned следует учитывать, что знаковый бит (если число отрицательное, то бит содержит значение 1) может станет причиной очень больших чисел, так как старший бит у типа unsigned не содержит признака знака: int х = 1; std::cout « (unsigned intlx «std::end1; //4294967295 Целочи сленное значение задается в десятичной, восьмеричной или ше стнадцатричной форме. В осьмеричные числа начинаются с нуля и содержат цифры от О до 7. Шестнадцатеричные числа начинаются с комбинации символов Ох (или ох) и Moryт Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  3  1712.10 содержать числа от О до 9 и букв ы от А до F (реrистр букв не имеет значения). Восьмеричные и ше стнадцатричные значения прео6разJ'lOТСЯ в десятичное значение. Пример: 11 Д=сятичное значение 11 Восьмеричное значение z = Ох77; 11 Шестнадцатеричное значение По умолчанию целочисленные константы имеют тип signed int. Если необходимо изменить тип на дрyrой, то после числа указ ываются следующие буквы: -+ L (или 1)  тип 10 ng int. Пример указания значения: 10L; -+ u (или и)  тип unsigned in t. Пример указ ания значения: 10 u; -+ если буквы u и L указ аны одновременно, то тип будет unsigned 10 ng int. Пример указ ания значения: 10 UL. ДЛЯ хранения вещественных чисел предназначены типы f loa t и do uble. Вещественное число может содержать точку и (или) экспоненту, начинающую ся с буквы Е (реrистр не имеет значения): float х, У; double z, k; х = 20.0; У = 12 .lе5; z = . 123; k = 47 .E5; ПО умолчанию вещественные константы имеют тип doub le. Если необходимо изменить тип на дрyrой, то после числа указ ываются следующие буквы: -+ F (или f)  тип f 10a t. Пример указания значения: 12. 3 f; -+ u (или и)  тип 10ng douk1e. Значение должно содержать точку и (или) экспоненту, иначе тип буд ет 10ng int. Пример указания значения: 12. 3L. При выполнении операций над вещественными числами следует учитывать оrpаничения точности вычислений. Например, результат следующей инструкции может показ аться странным: std::cout « (0.30.10.10.11 «std::end1; // 2.77556e017 Ожидаемым был бы результат О. О, но как видно из примера мы получили совсем друrой результат (2 .77 55 6e 017). Листинrи на странице http://unicros s.narod.ru/cpp/ int х, у, х = 119; У = 0167; "' , 
@Прохоре,ю/С НА, 2010 '.  4  1712.10 Если в выражении используются числа, имеющие разный тип данных, то тип результата выражения будет с оответствовать наиболее сложному типу. Например, если ПРОИЗВОДИТСЯ сложение переменной, имеющей тип int, с переменной имеющей Т1IП do ub le, то целое число будет автоматически прео6разовано в вещественное. Результато м этоrо выражения буд ет значение, имеющее тип douk 1e. Однако, если результат выражения присваивается переменной типа int, ТО тип do ub le будет преобразован в тип int (при этом компилятор выведет предупрежд aIOще е сообщение о возможной потере данных): int х = 10, У = о; douk1e z = 12.5; У = х + z; std: : cout « у « std:: end1; / / 22 (тип intl std::cout « (х + "l «std::end1; //22.5 (тип douk1el l\Iатеl\Iaтпческпе константы в VC++ в зarоловочном файле math.h определены следующи е макросы, содержащие з н ач е н ия мате матич е ских к О н стаит: -+ м Р I  число пп. Определение макроса: #define М PI 3.14159265358979323846 -+ м  Р I 2  значение выражения р l/2 Определение макроса #define М PI 2 1.57079632679489661923 -+ м  Р I 4  значение выражения р l/ 4 Определение макроса #define М PI 4 0.785398163397448309616 -+ MlPI значение выражения l/pi. Определение макроса: #define М 1 PI 0.318309886183790671538 -+ M2PI значение выражения 2/pi. Определение макроса: #define М 2 PI 0.636619772367581343076 -+ м  Е  значение константы е. Определение макроса: #define М Е 2.71828182845904523536 -+ м  LOG2 Е  значение выражения 10 g2 (е 1 . Определение макроса: #define М LOG2E 1.44269504088896340736 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  5  1712.10 -+ MLOG10E значениевыражения 10g10 (el. Определение макроса: #define М LOG10E 0.434294481903251827651 -+ М  LN2  значение выражения 1n (21 . Определение макроса: #define М LN2 0.693147180559945309417 -+ М  LN 10  значение выражения 1n (1 О 1 . Определение макро са: #define М LN10 2.30258509299404568402 -+ М  2  SQRTP I  значение выражения 2/ sqr t (р il . Определение макр оса: #define М 2 SQRTPI 1.12837916709551257390 -+ М  SQRT2  значение выражения sqrt (2 1 . Определение макроса: #define М SQRT2 1.41421356237309504880 -+ М  SQRT 1 2  значение выражения 1/ sqrt (2 1 Определение макроса #define М SQRT1 2 0.707106781186547524401 Прежде чем использовать константы необходимо перед подключением файла math.h определить макрос с названием USE МАТН D EF I ЫЕ S. Пример вывода значения констант приведен в листинrе 4.1. -ТШСТIПП' 4.1. ВЫВОД ЗlffiчеlШЙ I'rrnтеI'rЮТИЧ?!СКI'I:r{ КОНСПIIП #include <iostream> #define USE МАТН DEFINES #inc1ude <math. h> int main (1 std::cout «MPI «std::endl; std::cout «ME «std::endl; std: : cin. get (1 ; return о; / / 3. 14159 // 2.71828 Основные ФУНКЦIIII для работы с ЧIIСШll\Ш Перечислим основные функции для работы с числами: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  б  1712.10 -+ ak s (1  возвращает абсолютное значение. Прототипы Функц ии: #nclude <cstdlb> int abs (int Х); 10ng aks (long XI; 10ng 10ng abs (long 10ng XI; #incl ude <cmat h> f10at aks (f 10at XI; douk1e abs(double XI; 10 ng do uk 1e aks (long douk 1e XI; Функция aks (1 для типа 10ng вызывает функцию 1aks (1 , для типа 10 ng 10ng  11aks (1, для типа f10at  fabsf (1, для типа douk1e  faks (1 , а для типа 10ng do uk1e  fak sl (1 . Пример : std: : cout « std: : abs (11 «std:: end1; / / 1 -+ pow ()  ВОЗВОДИТ число Х в степень У. В случае переполнения возникает ошибка выхода з а пределы допустимых значений. Прототипы функции: #incl ude <cmat h> f 10at pow (f 10at Х, int YI; f 10at pow (f 10at Х, f10at YI; do uk1e pow(double Х, int YI; do uk1e pow(double Х, douk 1e YI; 10ng do uk 1e pow(long douk 1e Х, int YI; 10ng do uk 1e pow(long douk 1e Х, 10ng do uk 1e YI; Пример: std: : cout « std: : pow (10. о, 21 « std:: end1; / / 100 std: :cout « std: :pow(3.0, 3.01 «std: :end1; // 27 -+ sqrt (1  квадратный корень. Прототипы функции: # inc lude <cmat h> f10at sqrt (f1oat XI; douk1e sqrt (douk1e XI; 10ng douk1e sqrt (long douk1e XI; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  7  1712.10 Функция sqrt (1 для типа f 10 at вызывает функцию sqr tf (1 , а для типа 10 ng do uk1e  sqr t1 (1 . Пример использования функции: std: : cout « std: : sqr t (100. 01 « std:: end1; / / 10 std: : cout « std: : sqrt (25. О 1 «std:: end1; / / 5 -+ ех р (1  экспонента. Прототипы функции: #incl ude <cmat h> f10at ехр (f 10at XI; douk1e exp(double XI; 10 ng do uk 1e ехр (long douk 1e XI; Функция ехр (1 для типа f 10a t вызывает функцию е xpf (1, а для типа 10 ng douk1e  exp1 (1 ; -+ 10 g (1  натуральный лоrари фм. Прототипы функции: #incl ude <cmat h> f10at 10g (f 10at XI; douk1e 10g(double XI; 10 ng do uk 1e 10g (long douk 1e XI; Функция 10g (1 для типа f 10a t вызывает функцию 10gf (1, а для типа 10 ng douk1e  10gl (1 ; -+ 10 g 10 (1  де сятичный лоrарифм. Пр ототипы функции: # inc lude <cmat h> f10at 10g10 (f 10at XI; do uk1e 10gl О (double XI; 10 ng do uk 1e 10g 10 (long double XI; Функция 10g 10 (1 для типа f 10a t вызывает функцию 10g 10 f ( 1 , а для типа 10ng douk1e  10g101 (1 ; -+ fmod (1  остаток от деления. Прототипы функции: #incl ude <cmat h> f10at fmod (f1oat Х, f10at YI; douk1e fmod (douk1e Х, douk1e YI; 10ng douk1e fmod (long douk1e Х, 10ng double YI; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  8  1712.10 Функция fmod (1 для типа f 10 at вызывает функцию fmo df (1 , а для типа 10 ng do uk1e  fmo d1 (1 . Пример использования функции: std: : cout « std: : fmod (100. О, 9.01 «std:: end1; / / 1 std: : cout « std: : fmod (100. О, 10. О 1 « std:: end1; / / о -+ то df (1  разделяет вещественное число Х на целую и дробную части. В качестве значения функция возвращает дро бную часть. Целая часть сохраняется в переменной, адрес котор ой передан во втором параметре. Прототипы функции: # inc lude <cmat h> f10at modf (f1oat Х, f10at *YI; do uk1e modf (do uk 1e Х, do uk 1e * УI ; 10ng douk1e modf (long douk1e Х, 10ng double *YI; Функция то df (1 для типа f 10 at вызывает функцию mod ff (1 , а для типа 10 ng do uk1e  mod f 1 (1 . Пример использования функции: double х = 0.0; std: : cout « std: :modf (12.5, &х) « std:: endl; std::cout « х « std::endl; / / 0.5 / / 12 -+ di v (1  возвращает структуру из двух полей: quo t (результат целочисленноrо деления Х / У), r ет (остаток от дел ения Х % У). Прототипы функции: #include <cstdlib> divt div (int Х, int У); 1divt div(long Х, 10ng YI; 11dlv t dlV (long 10ng Х, 10ng 10ng YI; Объявления структур: typedef struct div t int quot; int rem; } divt; typedef struct ldiv t 10 ng quot; long rem; ldiv t; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  9  1712.10 typedef struct 11div t 10ng 10ng quot; 10ng 10ng rem; { 11div t. , Функция div (1 для типа 10ng вызывает Функц шо 1div (1 , а для типа 10 ng 10ng  11div ( 1 . Пример использования функции: divt d; d = std:: div( 13, 21; std::cout « d.quot « std::endl; std::cout « d.rem « std: :endl; // 6 // 1 13 / 2 13 % 2 Окр)тленпе чпсел Для окрyrления чисел предназначены следующи е функции: -+ се i1 (1  возвращает значение, окруrленное до ближайшеrо большеrо значения. Прототипы функции: #incl ude <cmat h> f10at cei1 (f1oat XI; douk1e cei1 (douk1e XI; 10ng douk1e cei1 (long douk1e XI; Функция се i1 (1 для типа f 10 at вызывает функцию се i1 f ( 1 , а для типа 10ng do uk1e  cei11 (1 . Пример использования функции: std: : cout « std: :cei1 (1. 491 « std: :endl; // 2 std: : cout « std: :cei1(1.51 « std: : endl; // 2 std: : cout « std: :cei1(1.511 « std: :endl; // 2 -+ f 100 r (1  зн ачение, окрyrл енное до ближайшеrо меньшеrо значения. Прототипы функции: #incl ude <cmat h> f10at f100r (f 10at XI; do uk1e f 100 r (double XI; 10 ng do uk 1e f 10 or (long double XI; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  10  1712.10 Функция f 10 or (1 для типа f 10a t вызывает функцию f 10 or f ( 1 , а для типа 10ng do uk1e  f 10 or 1 ( 1 . Пример использования функции: std: : cout « std: :f1oor(1.491 « std: : endl; // 1 std: : cout « std: :f1oor(1.51 « std: :endl; // 1 std: : cout « std: :f1oor(1.511 « std: : endl; // 1 Трпrо HOI\IeTp пческпе функцпп в языке С++ доступны следующи е триrонометрические функции: -+ sin (1, cos (1, tan (1  стандартные триrонометрические функции (синус, косинус, TaHreHc). Значение указывается в радианах. Прототипы функций: #incl ude <cmat h> f 10at sin (f loat XI; f 10at cos (f loat XI; f 10at tan (f 10at XI; do uk1e sin(double XI; do uk1e cos(double XI; do uk1e tan(double XI; 10 ng do uk 1e sin (long douk 1e XI; 10 ng do uk 1e cos (long douk 1e XI; 10 ng do uk 1e tan (long douk 1e XI; ДЛЯ типа f 10a t вызываются функц ии s inf ( 1 , с osf (1 и tan f ( 1 , а для типа 10ng douk1e  sin1( 1, cos1( 1 и tan1 (1; -+ asin (1, acos (1, atan (1  обратные триrонометрические функции (арксинус, арккосинус, apIcraHreHc). Значение возвращается в радианах. Прототипы функций: #incl ude <cmat h> f 10at acos (float XI; f 10at asin (float XI; f 10at atan (f1oat XI; do uk1e asin (do ub le XI; do uk1e acos (do ub le XI; do uk1e atan (douk1e XI; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 11  1712.10 10ng do uk 1e acos (long do uk 1e XI; 10ng do uk 1e asin (10 ng do uk 1e XI; 10ng do uk 1e atan (10 ng do uk 1e XI; Для типа f 10at вызываются функции asinf (1 , асо sf (1 и at an f ( 1 , а для типа 10ng douk1e  asin1 (1, acos1 (1 и atan1 (1 . Преобразованпе строкп В чпсло Для преобразования строки в число используются следующие функции: -+ at oi (1  преобразует CCтpOKY в число, имеющее тип int. Прототип функции: #include <cstdlib> int atoi(const char *str); Считывание символов производится пока они соответствуют цифрам. Иными словами, в строке MOryт содержаться не только цифры. Пробельные символы в начале строки иrнорируются. Пример преобразования: std: : cout « std: : atoi (rr2 yr) « std: :endl; // 25 std: : cout « std: :atoi ("2.5") « std: : endl; // 2 std: : cout « std: :atoi(rrSstr rr ) « std: : endl; // 5 std: : cout « std: :atoi(rrS s l0 rr ) « std: : endl; // 5 std: : cout « std: : atoi (rr \t\n 25 rr) « std: : endl; // 25 std: : cout « std: : atoi (rr 25 rr) « std: : endl; // 2 5 std: : cout « std: : atoi (rrstr rr) « std: : endl; // о -+ ato1 (1  преобразует CCтpOKY в число, имеющее тип 10ng. Прототип функции: #include <cstdlib> long atol(const char *Str); Пример преобразования: std: : cout « std: : atol (rr2 yr) «std:: endl; std: : cout « std: : atol (rr \n 2 yr) « std:: endl; std: : cout « std: :atol ("2.5") « std: : endl; std: : cout « std: :atol(rrSstr rr ) « std: : endl; std: : cout « std: :atol(rrS s l0 rr ) « std: : endl; std: : cout « std: : atol (rrstr rr) « std: : endl; // 25 / / 2 5 // 2 / / 5 / / 5 / / о Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  12  1712.10 -+ st rt 01 (1 и st rto u1 (1  преобразуют Ccтpoкy в число, имеюще е тип 10ng и unsigned long соответственно. Прототипы функций: # inc lude <с stdlib > long strtol(const char *Str, char **EndPtr, int Radix); unsigned long strtoul(const char *Str, char **EndPtr, int Radix); Про6ельные символы в начале строки иrнорируются. Считывание символов заканчивается на символе не явля::ющемся записью числа. Указатель на этот символ доступен через параметр Endpt r, е ели он не равен о. В пара метре Radix можно указать систему счисления (число от 2 до 36). Если в параметре Radix задано число О, то система счисления определяется автомашчески. Пример прео6разования: char *р = о. , std: : cout « std: : strtol (rr2 5 rr, о, 01 « std: : endl; // 25 std: : cout « std: : strtol (rr02 yr, о, 01 « std: : endl; // 21 std: : cout « std: : strtol (rrO x 25 rr, о, 01 « std: : endl; // 37 std: : cout « std: :strtol (rrl11 rr , о, 21 « std: : endl; // 7 std: : cout « std: : strtol (rr02 yr, о, 81 « std: : endl; // 21 std: : cout « std: : strtol (rrO x 25 rr, о, 161 « std: : endl; // 37 std: : cout « std: : strtol (rrs s 10 rr, &р, 01 « std: : endl; // 5 std: : cout « р « std: : endl; // s 10 Если в строке нет числа, то возвращается число о. Если ЧИСЛО ВЫХОДИТ за диапазон значений для типа, то значение будет соответствовать минимальному (LONG  М 1М или о) ипи максимальному (LONGМAX ипи ULONGMAX) значению для типа, а переменной errno присваивается значение ERANGE. Чтобы сбросить флаr ошибки следует присвоить значение Опеременной err по. Пример: std: : cout « std: : strtol (rrstr rr , О, О) « std: : endl; std: : cout « std: : strto1 ("99999999999999999", о, 01 « std:: end1; / / 2147483647 (соответствует LONGMAXI // о if (errno Е RANGE 1 std::cout « rrError rr « std: :endl; 11 Error er rno = о; 11 Сб расываем флаr ошиб ки std: : cout « std: : strtol (rr2 5 rr, О, О) «std:: endl; 11 25 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  13  1712.10 if (errno ,= ERANGE 1 std::cout « rrOK rr « std: :endl; 11 ОК -+ at о f (1  преобразует CCтpOKY в число, имеющее тип do uk 1e. Пр ототип функции: #nclude <cstdlb> double atof (const char *string); Пример преобразования: std: : cout « std: : atof (rr2 yr) «std:: endl; 11 25 std: : cout « std: : atof (rr2 .5 rr) « std:: endl; 11 2.5 std: : cout « std: : atof (rr 5 .1str rr) « std:: endl; 11 5.1 std: : cout « std: : atof (rr 5510 rr) « std:: endl; 11 5 std: : cout « std: : atof (rrstr rr) « std:: endl; 11 о -+ st rt od (1  преобразует CCтpOKY в число, имеющее тип douk 1e. Пр ототип функции: #include <cstdlib> double strtod (const char *str, char ** EndPtr) ; Про6ельные символы в начале строки иrнорируются. Считывание символов заканчивается на символе не явля::юще мся записью вещественноrо числа. Указ атель на этот символ доступ ен через параметр Endpt r, если он не равен о. Пример преобразования: char * р = о; std: : cout « std: : strtod (rr \t\n 2 5 rr , 01 « std: : endl; // 25 std: : cout « std: : strtod (rr2 . yr, 01 « std: : endl; // 2.5 std: : cout « std: : strtod ("5. lstr", 01 « std: : endl; // 5.1 std: : cout « std: : strtod ("14. 5e5s 10", &рl « std: : endl; // 1.45е+006 std: : cout « р « std: : endl; // s10 Если в строке нет числа, то возвращается число о. Если число выходит за диапазон значений для типа, то возвращается значение HUGEVAL или HUGEVAL, а переменной errno присваивается значение ERANGE. Чтобы сбросить флаr ошибки следует присвоить значение Опеременной err по. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  14  1712.10 Вс е рассмотренные в этом разделе функции позволяют преобразовать всю Ccтpoкy в число. Если необходимо преобразовать отдельный символ (представляющий число) в соотвеТСТВYIOщее целое число от О ДО g, ТО можно воспользоваться следующим КОДОМ: char ch = 18 1; int n = ch  101; 11 Эквивалентно int n = 56  48; std::cout «n« std::endl; 118 В переменной типа с har хранится код символа, а не сам символ. Символы ОТ 10 I ДО '9' в кодировке АSСП имеют коды от 48 до 57 соответственно. Следовательно, чтобы получить целое число от О ДО 9 достаточно вычесть из текущеrо символа КОД символа 10 I . В качестве еще одноrо примера сохр аним все числа, БстречaIOЩИ еся в CCтpOKe, в целочисленном массиве (листинr 4.2). -ТШСТIПП 4.2. ПреоБР;[lЗОВ;[IIOre сmrmолов Сстроки в отдельные чис..тrn # include <iostream > int main (1 char str[] = "0123456789"; const int SIZE = 10; int arr[SIZE] = {О{, index = о; for (char * p=str; * р; ++р) { 11 Перебираем строку if (*р >= 101 && *р -с= 191) { arr[index] = *р  101; ++index; if (index >= SIZEI break; for (int i=O; i<SIZE; ++i) { 11 ВЫВОДИМ значения std::cout «arr[i] «std::endl; std: : cin. get (1 ; return о; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  15  1712.10 Преобразованпе чпсла в строку Преобразовать значения элементарных типов в CCтpOKY позволяет функция sp r int f ( 1 . Прототип функции: #include <cstdio> int sprintf (char * DstBuf, const char * Format, ...); В параметре F ormat указыв ается строка специальноrо формата. Внутри этой строки можно указать обычные символы и спецификаторы формата, начинающиеся с символа %. Специ фикаторы фор мата совпадают со спецификаторами, используемыми в функции pr in tf (1 (см. раздел "В ывод данных в языке С"). Вместо спецификаторов формата подставля::ются значения, указанные в каче стве парамеТРОБ. Количество спецификатор ов должно совпадать с количеством переданных параметров. Результат записывается в буфер, адрес KOToporo передается в первом параметре (DstBuf). В кач естве значения функция возвращает количество символов, записанных в символьный массив. Пример преобразования целоrо числа в Ccтpoкy: char buf[50]; int х = 100, count = о; count = std:: spr intf (buf, rr %d rr , х); std::cout «buf «std::endl; std::cout «count «std::endl; // 100 // 3 Функция sp r int f ( 1 не производит никакой проверки размера буфер а, возможно переполнение буфер а. В VC++ вместо функции spr in tf ( 1 использовать функц ию spr ln tf s ( 1 . Прототип функции: # include <stdio. h> lnt sprlntf s (char * DstBuf, size t Slze InBytes, const char * Format, ...); п оэто му сл е дует Параметры Ds tB uf и F orma t аналоrичны параметр ам функц ии s pr in tf (1. В параметре Si "е InByte s указывается размер буфер а. В качестве значения функция возвращает количество символов, записанных в символьный массив. Пример преобразования вещественноrо числа в Ccтpoкy: char buf[50]; int count = о; douk1e pi = 3.14159265359; count = sprlntf s (buf, 50, rr I %10. 5f I rr, std::cout «buf «std::end1; // std::cout «count «std::endl; 11 12 pil; 3 . 14159 ' Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  16  1712.10 rенерацпя псевдослучаlIНЫХ чпсел Для rенерации псевдослуч айных чисел используются следующи е функции: -+ rand (1  rенерирует псевдослуч айное число от О до RAND МАХ. Прототип функц ии И определение макр оса RAND  МАХ: #nclude <cstdlb> int rand (void) ; #define RAND МАХ Ox7fff Пример: std: : cout « std: : rand (1 « std: : endl; // 41 std: : cout « std: : rand (1 « std: : endl; // 18467 std: : cout « RAND МАХ « std: : endl; // 32767 Чтобы получить случайное число от О до определенноrо значения, а не до PAND МАХ, следует использовать оператор % для получения остатка от деления. Пример получения числа от О до 10 включительно: std: : cout « std: : rand (1 % 11 « std:: end1; -+ sr and ()  настраивает rеиератор случайных чисел на HOBJ'lO последовательность. В качестве параметр а обычно используется функция time (1 с нулевым указ ателем в каче стве параметра, возвращающая количество секунд, прошедших с 1 января 1970 r. Прототипы функций: #include <cstdlib> void srand(unsigned int Seed); #incl ude <ct ше> time t tirne(time t *Tirne); Пример: std::srand(static cast<unslgned lnt> std: : cout « std: : rand () « std:: endl; Если функция s rand (1 вызвана с одним и тем же параметром, то буд ет rенерировать ся одна и та же последовательность псевдослучайных чисел: std::time(OI 11; std: : srand (1001 ; std: : cout « std: : rand (1 « std:: end1; / / 365 std: : srand (1001 ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 ii  17  171 2.10 std: : cout « std: : rand (1 « std:: end1; / / 365 В качестве примера создадим reHepaTOp паролей произвольной длины (листинr 4.3). Для этоrо добавляем в массив ar r все разрешенные символы, а далее в цикле получаем случайный элемент из массива. Затем записываем СИМВОЛ, который содержит элемент массива, в итоrовый символьный мае сив, адре с первоrо элемента KOToporo передан в кач естве первоrо параметра. В конец символьноrо массива вставляем нулевой символ. Следует учитывать, что символьный массив должен быть минимум на один символ больше, чем количество символов в пароле. I .1IИСТIПП 4.3. reнepnTop Шlролей #include <iostream> #inc1ude <cstd1ik> # inc 1 ude <с time > void passwgenerator(char *pstr, int count char); int main (1 char str[80]; std: : srand (static cast<unslgned lnt> ( std:: time (О) )); passwgenerator(str, 8); std::cout «str «std::endl; 11 Выведет примерно bjreJVue passwgenerator(str, 8); std::cout «str «std::end1; 11 СЕvз3ХС1 passw generator (str, 10); std::cout «str «std::end1; 11 BTJ6rLPPvy std: : cin. get (1 ; return о; void passwgenerator(char * pstr, int count charl const short SIZE = 60; char arr[SIZE] = {Ial, 'Ь 1, IC 1, 'd 1, le 1, 'f 1, Igl, 'h 1,1 i 1, Ij 1, 'k ' , 111, Im l , In l , Ip 1, Iql, Ir 1, IS 1, It 1, lu l , Iv l , Iw l , IX 1, Iyl, 1 Z 1, 'А ' , 'в 1, IC 1, 'D 1, 'Е 1, 'F 1, IG I , IH I , 111, IJI, IK I , 'L 1, 'М ' , IN I , Ip 1, IQI, IR I , 131, IT I , IU I , IV I , IW I , IX I , Iyl, IZ 1, 111, 12 1, 13 1, 141, 151, 161, 171, 181, 1 9 1, 1 Ol}; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  18  1712.10 for (int i=O; i<count char; ++i) { *pstr = arr[std:: rand (1 % SIZE]; ++pstr; *pstr = 1\01; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  2  1712.10 Массив  это нумерованный набор переменных одноrо Т1Iпа. Переменная в массиве называется элементом, а ее позиция в массиве задается индексом. Все элементы массива рас п ол araIOTC я в с ме ж н ых яч е йках п а:мяти. Напр и мер, е ел и о бъявл е н мае с ив из тр ех элементов, имеющих тип long int (занимает 4 байта), то адрес первоrо элемента массива (в 32битной операционной системе) будет ОхО041А040, BToporo  Ох 00 41АО 4 4, а тpenero  О хО 041А04 8. Объем памяти (в байтах), занимаемый мае с ив о М, о пр ед еляется так: <Объем памяти> = sizeof «Тип» * <Количество элементов>   Ооъявленпе п ПНIIЦШlЛпзацпя I\IaCCIma Объявление мас сива выrлядит следующи м образо м: <Тип> <Переменная>[<Количество элементов>]; Пример объявления массива из трех элементов, имеющих тип 10 ng int: 10ng ап [3]; При объявлении элементам массива можно присвоить начальные значения. Для этоrо после объявления указывается оператор =, а далее значения через запятJ'lO внутри фиryрных скобок После закрывающей фиryp ной скобки обязательно указывается точка с запятой. Пример инициализации массива: 10ng ап [3] = {10, 20, 30{; КоличеС1БО значений внутри фиrурных скобок может быть меньше количеС1Ба элементов массива. В этом случае значения присваивaIOТСЯ соответствJ'lOЩИМ элементам с начала массива. Пример: 10ng ап[3] = {10, 20{; В этом при мере первому элементу массива присваивается значение 10, второму  значение 2 О, а третьему элементу будет присвоено значение о. Присвоить всем элементам массива значение О можно так: int arr[15] = {О{; Есл и пр и о бъявл е н ии мас с ив а указ ыв aIOтся нач аль н ы е з н ач е н ия, элементов внутри maдpaTHblX скобок можно не указ ывать. соответствовать количеству значений внутри фиryp ных скоб ок. Пример: то количество Размер будет 10ng ан[] = {10, 20, 30{; Если при объявлении массива начальные значения не указ аны, то: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  3  1712.10 -+ элементам rло6альных мае сивов автоматически присваивается значение о; -+ элементы локальных массивов будут содер жать произвольные значения, так называемый "мусор" Полученпе п ПЗI\Iененпе значенпя элемента масспва 06раще ни е к элементам мае сива осуще ствляется с ПОМОЩЬЮ maдpaTHblX СКО бок, В которых указывается индекс элемента. 06раште внимание на то, что нумерация элементов массива начинается с О, а не с 1, поэтому первый элемент имеет индекс о. С помощью индексов можно присвоить начальные значения элементам массива уже после о бъявл е н ия: 10ng ап [3]; arr[O] = 10; 11 первый элемент имеет индекс О!!! arr [1] = 20; 11 Второй элемент arr[2] = 30; 11 третий элемент Следует учитывать, что проверка выхода указанноrо индекса за пределы диапазона на этапе компиляции не производится. Таким образом, можно перезаписать значение в смежной ячейке па:мяти и тем с амым нарушить работоспособность проrpаммы или даже повредить операционную систему. Помните, что контроль корректности индекса входит в обязанности проrpам:миста. После определения массива выделяется необходимый размер па:мяти, а в переменной сохраняется адре с первоrо элемента массива. При указании индекс а внутри maдpaTHblx ско бок производится вычисление адрес а соотвеТСТВJ'lOщеrо элемента массива. Зная адрес элемента массива можно получить значение или перезаписать ero. Иными словами, с элементами массива можно производить такие же операции, как и с обычными переменными. Пример: 10ng ап[3] = {10, 20, 30{; long х = о; х = ап[1] + 12; arr[2] = х  arr[2]; std: : cout « х « std:: end1; / / 32 std::cout «arr[2] «std::end1; //2 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  4  1712.10 Перебор элеl\Iентов маССIIва Для перебора элементов массива уд обно использовать цикл f or. В первом параметре переменнойсчетчику присваивается значение О (элементы массива нумеруются с нуля), условием продолжения является значение переменнойсчетчика меньше количества элементов массива. В третье м параметре указывается приращение на единицу на каждой итерации цикла. Внутри цикла доступ к элементу осуще ствляется с помощью квадр атных скобок, внутри которых указывается переменнаясчетчик. Пронумеруем все элементы массива, азатем выведем все значения в прямо м И обратном порядке: const short ARR SIZE = 20; int arr[ARRSIZE]; 11 Нумеруем все элементы массива for (int i=O, j=l; i<ARRSIZE; ++i, ++jl arr[i] = j; { 11 ВЫВОД им з наче ния в пр ямом по ряд ке for (int i=O; i<ARR SIZE; ++i) std::cout «arr[i] «std::endl; std::cout « rrrr «std::endl; 11 ВЫВОДИМ значения в обратном порядке for (int j=ARR  S IZE 1; j >=0; j 1 std::cout «arr[j] «std::endl; в этом примере мы объявили количество элементов массива как ПОСТОЯННYIO величину (константа ARR  S I ZE). ЭТО очень удобно, так как размер массива приходится указывать при каждом пере60ре массива. Если количество элементов указ ывать в виде числа, то при изменении размер а массива придется вручную изменять все значения. При использовании константы количество элементов достаточно будет изменить только в одном месте. Чтобы получить количество элементов массива из проrpаммы, необходимо общий размер массива в байтах разделить на размер типа. Получить эти размеры можно с помощью оператора s ize of . Пример определения количества элементов массива: int arr[15] = {О{; std::cout «sizeof arr 1 sizeof (int) «std::endl; 11 15 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  5  1712.10 Цикл fo r всеrда можно заменить циклом whi1e. В качестве примера пронумеруем элементы в обратном порядке, а зате м выведем все значения: const short ARR SIZE = 20; int arr[ARRSIZE]; 11 Нумеруем все элементы int i = О, j = ARRSIZE; while (i<ARRSIZEI arr[i] = j; ++i; j; { 11 ВЫВОДИМ значения массива i = о; while (i<ARRSIZEI std::cout «arr[i] «std::endl; ++i; Доступ к элеl\Iентаl\I маССIIва с помощью указателя После определения массива в переменной сохраняется адрес первоrо элемента. Иными словами, название переменной является указателе м, который ссылается на первый элемент массива. Поэтому доступ к элементу массива мож ет осуществляться как по индексу, указ анному внутри maдpaTHblX скобок, так и с использованием адресной ариф метики. Например, следующие инструкции вывода являются эквивалентными: int arr[3] = {1, 2, 3{; std: : cout « ан[ 1] « std:: end1; / / 2 std::cout «*(arr + 11 «std::end1; //2 std::cout «*(1 + arrl «std::end1; //2 std: : cout « 1 [arr] « std:: end1; / / 2 Последняя инструкция может показать ся странной. Однако, если уч есть, что выражение 1 [ar r] воспринимается компилятором как * (1 + arr), то все встанет на свои места. При указании индекса внутри квадратных ско бок, каждый раз производится вычисление адре са соотвеТСТВJ'lOщеrо элемента массива. Чтобы сделать процесс доступа к элементу массива более эф фективным объявляют указатель и присваивaIOТ ему адрес первоrо элемента. Далее для доступа к элементу просто перемещaIOТ Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  б  1712.10 указ атель на соответствYIOЩИЙ элемент. Пример объявления указателя и присваивания ему адре са первоrо элемента массива: int *р = о; int ап[3] {1, 2, 3 { ; р = arr; Обратите внимание на то, что перед названием массива не указ ывается оператор &, так как название переменной содержит адре с первоrо элемента. Если использовать оператор &, то необходимо дополнительно указать индекс внутри кв адратных скобок: р = &arr[O]; 11 Эквивалентно: р = arr; Таким же образом можно присвоить указателю адре с произвольноrо элемента массива, например, тpenero: р = &arr[2]; 11 Указатель на третий элемент массива Чтобы получить значение элемента, на который ссылается указатель, необходимо произвести операцию разыменования. Для этоrо перед названием указателя добавляется оператор * . Пример: std::cout «*р «std::endl; Указатели часто ИСПОЛЬЗJ'lOТСЯ для пере60ра элементов массива. В качестве примера создади м массив из трех элементов, а затем выведе м значения с помощью цикла for: const short SIZE = 3; int *р = О, arr[SIZE] = {1, 2, 3{; 11 Устанавливаем указатель на первый элемент массива р = arr; 11 Оператор & не указывается! I I for (int i=O; i<SIZE; ++i) std::cout «*р «std::endl; ++р; 11 Перемещаем указатель на слующий элемент р arr; 11 Восстанавливаем положение указателя В первой строке объявляется константа S 1 ZE, в которой сохраняется количество элементов в массиве. Если массив используется часто, то лучше сохранить ero размер как константу, так как количество элементов нужно буд ет указ ывать при каждом переборе массива. Если в каждо м цикле указывать конкретное число, то при изменении размер а массива придется вручную вносить изменения во всех циклах. При объявлении константы достаточно буд ет изменить ее значение один раз при инициализации. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  7  1712.10 В слеДJ'lOщей строке объявляется указатель на тип in t и массив. КоличеС1БО элементов массива задается константой S 1Z Е. При объявлении массив инициализируется начальными значениями. Внутри цикла fo r выводится значение элемента на который сс ьтается указатель, а зате м значение указ ателя увеличивается на единицу (++р;). Обратите внимание на то, что изменяется адрес, а не значение элемента массива При увеличении значения указ ателя используются правипа адресной арифметики, а не правила обычной ариф метики. Увеличение значения указателя на единицу означает, что значение будет увеличено на размер Т1Iпа. Например, если тип in t занимает 4 байта, то при увеличении значения на единицу указатель вместо адреса О хОО 12 FF 30 буд ет содержать адрес Ох 0012 FF 34. Значение увеличипось на 4, а не на 1. В нашем примере вместо двух инструкций внутри цикла можно использовать одну: std::cout «*р++ «std::endl; Выраж ение р++ возвращает текущи й адрес, а затем увеличивает ero на единицу: Символ * позволяет получить доступ к значению элемента по указанному адресу. Последовательность выполнения соответствует слеДJ'lOщей расстановке скобок: std::cout «*(р++) «std::endl; Если скобки расставить так: std::cout « (*р)++ «std::endl; то, вначале будет получен доступ к элементу массива и выведено ero текуще е значение, а затем произведено увеличение значения элемента массива. Перемещение указателя на следующи й элемент не производится. Указатель можно использовать в качестве переменнойсчетчика в цикле for. В этом случае начальным значением будет адрес первоrо элемента массива, а условием продолжения  адрес меньше адреса первоrо элемента плюс количество элементов. Приращение осуществляется аналоrично обычному, только вместо обычной ар и Ф метики пр и ме няется адр е с н ая ар и Ф мети ка. Пр и мер: const short S1ZE = 3; int arr[SIZE] = {1, 2, 3{; for (int *p=arr; p<arr+S1ZE; ++р) std::cout «*р «std::endl; Вывести все значения массива с помощью цикла while и указателя можно так: const short S1ZE = 3; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  8  1712.10 int *р = О, i = SIZE, arr[SIZE] = {1, 2, 3}; Р = arr; while (i > 01 std::cout «*р++ «std::endl; р = arr; l\Iасспвы указателей Указатели можно сохр анять в массиве. При объявлении массива указ ателей и с пользует ся ел едJ'!O щи й с и нтакс и с: <Тип> *<Название массива>[<Количество элементов>]; При мер использования массива указ ателей: int *р[З]; 11 Массив указателей из трех элементов int х = 10, У = 20, z = 30; р[О] = &Х; Р [1] = &у; р[2] = &Z; std: : cout « *р [О] « std: : endl; // 10 std: : cout « *р [1] « std: : endl; // 20 std: : cout « *р [2] « std: : endl; // 30 Дпнаl\Iпческпе масспвы При объявлении массива необходимо задать точное количество элементов. На основе этой ин формации при з алуске проrp аммы автоматически выделяется необходимый объем па:мяти. Иными словами, размер массива необходимо знать ДО выполнения проrpаммы. Во время выполнения проrpаммы увеличить размер существующеrо мае с ив а нельзя. Чтобы произвести увеличение массива во вре:мя выполнения проrpаммы необходимо выделить достаточный объем па:мяти с помощью оператора new, перенести суще ствующие элементы, а лишь затем добавить новые элементы. Управление динамической па:мятью полностью лежит на rшечах проrpаммиста, поэтому после завершения работы с па:мятью необходимо самим возвратить па:мять операционной системе с помощью оператора dele te. Если па:мять не возвратить операционной системе, то УЧ асток па:мяти станет недоступным для дальнейшеrо использования. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  9  1712.10 Подо бные ситуации приводят к утечке памяти. Сделать эти участи опять доступными МОЖНО только после перезarpузки компьютера. Выдел ение памяти под массив производится следующим образом: <Указатель> = new <Тип данных>[<Количество элементов>]; Освободить выделенную память можно так delete [] <Указатель>; Обратите внимание на то, что при освобождении па:мяти количество элементов не указ ыв ается. При выделении па:мяти может возникнуть ситуация нехватки па:мяти. В ранних версиях С++ в этом случае возвращался нулевой указатель. Соrласно новой версии стандарта в случае ошибки оператор new долж ен возбуждать исключение bad a110c (о бъект исключения определ ен в файле new). Обработать это исключение можно с помощью конструкции tr у. . . са t ch. Пример выделения памяти с обраб откой исключения: # inc 1 ude <new> 11 ... Фраrмент опущен const short SIZE = 3; int *р = о; try { р = new int[SIZE]; 11 Размер массива 11 Со=щаем указатель 11 Выделяем память catch (std:: bad  a110c енl std::cout « rrError rr «std::endl; std: : exit (11 ; 11 Выходим при ошибке { р [О] = 1; р [1] = 2; р [2] = 3; for (int i=O; std: : cout 11 ПОльзуемся памятью i<SIZE; ++i) «p[i] «std::end1; { delete [] р; р = о; Выдел ение // // Возвращаем память Обнуляем указатель исключение выполнения памяти производится внутри блока try. Если при этом возникнет Ь ad  a11oc, то управление будет передано в блок cat ch. После инструкций в блоке са tc h управление передается инструкции, Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  10  1712.10 расположенной сразу после блока. Иными словами, компилятор считает, что вы обработали исключение и можно продолжить выполнение проrpаммы. Следует уч итывать, что пользоваться указ ателем после обработки нельзя, поэтому внутри блока са tc h обычно ВЫВОДЯТ сообщение 06 оши 6ке и завершaIOТ выполнение проrpаммы. Если исключение не обработать, то проrpамма аварийно завершится. Если исключение не возникло, ТО инструкции внутри блока са tc h не выполняются. Обратите внимание на то, что определение указателя ПРОИЗВОДИТСЯ вне блока try. Если определение разместить внутри блока, то область видимости переменной будет оrpаничена этим блоком. После выхода из блока переменная автоматически уничтожается, а выделенная память операционной системе не Бозращается. Поэтому, определение указ ателя ДОЛЖНО нахОДИТЬСЯ перед блоком, а не внутри Hero. После использования оператора de1ete указатель попрежнему будет содержать прежний адрес, поэтому указатель принято обнулять. l\IноrОI\Iерные маССIIВЫ Массивы в языке С++ Moryт быть мноrомерными. Объявление MHoroMepHoro массива имеет следующий фор мат <Тип> <Переменная>[<Количество элементов1>]...[<Количество элементов М>]; На практике наиболее часто использJ'loтся двух мерные массивы, позволяющие хранить значения ячеек таблицы, содержаще й определенное количество строк и столбцов. Объявление двухмерноrо массива выrлядит так: <Тип> <Переменная>[<Количество строк>] [<Количество столбцов>]; Пример объявления двухмерноrо массива, содержащеrо две строки и четыре столбца: int arr[2][4]; 11 Две строки из 4x элементов каждая Вс е элементы двухмерноrо массива располarаются в памяти друr за друrом. Вначале элементы первой строки, затем второй и т. д. При инициализации двухмерноrо массива элементы указываются внутри Ф иryрных ско бок через залятую. Пример: int ап[2] [4] = 1, 2, 3, 4, 5, 6, 7, 8 {; Чтобы сделать процесс инициализации нarлядным мы расположили элементы на отдельных строках. Количество элементов на строке совпадает с количеством столбцов Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 11  1712.10 в массиве. Если элементы одной строки разместить внутри фиrурных ско бок, то процесс станет еще нarляднее: int ап [2][ 4] = {1, 2, 3, 4}, {5, 6, 7, 8 { {; Если при объявлении ПРОИЗВОДИТСЯ инициализация, ТО количество строк можно не указыв ать, оно будет определено автоматически: int ап[][4] = { {1, 2, 3, 4}, {5, 6, 7, 8 { {; Получить или задать значение элемента можно указав два индекс а (не забывайте, что нуме рация нач и н ается с нуля): std::cout «arr[O][O] «std::end1; // 1 std::cout «arr[l][O] «std::end1; //5 std: : cout « ан[ 1] [3] « std:: end1; / / 8 Чтобы BЫBecТ1l все значения массива необходимо использовать вложенные циклы. В кач естве примера пронуменуем все элементы массива, а затем выведем все значения: const short ARRROWS = 4; const short ARRCOLS = 5; int i, j, n = 1, arr[ARRROWS][ARRCOLS]; 11 Нумеруем все элементы массива for (i=O; i<ARRROWS; ++il { for (j=O; j<ARRCOLS; ++jl arr[i] [j] = n; ++n; { 11 ВЫВОД им з наче ния for (i=O; i<ARRROWS; ++i) for (j=O; j<ARRCOLS; ++jl std::cout.width(31; std::cout «arr[i][j]; 11 Ширина по л..q Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  12  1712.10 std::cout «std::endl; Вс е элементы MHoroMepHoro массива располarаются в памяти дрyr за друrом. Поэтому ДЛЯ пере60ра массива можно использовать указатель. В качестве примера выведем все элементы двухмерноrо массива с помощью цикла for и указателя: const short RO'Ji,E = 4, COLS = 5; int arr[ROWS] [COLS] = { {l, 2, 3, 4, 5}, {6, 7, 8, 9, 10}, {11, 12, 13, 14, 15 {, {16, 17, 18, 19, 20{ {; for (int *p=arr[O]; p<arr[O]+ROWS*COLS; ++рl std::cout «*р «std::endl; Попск I\ШНПI\НlЛьноrо п макспмальноrо значенпя Чтобы в массиве найти минимальное значение следует присвоить переменной min значение первоrо элемента массива, а затем произвести сравнение с остальными элементами. Если значение текущеrо элемента меньше значения переменной min, ТО присваиваем значение текущеrо элемента переменной min. Чтобы найти максимальное значение следует присвоить переменной тах значение первоrо элемента массива, а зате м произвести сравнение с остальными элементами. Если значение текущеrо элемента больше значения переменной тах, то присваиваем значение текущеrо элемента переменной тах. Пример поиска минимальноrо и максимальноrо значения приведен в листинrе 5.1. .тшст IПП' 5.1. по иск I'rlIПllfllrrnльноrо и I'rrnКСИl'rrnльноrо ЗlffiчеlШЯ #include <iostream> int main (1 const short ARRSIZE = 5; int arr[ARRSIZE] = {2, 5, 6, 1, 3{; int min = arr[O], тах = arr[O]; for (int i=l; i<ARRSIZE; ++i) Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  13  1712.10 if (min > arr[i]) min = arr[i]; if (тах < arr[i] 1 ,"ах = arr[i]; std: : cout « rrmin = " « min « std: : cout « rr max = " « ,"ах « std: : cin. get (1 ; return О. , std: : endl; std: : endl; Сортпровка I\IaCCIma Сортировка массива  это упорядочивание элементов по возрастанию или убыванию значений. Сортировка применяется при выводе значений, а также при подrотовке массива к частому поиску значений. Поиск по отсортированному массиву ПРОИЗВОДИТСЯ rора:здо быстрее, так как не нужно каждый раз просматривать все значения массива. Для упорядочивания элементов массива очень часто применяется метод, называемый пузырьковой сортировкой. При этом методе наименьшее значение как бы Ilвсплывает" в начало массива, а наибольшее значение Ilпоrруж ается ll в конец массива. Сортировка выполняется в несколько ПРОХОДОВ. При каждом проходе последовательно сравНИВaIOтся значения двух элементов, которые расположены рядом. Если значение первоrо элемента больше BToporo, то значения эле ментов меняются местами. Для сортировки массива из пяти эле ментов необходимо максимум четыре проход а и десять сравнений. Если после прохода не было ни одной перестановки, то сортировку можно прервать. В этом случае для сортировки ранее уже отсортированноrо мас сива нужен Bcero один проход. Последовательность сравнения элементов массива при пузырьковой сортировке по возрастанию показана в табл. 5.1, а код проrpаммы приведен в листинrе 5.2. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  14  1712.10 Таблица 5.1. Последователыюс ть сравнен:uя элементов при пузырьковой сортироеке ПрОХОД О IШСНИ<' '3к-1 'Че'1ШЯ 'Э'.т.I'rIe'IПОВ I'r&"l( (ИВ Элеменrы мае сива an[О] arr[l] arr[2] arr[3] arr[4] Начальны е знач ения 10 5 б 1 3 Сравниваются arr[3] и arr[ 4] 10 5 б 1 3 Сравниваются arr[2] и arr[3] 10 5 1 б 3 1 Сравниваются arr[l] и arr[2] 10 1 5 б 3 Сравниваются arr[O] и arr[l] 1 10 5 б 3 Сравниваются arr[3] и arr[ 4] 1 10 5 3 б 2 Сравниваются arr[2] и arr[3] 1 10 3 5 б Сравниваются arr[l] и arr[2] 1 3 10 5 б Сравниваются arr[3] и arr[ 4] 1 3 10 5 б 3 Сравниваются arr[2] и arr[3] 1 3 5 10 б 4 Сравниваются arr[3] и arr[ 4] 1 3 5 б 10 -Тшст IПП 5.2. П:'r"'З ырь КОВ;[IЯ сор тир OBK;[I по возрn СПIIШЮ #include <iostream> int main (1 const short ARRSIZE = 5; int arr[ARRSIZE] = {10, 5, 6, 1, 3{; int j = О, tmp = О, k = ARRSIZE  2; bool isswap = false; for (int i=O; i-:::=k; ++i) isswap = false; for (j=k; j >=i; j 1 { if (ап [j] > arr[j+1] 1 tmp = arr[j+1]; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  15  1712.10 arr[j+1] = arr[j]; arr[j] = tmp; isswap = true; { 11 Если перестаНQБQК не было, то выходим if (! is swap) break; { 11 ВыВОДИМ отсортированный массив for (int i=O; i<ARR-;rZЕ; ++i) std::cout «arr[i] «std::endl; std: : cin. get (1 ; return о; { в качестве еще одноrо примера произведем с ортировку по убыванию (листинr 5.3). Чтобы пример был более полезным изменим налравление проходов. ЛИСТИIП' 5.3. П:'ПЫРЬКОВnЯ CopTltpOBKt"I по :'rбывt"lНИЮ #include <iostream> int main (1 const short ARRSIZE = 5; int arr[ARRSIZE] = {10, 5, 6, 1, 3{; int j = О, tmp = о; bool isswap = false; for (int i=ARRSIZEl; i>=l; i) isswap = false; for (j=O; j<i; ++jl if (ап [j] < arr[j+1] 1 tmp = arr[j+1]; arr[j+1] = arr[j]; arr[j] = tmp; isswap = true; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  16  1712.10 if (IJ..S swap) break; for (int i=O; i<ARRSIZE; ++il std::cout «arr[i] «std::endl; std: : cin. get (1 ; return о; Для сортировки массива можно также воспользоваться стандартной Функци ей qso rt (1 . Прототип функции: #inc1ude <cstd1ik> void qsort(void *Вазе, sizet NumOfElements, size t SizeOfElements, int (* PtFuncCompare) (const void *, const void *)); в параметре Bas е указывается адрес перБоrо элемента массива, в параметре NumOfE lemen t s  количество элементов массива, а в параметре Si ze Of Eleme nt s  размер каждоrо элемента в байтах. Адрес пользовательской функции (указ ывается название функции без круrлых скобок и параметров), внутри которой производится сравнение двух элементов, передается в последнем параметре. Прототип пользовательской функции сравнения должен выrлядеть так: int <Название функции>(соnst void *argl, const void *arg2); При сортировке по возрастанию функция должна возвращать отрицательное зн ачение, если arg 1 меньше arg2, положительное значение, если argl больше arg2, или О, если значения равны. Внутри функции необходимо выполнить приведение указ ателя void * к определенному типу. Пример использования функции qsor t ( 1 приведен в л и стинrе 5.4. .1IИСТIПП 5.4. CopTIlpOBKn mссивn с IЮЮШ;ЬЮ ф)...к.ЦlШ qSOl'tO #include <iostream> #inc1ude <cstd1ik> int mysort(const void *argl, const void *arg2); int main (1 const short ARRSIZE = 5; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  17  1712.10 int arr[ARRSIZE] = {10, 5, 6, 1, 3{; std: :qsort (arr, АRR:::-;rZЕ, sizeof (int), mysort); for (int i=O; i<ARRSIZE; ++il std::cout «arr[i] «std::endl; std: : cin. get (1 ; return о; int mysort(const void *argl, const void *arg2) return *(int *)argl  *(int *)arg2; Чтобы произвесТ1l сортировку по убыванию, достаточно поменять значения местами: int mysort(const void *argl, const void *arg2) return *(int *)arg2  *(int *)argl; Проверка наЛIIЧIIЯ значеНIIЯ в I\IaCCIIBe Если массив не отсортирован, то проверка наличия значения в массиве СВОДИТСЯ к пере6иранию всех элементов от начала до конца. При наличии первоrо вхождения можно прервать поиск Пример поиска первоrо вхождения: const short ARRSIZE = 5; int аrr[АRR:::-;rZЕ] = {10, 5, 6, 1, 3}, index = 1; int searchkey = 6; for (int i=O; i<ARR SIZE; ++i) if (arr[i] searchkeyl index = i; break; if (index ,= 11 std: : cout « rrYes rr « std: : endl; std: : cout « rr inde х = " « inde х « std: : endl; else std:: cout « rrNo rr « std:: endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  18  1712.10 Если значение находится в начале массива, то поиск 6уд ет произведен достаточно быстро, но если значение расположено в конце массива, то придется просматривать весь массив. Если массив состоит из 100 000 элементов, то нужно будет сделать 100 000 сравнений. Поиск по отсортированному массиву производится rораздо быстрее, так как не нужно каждый раз просматривать все значения массива. Наи60ле е часто при меняется бинарный поиск (листинr 5.5), при котором мас сив делится пополам и производится сравнение значения элемента, расположенноrо в середине массива, с ИСКО мым значением. Если искомое значение меньше значения элемента, ТО пополам делится первая половина массива, а если больше, то пополам делится вторая половина. Далее таким же образом ПРОИЗВОДИТСЯ деление оставшейся части массива. Поиск заканчивается коrд а будет найдено первое совпадение или коrда начальный индекс станет больше конечноrо индекса. Таки м образом, на каждой итерации отбрасывается половина оставшихся элементов. Поиск значения, которое расположено в конце массива, состоящеrо из 100 000 элементов, будет произведен Bcero за 17 шаrов. Однако, если поиск производится один раз, то затраты на сортировку сведут на нет все преимущества бинарноrо поиска. В этом случ ае прямой перебор элементов может стать эффективнее. -Тшст IПП' 5.5. БШНЧIНЫЙ поиск В отс ортщlO В;[IIПЮ I'rll'rrnссиве #include <iostream> #inc1ude <cstd1ik> int mysort(const void *argl, const void *arg2); int mysearch(int key, const int *arr, int count); int main (1 const short ARRSIZE = 5; int arr[ARR SIZE] = {10, 5, 6, 1, 3 {; 11 Сортируем по возрастанию std: : qsort (arr, ARR S IZE, sizeof (int), :mysort); 11 Производим поиск int index = :mysearch(6, arr, ARRSIZE); if (index ,= 11 std::cout « rrYes rr «std::endl; std: : cout « rrindex = rr « index « std:: endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  19  1712.10 else std:: cout « rrNo rr « std:: endl; std: : cin. get (1 ; return о; { 11 Сортировка по возрастанию int mysort(const void *argl, const void *arg2) return *(int *)argl  *(int *)arg2; { 11 Бинарный поиск в отсортированном массиве int mysearch(int key, const int *arr, int count) if (count < 1 11 ! arr) return 1; int start = О, end = count  1, i = о; while (start <= endl { i = (start + endl / 2; if (arr[i] == key) return i; e1se if (arr[i] < keyl start e1se if (arr[i] > keyl end i + 1; i  1; return  1; Для проверки наличия элемента в массиве можно также воспользовать ся стандартной функцией bse ar ch ( 1 . Прототип функции: #inc1ude <cstd1ik> void *bsearch(const void *Кеу, const void *Вазе, sizet NumOfElements, sizet SizeOfElements, int (* PtFuncCompare) (const void *, const void *)); в параметре Ке у передается адрес переменной, в которой хранится искомое значение, в параметре Bas е указывается адрес первоrо элемента массива, в параметре NumOfE lemen t s  количество элементов массива, а в параметре Si ze Of Eleme nt s  размер каждоrо элемента в байтах. Адрес пользовательской функции (указ ывается название функции без круrлых скобок и параметров), внутри которой производится сравнение двух элементов, передается в последнем параметре. Прототип пользовательской функции сравнения должен выrлядеть так: int <Название функции>(соnst void *argl, const void *arg2); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  20  1712.10 Фунщия должна возвращать отрицательное значение, если arg 1 меньше arg2, положительное значение, если arg 1 больше ar g2 , или О, если значения равны. Внутри функции необходимо выполнить приведение указателя void * к определенному типу. Кроме Toro, необходимо выполнить приведение указателя при получении результата. Если значение не найдено, то возвращается нулевой указатель, в противном случае указ атель ссылается на найденный элемент. Пример использования функции bs earc h (1 приведен в листинrе s. б. .1IИСТIПП 5.6. Проверкn ншшчия Зlffiчення В тccнвe с IЮЮШ;ЬЮ ф)"НlЩIШ Ьseю-сl,О #include <iostream> #inc1ude <cstd1ik> int mysort(const void *argl, const void *arg2); int mysearch(const void *argl, const void *arg2); int main (1 const short ARRSIZE = 5; int arr[ARR SIZE] = {10, 5, 6, 1, 3}, searchkey = 6; 11 Сортируем по возрастанию std: : qsort (arr, ARR S IZE, slzeof (int), :mysort); 11 Производим поиск int *р = (int *)std::bsearch(&searchkey, arr, ARRSIZE, sizeof (int), mysearch); f (р) std::cout « rrYes rr «std::endl; else std:: cout « rrNo rr « std:: endl; std: : cin. get (1 ; return о; { 11 Сортировка по возрастанию nt mysort(const void *argl, const void *arg2) return *(int *)argl  *(int *)arg2; { 11 Сравнение при поиске nt mysearch(const void *argl, const void *arg2) return *(int *)argl  *(int *)arg2; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  21  1712.10 Коппрованпе элеl\Iентов пз одноrо масспва в друrОII Для копирования элементов из одноrо массива в дрyrой используются слеДJ'lOщие функции: -+ тете ру ()  копирует первые Si ze байтов из массива Sr с В массив Dst. В каче стве значения функция возвращает указ атель на массив Dst. Если массив Sr с длиннее массива D st, то произойдет переполнение буфер а. Если указатели пересекаются, то поведение функции непредсказуемо. Прототип функц ии: #incl ude <cs tr in g> void *memcpy(void *Dst, const void *Src, size t Size); Пример использования функции: const short ARRl SIZE = 5, ARR2 SIZE = 3; int arr1[ARR1 SIZE] = {О{, arr2[ARR2 SIZE] = {1, 2, 3{; int *р = О, i = о; 11 Ко пируем все элементы массива ar r 2 р = (int *) std: :тетсру (arrl, arr2, sizeof arr2); for (i=O; i<ARRl SIZE; ++i) std: : cout « arrl [i] « rr rr; //12300 std::cout « std: :endl; if ('рl std::exit(ll; 11 Перемещаем указатель на четвертый элемент массива р += 3; 11 Копируем только два первых элемента массива arr2 std: : тетсру (р, arr2, 2 * sizeof (int) ) ; for (i=O; i<ARRl SIZE; ++i) std: : cout « arrl [i] « rr rr; //12312 std::cout « std: :endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  22  1712.10 в VC++ вместо функции тетср у (1 можно использовать функцию тетср у s (1 Прототип функции: #nclude <cstrng> errno t тетсру S (vold *Dst, rsize t DstSize, const void *Src, rsi ze t МахСо unt) ; Функция тетср у s копирует первые МахС оиn t байтов из массива S rc В массив Ds t. В параметре Dst Si ze указывается размер массива D st в байтах. Если копирование прошло успешно функция возвращает значение о. Пример: const short ARRl SIZE = 5, ARR2 SIZE = 3; int arr1[ARR1 SIZE] {О {, ап2 [ARR2 S IZE] {1, 2, 3 { ; тетсру s (arrl, sizeof arrl, arr2, 2 * sizeof (int) ) ; for (int i=O; i<ARRl S IZE; ++i) std::cout « arrl[i] « rr rr. , //12000 std::cout « std: :endl; -+ me:mтove ( ) копирует первые S ize байтов из массива Sr с В массив Dst. В каче стве значения функция возвращает указ атель на массив Dst. Если массив Sr с длиннее массива Ds t, то произойдет переполнение буфера. Основное отличие функц ии memmove (1 от тетср у (1 в выполнении корректных действий при пересечении указателей. Прототип функции: #incl ude <cs tr ing> void *memmove(void *Dst, const void *Src, size t Size); Пример: const short ARR SIZE = 5; int arr[ARR SIZE] р = arr + 2; 11 Указатели пересекаются {1, 2, 3, 4, 5}, *р О. , std::memmove(p, arr, 3 * Sizeof(int)); for (int i=O; i<ARR SIZE; ++i) std: : cout « arr [i] « rr rr. , 11 1 2 1 2 3  копирование произведено корректно Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  23  1712.10 std::cout « std::endl; В VC++ вместо функции memmove (1 можно использовать функцию memmove s (1 . Прототип функции: #incl ude <cs tr ing> errno t memrnove s(void *Dst, rsize t DstSize, const void *Src, rsize t MaxCount); Функция memrnove s копирует первые МахС ount байтов из массива S rc В массив Ds t. В параметре D stS i "е указывается раз мер массива D st в байтах. Если копирование прошло успешн о функция возвращает значение о. Пример: const short ARR SIZE = 5; int arr[ARR SIZE] {1, 2, 3, 4, 5}, *р о. , р = arr + 2; mе:mnюvе s (р, sizeof arr, arr, 3 * sizeof (int) ) for (int i=O; i<ARR SIZE; ++i) std: : cout « arr [i] //12123 « rr rr. , std: : cout « std:: endl; СравнеНIIе I\IaCCIIBOB Для сравнения массивов предназначена функция тетстр (1. Функция тетстр (1 сравнивает первые Si "е байтов массивов в uf 1 и Buf 2. В каче стве значения функция в озвр аща ет -+ отрицательное число  если Buf 1 меньше Buf2; -+ о  если массивы равны; -+ по ложите ль ное число  если Ви f 1 больше в uf 2. Прототип функции: #include <cstring> int memcmp(const void *Bufl, const void *Buf2, size t Size); Пример: int ап1[3] = {1, 2, 3{, ан2 [3] = {1, 2, 3{, х х = std:: тетстр (arr 1, arr2, sizeof arr2); о. , Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  24  1712.10 std::cout «х «std::endl; ан1 [2] = 2; / / ан1 [] = {1, 2, 2 {, ан2 [] х = std:: тетстр (arr 1, arr2, sizeof arr2); std::cout «х «std::endl; ан1 [2] = 4; / / ан1 [] = {1, 2, 4{, ан2 [] х = std:: тетстр (arr 1, arr2, sizeof arr2); std::cout «х «std::endl; Функция тетстр ( 1 производит сравнение с учетом реrистра символов. Если необходимо произвести сравнение б ез учета символов, то в VC++ можно воспользоваться функцией memlcmp ( 1 . Для сравнения русских букв следует настроить локаль. Прототип функц ии: #include <cstring> int memicmp(const void *Bufl, const void *Buf2, size t Size); Предн азн ачение параметров и возвращаемо е значение такое же, как у функции тетстр (1 . Пример использования функции: std: : setlocale (LC  ALL, rrRussian  Russia. 1251 rr) ; 11 Настройка лакали char strl [] = rrабв rr , str2 [] = rrАБв rr ; int х = о; х = memicmp(strl, str2, sizeof str2); std: : cout « х « std:: endl; 11 о х = std::memcmp(strl, str2, sizeof str2); std: : cout « х « std:: endl; 11 1 // о = { 1, 2, 3 { // 1 = { 1, 2, 3 { // 1 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  2  1712.10 в языке С++ доступны два типа однобайтовых строк строка, применяемая в языке С (поэтому часто называемая Сстрокой), и кл асс st r ing. CCтpOKa является массивом символов (тип char), последний элемент KOToporo содержит нулевой символ (\ о). Обратите внимание на то, что нул евой символ (нулевой байт) не имеет никакоrо отношения к числу о. Коды ЭТИХ символов разные. Класс st r ing предоставляет более уд обный интер фейс доступа, который избавляет проrpаммиста от необходимости следить за размер ом символьноrо массива и предоставляет множество методов ДЛЯ обработки строки. При необходимости можно преобразовать объект кл асса st r ing в C строку.   Ооъявленпе п ПНIIЦШlЛпзацпя отдельноrо СПI\ШОШl Для хранения символа используется тип char. Переменной, имеющей тип char , можно присвоить числовое значение (код символа) или указ ать символ внутри апострофов. Обратите внимание на то, что использовать кавычки нельзя, так как в этом случае вместо одноrо символа будет два: с06 ственно сам символ плюс нулевой символ. Пример: char chl, ch2; ch1 = 119; // Буква w ch2 = IW I ; 11 Буква w Внутри апостроф ов можно указать специальные символы. Специальные символы  это ко м6инации :знаков, 060значaIOЩИХ служ е6ные или непечатаемые символы. Перечислим специальные СИМВОЛЫ, доступные в С++: -+ \0  нулевой символ; -+ \ n  перевод строки; -+ \ r  возврат каретки; -+ \ t  rоризонтальная табуляция; -+ \ v  вертикальная табуляция; -+ \ а  звуковой сиrнал; -+ \ ь  возврат на один символ; -+ \ f  перевод формата; -+ \'  апостроф; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  3  1712.10 -+ \ rr  кавычка; -+ \?  знак вопроса; -+ \ \  обратная косая черта; -+ \ N  восьмеричное значение М; -+ \ хЫ  шестнадцатеричное значение N Пример указания восьмеричноrо и шестнадцатеричноrо значений: char chl, ch2; chl = 1\1671; 11 Буква w (восьмеричное значение) ch2 = '\х77 1 ; 11 Буква w (шестнадцатеричное значение) По умолчанию тип char является знаковым и позволяет хранить диапазон значений от  12 8 до 127. Если перед типом указано ключевое слово uns igne d, то диапазон будет от о до 255. Коrда переменной присваивается символ внутри апостро фов, он автоматически прео6разуется в СОО1БетствJ'!OЩИЙ целочисленный код. Тип char занимает в памяти один б айт (восемь бит). Если тип является знаковым, то старший бит содержит признак знака: О соответствует положительному числу, а 1  отрицательному. Если тип является 6еззнаковым, то признак зн ака не используется. Это следует учитывать при прео6раз овании знакОБоrо типа в 6еззнаковый, так как старший бит станет причиной больших значений: char chl = 1; unsigned char ch2 = (unsigned char)chl; std::cout « (intlch2 «std::end1; //255 Символы, имеющие код меньше 128 (занимают 7 бит), соответствуют кодировке AS сп. Коды ЭТИХ символов одинаковы практически во всех одн06айтовых кодировках. В состав кодировки АSСП входят ци фры, буквы латинскоrо алф авита, знаки препинания и некоторые служебные символы (например, перенос строки, табуляция и т. д.). Коды основных символов в кодировке АSСП в десятичном (dec), восьмеричном (oct) и шестнадцатеричном (hex) виде приведены в табл. б.1. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  4  1712.10 (l( О({ llH (Иl'rШОЛ О О О \0 7 7 7 \а 8 10 8 \Ь 9 11 9 \t 10 12 а \n 11 13 Ь \v 12 14 с \f 13 15 d \r 32 40 20 пробел 33 41 21 , 34 42 22 " 35 43 23 # 36 44 24 $ 37 45 25 % 38 46 26 & 39 47 27 , 40 50 28 ( 41 51 29 1 42 52 2а * 43 53 2Ь + 44 54 2с , 45 55 2d  46 56 2е ТаблlШp 6.1. КDды ОСlЮвiiЫХ символов в кодировке АSСП (l( О({ llH (Иl'rШОЛ 76 114 4с L 77 115 4d м 78 116 4е N 79 117 4f о 80 120 50 р 81 121 51 Q 82 122 52 R 83 123 53 s 84 124 54 т 85 125 55 u 86 126 56 v 87 127 57 w 88 130 58 х 89 131 59 у 90 132 5а z 91 133 5Ь [ 92 134 5с \ 93 135 5d ] 94 136 5е л 95 137 5f  96 140 60 97 141 61 а 98 142 62 Ь Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  5  1712.10 47 57 2f / 48 60 30 О 49 61 31 1 50 62 32 2 51 63 33 3 52 64 34 4 53 65 35 5 54 66 36 6 55 67 37 7 56 70 38 8 57 71 39 9 58 72 3а : 59 73 3Ь ; 60 74 3с < 61 75 3d = 62 76 3е > 63 77 3f ? 64 100 40 @ 65 101 41 А 66 102 42 в 67 103 43 с 68 104 44 D 69 105 45 Е 70 106 46 F 71 107 47 G 99 143 63 с 100 144 64 d 101 145 65 е 102 146 66 f 103 147 67 g 104 150 68 h 105 151 69 i 106 152 6а j 107 153 6Ь k 108 154 6с 1 109 155 6d m 110 156 6е n 111 157 бf о 112 160 70 р 113 161 71 q 114 162 72 r 115 163 73 s 116 164 74 t 117 165 75 u 118 166 76 v 119 167 77 w 120 170 78 х 121 171 79 у 122 172 7а z 123 173 7Ь { Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  6  1712.10 72 110 48 н 73 111 49 I 74 112 4а J 75 113 4Ь к 124 174 7с I 125 175 7d { 126 176 7е  127 177 7f DEL Восьмой бит у типа uns igne d с har предназначен для кодирования символов национальных ал фавИТОВ. У типа char эти символы имеют отрицательные значения (старший бит содержит признак знака). Таким образом тип char позволяет закодировать Bcero 25б символов. Для кодирования букв pyccKoro языка предназначено пять кодировок  Windows  125 1 (ср 1251), ср8бб, iso88595, koi8r и maccyrillic. Проблема заключается в том, что код одной и той же русской буквы в этих кодировках может быть разным. Пзза этоrо возникает множество проблем. Например, при выводе русских букв в консоли может отобразиться нечитаемый текст. Причина искаже ния русских 6ym заключается в ТОМ, что по умолчанию в окне консоли используется кодировка ср8бб, а в проrp амме мы выводим текст в кодировке ср 125 1. Коды русских букв и некоторых символов в кодировках ср8бб и ср 1251 в десятичном (unsigned и signed), восьмеричном (oct) и шестнадцатеричном (hex) виде приведены в табл. б.2. Обратите внимание на то, что КОДЫ 6ym Ilёll и IIЁII выпадmoт из последовательности КОДОВ, поэтому при использовании, например, реryлярных выражений 6J'Iffi а 11 ё ll не попадает в диапззон [а  я] , ее необходимо указ ывать дополнительно [а  яё] . Таблица 6.2. КDды py;eкux бут и некоторых еuмволое в кодировках ер8 бб и ер1251 '1'866 c1'151 (Иl'rШОЛ 1.ш.siglll:"(1 Sigll(\ оС! \"''' ш"igIl(\ SigIl(\ оС! \lH А 128 128 200 80 192 б4 300 со Б 129 127 201 81 193 63 301 сl в 130 126 202 82 194 62 302 с2 r 131 125 203 83 195 61 303 с3 Д 132 124 204 84 196 60 304 с4 Е 133 123 205 85 197 59 305 с5 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  7  1712.10 Ё 240 16 360 flJ 168 88 250 а8 ж 134 122 206 86 198 58 306 с6 з 135 121 207 87 199 57 307 с7 и 136 120 210 88 200 56 310 с8 й 137 119 211 89 201 55 311 с9 к 138 118 212 8а 202 54 312 са л 139 117 213 8Ь 203 53 313 сЬ м 140 116 214 8с 204 52 314 сс н 141 115 215 8d 205 51 315 cd о 142 114 216 8е 206 50 316 се п 143 113 217 8f 207 9 317 cf р 144 112 220 90 208 8 320 dO с 145 111 221 91 209 7 321 dl т 146 110 222 92 210 6 322 d2 у 147 109 223 93 211 5 323 d3 ф 148 108 224 94 212 4 324 d4 х 149 107 225 95 213 3 325 d5 Ц 150 106 226 96 214 2 326 d6 ч 151 105 227 97 215 1 327 d7 ш 152 104 230 98 216 O 330 d8 Щ 153 103 231 99 217 39 331 d9 ъ 154 102 232 9а 218 38 332 da ы 155 101 233 9Ь 219 37 333 db ь 156 100 234 9с 220 36 334 dc э 157 99 235 9d 221 35 335 dd Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  8  1712.10 ю 158 98 236 9е 222 34 336 de я 159 97 237 9f 223 33 337 df а 160 96 240 аО 224 32 340 еО б 161 95 241 аl 225 31 341 еl в 162 94 242 а2 226 зо 342 е2 r 163 93 243 а3 227 29 343 е3 д 164 92 244 а4 228 28 344 е4 е 165 91 245 а5 229 27 345 е5 ё 241 15 361 f1 184 72 270 ь8 ж 166 90 246 а6 230 26 346 е6 з 167 89 247 а7 231 25 347 е7 и 168 88 250 а8 232 24 350 е8 й 169 87 251 а9 233 23 351 е9 к 170 86 252 аа 234 22 352 еа л 171 85 253 аЬ 235 21 353 еЬ м 172 84 254 ас 236 20 354 ес н 173 83 255 ad 237 19 355 ed о 174 82 256 ае 238 18 356 ее п 175 81 257 af 239 17 357 ef р 224 32 340 еО 240 16 360 fO с 225 31 341 еl 241 15 361 f1 т 226 зо 342 е2 242 14 362 f2 у 227 29 343 е3 243 13 363 f3 Ф 228 28 344 е4 244 12 364 1'1 х 229 27 345 е5 245 11 365 f5 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  9  1712.10 ц 230 26 346 е6 246 10 366 f6 ч 231 25 347 е7 247 9 367 fI ш 232 24 350 е8 248 8 370 f8 ш 233 23 351 е9 249 7 371 f9 ъ 234 22 352 еа 250 6 372 fa ы 235 21 353 еЬ 251 5 373 fb ь 236 20 354 ес 252  374 fc э 237 19 355 ed 253 3 375 fd ю 238 18 356 ее 254 2 376 fe я 239 17 357 ef 255 1 377 ff Е 242 14 362 f2 170 86 252 аа Е 243 13 363 f3 186 70 272 Ьа о 248 8 370 f8 176 80 260 ЬО !I! 252  374 fc 185 71 271 Ь9 "     132 124 204 84     133 123 205 85 <;:     136 120 210 88 1;:;     137 119 211 89 ,     145 111 221 91 ,     146 110 222 92 "     147 1 09 223 93 "     148 1 08 224 94      150 1 06 226 96      151 1 05 227 97 m     153 103 231 99 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  10  1712.10 ,     166 90 246 а6 , !;;     167 89 247 а7 I!;)     169 87 251 а9 «     171 85 253 аЬ ,     172 84 254 ас     173 83 255 ad @     174 82 256 ае :t     177 79 261 Ы »     187 69 273 ЬЬ НастроlIка ЛОЮ1ЛП В языке С При изменении реrистра русских букв может возникнуть проблема. Чтобы ее избежать, необходимо правильно настроить локаль (совокупность локальных настроек системы). Для настройки локали используется функция se t10c a1e (1 . Прототип функции: #include <clocale> char *setlocale(int Category, const char *Locale); В первом параметре указывается катеrория в виде числа от О ДО 5 или соответствYIOЩИЙ числу макро с: -+ о  LC ALL  устанавливает локаль для всех катеrорий, -+ 1  LC COLLATE  для сравнения строк, -+ 2  LC СТУР Е  для перевода символов в нижний или верхний реrистр, -+ 3  LC МОЫЕ TAR У  для отображения денежных единиц, -+ 4  LC NUME RI С  для форматирования дробных чисел, -+ 5  LC TIME  для форматирования вывода даты и времени В ( 11 11 О втором параметре задается название локали в виде строки например, rus, "RussianRussia", "RussianRussia.12S1" или 11.125111). Вместо названия можно указать пустую строку. В этом случае будет использоваться локаль, настроенная в системе. В VC++ после настройки локали автоматически ПРОИЗВОДИТСЯ прео6раз ование кодировок при выводе в ОКНО коне оли. Пример настройки локали для всех катеrорий: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 11  1712.10 std: : setlocale (LC  ALL, rrRussian  Russia. 1251 rr) ; в кач естве значения функция возвращает указатель на строку с названием локали, соотвеТСТВYIOщей заданной катеrории, или нулевой указатель в случае ошибки. Если во втор о м пар аметр е пер ед ан н ул ев о й указ ател ь, то фу нкц И Я В озвр ащ ает указ ате ль н а строку с названием текуще й локали. Пример настройки локали и вывода текущеrо названия локали приведен в ЛИСТ1lнrе 6.1. I .1IИСТIПП 6.1. Настройка ЛОКaJШ # include <iostream > #include <clocale> int main (1 char *pch = о; 11 Настройка лакали pch = std:: setlocale (LC ALL, rrRussian  Russia. 1251 rr) ; if (pch) std::cout «pch« std::endl; 11 Russian Russia.1251 11 Получение текущей лакали pch = std::set1oca1e(LCALL, 01; if (pch) std::cout «pch« std::endl; 11 Russian Russia.1251 std:: cout « rrB VC++ ЭТОТ русский текст в КОНСОЛИ rr « rrО'КIбражается нормально rr « std:: endl; std: : cin. get (1 ; return о; Функция 10 ca1e со nv (1 позволяет получить информацию о способе форматирования веще ственных чисел и денежных сумм для текущей локали. Прототип функции: #include <clocale> struct lconv *localeconv(void); Функция возвращает указатель на структуру 1conv. Пример вывода символа десяшчноrо разделителя для локали Russ lan R uss la . 1251 lconv *р = о; std: : setlocale (LC ALL, rrRussian  Russia. 1251 rr) ; р = std::localeconv(); if (рl std::cout «p>decimalpolnt «std::endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  12  1712.10 Объявление структуры 1conv выrлядит следующим образом: struct lconv { char * de cimal р о lnt ; char *thousands sep; char * grouping ; char * lnt curr symbol; char *currencysymbol; char *nюn decJ.1Llal pOlnt; char * nюn thousands sep; 11 Дес ятичный р азд е лите ль ( rr, rr) 11 Разд е лите ль 'Iыяч ( rr rr) 11 Способ rруппировки значений 11 Наз вание валю'Iы ( rr R UR rr ) 11 СИМВОЛ валю'Iы (rrp. rr) 11 Д=сятичный разделитель для 11 денежных сумм (rr, rr) 11 р азд е лите ль 'Iыяч Д ЛЯ Д е нежных 11 сумм (rr rr) char *тоn grouplng; 11 Способ rруппировки для денежных сумм char *posltlve slgn; 11 Положительный знак для денежных сумм char * nе ga t 1 ve s 19n ; 11 Отр ица те ль ный знак Д ля Д енежных сумм (rr  rr ) char lnt frac diglts; 11 Количество цифр в дробной части для 11 денежных сумм в меЖдународном формате (2) char frac dlglts; 11 Количество цифр в дробной части для 11 денежных сумм в национальном формате (2) char р cs precedes; 11 1  если символ валю'Iы перед значением 11 о  если символ валю'Iы после значения char р sep Ьу space; 11 1  если символ валю'Iы отделяется пробелом 11 О  в противном случае 11 р cs precedes и р sep  Ьу  space прим:енЯIOТСЯ 11 для положительных значений char n cs precedes; 11 1  если символ валю'Iы перед значением 11 о  если символ валю'Iы после значения char n sep Ьу space; 11 1  если символ валю'Iы отделяется пробелом 11 О  в противном случае 11 ncs precedes и nsepbyspace прим:енЯIOТСЯ 11 для отрицательных значений char р slgn posn; 11 Позиция символа положительноrо значения char n slgn posn; 11 Позиция символа отрицательноrо значения wchar t * W decimal pOlnt; 11 Аналоrичные значения для расширенных wchar t *Wthousands sep; 11 символов. Описание см. БЫllE wchar t *Wlnt curr symbol; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  13  1712.10 wchar t *Wcurrencysyllibol; wchar t *Wmondecimalpoint; wchar t *Wmonthousands sep; wchar t *Wposltlve slgn; wchar t *Wnegatlve slgn; {; НастроlIка ЛОЮ1ЛП В языке С++ в языке С++ настройка локали ПРОИЗВОДИТСЯ с ПОМОЩЬЮ кл асса loc ale. Прежде чем использовать класс необходимо ПОДКЛЮЧИТЬ зarоловочный файл 10С ше. Наиболее часто используются следующие конструкторы класса: #include <locale> 10ca1e(l; locale(const char *Locname, category Cat = all); locale(const string &Str, category Cat = all); locale(const locale &Right); locale(const locale &Loc, const char *Locname, category Cat); locale(const locale &Loc, const string &Str, category Cat); locale(const locale &Loc, const locale &Other, category Cat); В параметрах Lo сnате и S tr задается название локали в виде Сстроки или объекта класса str ing соответственно (например, Ilrus ll , "RussianRussia", "RussianRussia.12S111 или ".1251"). Вместо названия можно указать пустую строку. В этом случае будет использоваться локаль, настроенная в системе. В параметре Cat можно указать следующи е флarи (или их комбинацию через побитовый оператор 1): -+ 10 са1е : : а11  устанавливает локаль для всех катеrорий; -+ 10 са1е : : со 11at е  для сравнения строк; -+ 10 са1е : : ct ур е  для перевода символов в нижний или верхний реrистр; -+ 10 са1е : : nю nе tary  для отображения денежных единиц; -+ 10 ca1e : : nume r ic  для форматирования дробных чисел; -+ 10 ca1e : : time  для форматирования вывода даты и времени; -+ 10 са1е : : те s sages; -+ 10 са1е : : по nе  флаrи не установлены. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  14  1712.10 Пример создания объекта класса 10c a1e Russian Russia .1251: ДЛЯ всех катеrорий в локали std: : locale loc (rrRussian  Russia. 1251 rr, std:: locale: : all) ; Чтобы установить локаль на rлобальном уровне следует передать созданный объект в статический метод g 10ba1 ( 1 . Прототип метода: static locale global (const locale &Loc); Метод принимает объект класса loc ale и возвращает прежнюю настройку локали. Получить название локали позволяют методы с str (1 и пате ( 1. Метод с  st r (1 возвращает значение в виде Сстроки, а метод пате ()  в виде объекта класса st r ing. Прототипы методов: const char *cstr () const; string narre () const; П ример настройки локали и вывода названия текущей локали приведен в листинrе б.2. I .1IИСТIПП 6.2. Настройка ЛОКaJШ # include <iostream > #include <locale> int main (1 std: : locale loc (rrRussian  Russia. 1251 rr, std:: locale: : all) ; std::1oca1e 10c2 = std::1oca1e::g1oba1(10cl; std::cout «loc.c str() «std::endl; 11 Russian Russia.1251 std::cout «10c2.c str(1 «std::end1; // С std: : cout « rrэ'КIТ текст :корректно отображается в окне :консоли,r « std:: endl; std: : cin. get (1 ; return о; в параметре метода g 10ba1 (1 можно указ ать объект еще одним способом: std: : locale: : global (std: : locale (rrRussian  Russia. 1251 rr) ) ; Как видно из примера, объект сразу передается в метод globa1 (1 и ниrде не сохраняется. Чтобы получить название настроенной локали следует использовать конструктор по умолчаншо. Пример получения названия: std::cout «std::1oca1e(l.c str(1 «std::end1; // С Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  15  1712.10 std: :locale: :global(std: :locale(rrRusslan Russa.1251rr)); std::cout «std::locale() .cstr() «std::endl; 11 RussianRussia.1251 Создать объект класса 10 cale для локали С позволяет статический метод с las sic ( ) . с помощью этоrо метода обычно ПрОН:ЗБОДЯТ сравнение локалей. Прототип метода: static const locale &classic(); Пример: if (std::1oca1e(1 == std::1oca1e::c1assic(11 std::cout « rrc rr «std::endl; e1se { std::cout «std::locale().c str() «std::endl; Создать пустой объект кл асса 10c a1e позволяет метод етр ty (1 . Прототип метода: static locale empty () ; Пример: std::locale loc = std::locale::empty(); std::cout «loc.c str() «std::endl; 11 * ПЗI\Iененпе реrпстра СПМВОJШ Для изменения реrистра символа предназначены следующие функции: -+ to ир ре r (1  возвращает код символа в верхнем реrистре. Если преобразования реrистра не было, то код символа возвращается без изменений. Прототип функции: #include <cctype> int toupper(int С); Пример: std: : setlocale (LC ALL, rrRussianRussia. 1251 rr) ; std: : cout « (charl std: : toupper ( 'w' 1 « std: : endl; // w std: : cout « (charl std: : toupper ( 'w' 1 « std: : endl; // W std: : cout « (charlstd::toupper( (unsigned charl Iб 1) « std: : endl; // Б -+ to 10we r (1  возвращает код символа в нижнем реrистре. Если преобразования реrистра не было, то код символа возвращается без изменений. Прототип функции: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  16  1712.10 #nclude <cctype> int tolower(int С); Пример: std: : setlocale (LC ALL, rrRussianRussia. 1251 rr) ; std: : cout « (char) std: : tolower ( I w 1) «std:: endl; 11 w std: : cout « (char) std: : tolower ( I W 1) «std:: endl; 11 w std: : cout « (char) std: : tolower ( (unsigned char) I Б I ) « std: :end1; // б Проверка ТIIпа содерЖIIl\юrо СIIМВОШl Для проверки типа содержимоrо символа предназначены следующие функции: -+ is digi t ()  возвращает ненулевое значение, если символ является десятеричной цифрой, в противном случае  о. Прототип функции: #include <cctype> int isdigit(int С); Пример: std: : cout « std: : isdigit ( I w 1) « std:: endl; 11 о std: : cout « std: : isdigit ( 12 1) « std:: endl; 11 4 std: : cout « std: : isdigit ( (unsigned char) I б 1) « std::end1; // о -+ is xdig it ()  возвращает ненулевое значение, если шестнадцатеричной цифрой (число от О до 9 или буква от А до значения)), в противном случае  о. Прототип функции: #include <cctype> int isxdigit(int С); си мв ол является F (реrистр не имеет Пример: std: : cout « std: : isxdigit ( 181 ) std::cout « std: :isxdigit( la l ) std: : cout « std: : isxdigit ( 1 F 1 ) std::cout « std: :isxdigit( Igl) « std: : endl; // 128 « std: : endl; // 128 « std: : endl; // 128 « std: : endl; // о Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  17  1712.10 -+ isa1pha (1  возвращает ненулевое значение, если символ является буквой, в противном случае  о. Прототип функции: #nclude <cctype> int isalpha(int С); ДЛЯ русских букв необходимо настроить локаль. Пример: std:: setlocale (LC ALL, rrRussianRussia.1251rr); std: : cout « std: : isalpha ( I W 1) « std: : endl; // 258 std: : cout « std: : isa1pha ( '2 '1 « std: : endl; // о std: : cout « std: :isa1pha((unsigned char) I б I ) « std: : endl; // 258 std: : cout « std: : isalpha ( (unsigned char) I Б 1) « std: :end1; // 257 -+ is sp ас е ()  возвращает ненулевое значение, если символ является про6ельным символом (пробелом, табуляцией, переводом строки или возвратом каретки), в противном случае  о. Прототип функции: #include <cctype> int isspace(int С); Пример: std: : cout « std: : isspace ( I W 1) « std:: endl; std: : cout « std: : isspace ( 1\ n 1) «std:: endl; std: : cout « std: : isspace ( 1\ t 1) «std:: endl; std: : cout « std: : isspace ( (unsigned char) I б 1) « std::end1; // о // о // 8 // 8 -+ is alnum ()  возвращает ненулевое значение, если символ является буквой или цифрой, в противном случае  о. Прототип функции: #include <cctype> int isalnwm(int С); ДЛЯ русских букв необходимо настроить локаль. Пример: std:: setlocale (LC ALL, rrRussianRussia.1251rr); std: : cout « std: : isalnum ( I W 1) « std:: endl; std: : cout « std: : isalnum ( 18 1) « std:: endl; / / 258 // 4 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  18  1712.10 std: : cout « std: : isalnum ( 1\ t 1) «std:: endl; 11 о std: : cout « std: : isalnum ( (unsigned char) I б 1) « std: :end1; // 258 -+ is lowe r ( ) возвращает ненулевое значение, если символ является 6уmой в нижнем реrистре, в противном случае  о. Прототип функции: #include <cctype> int islower(int С); ДЛЯ русских букв необходимо настроить локаль. Пример: std: : setlocale (LC ALL, rrRussian Russia. 1251 rr) ; std: : cout « std: : islower ( I w 1) « std: : endl; // 2 std: : cout « std: : islower ( 18 1) « std: : endl; // о std: : cout « s td: : islowe r ( I \ t I ) « std: : endl; // о std: : cout « std: :islower((unsigned char) I б I ) « std: : endl; // 2 std: : cout « std: :islower((unsigned char) I Б I ) « std: : endl; // о -+ is ир ре r ( ) возвращает ненулевое значение, если символ является 6уп:ой в верхнем реrистре, в противном случае  о. Прототип функции: #include <cctype> int isupper(int С); ДЛЯ русских букв необходимо настроить локаль. Пример: std: : setlocale (LC ALL, rrRussianRussia. 1251 rr) ; std: : cout « std: : isupper ( I W 1) « std:: endl; // 1 // о // о std: : cout « std: : isupper ( 18 1) « std: : endl; std: : cout « std: :isupper (' \t' 1 « std: : endl; std: : cout « std: :isupper((unsigned char) I б I ) « std: : endl; // о std: : cout « std: :isupper((unsigned char) I Б I ) « std: : endl; // 1 -+ is риnс t ( ) возвращает ненулевое значение, если символ является символом пунктуации, в противном случае  о. Прототип функции: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  19  #incl ude <се type > int ispunct(int CI; Пример: std: : cout « std: : ispunct ( 18 1) « std: : endl; // о std: : cout « std: : ispunct ( I f 1) « std: : endl; // о std: : cout « std: : ispunct ( I , '1 « std: : endl; // 16 std: : cout « std: : ispunct ( I . '1 « std: : endl; // 16 std: : cout « std: : ispunct ( I '1 « std: : endl; // о 1712.10 -+ is pr in t ()  возвращает ненулевое значение, если символ является печатаемым (включая пробел), В противном случае  о. Прототип функции: #include <cctype> int isprint(int С); ДЛЯ русских букв необходимо настроить локаль. Пример: std: : setlocale (LC ALL, rrRussianRussia. 1251 rr) ; std: : cout « std: :isprint (18 1) « std: : endl; // 4 std: : cout « std: :isprint (1 \х5 1) « std: : endl; // о std: : cout « std: : ispr int ( I '1 « std: : endl; // 64 std: : cout « std: :isprint((unsigned char) I б I ) « std: : endl; // 258 -+ is gr ар h ()  возвращает ненулевое значение, если символ является печатаемым (пробел печатаемым не считается), В противном случае  о. Пр ототип функц ии: #include <cctype> int isgraph(int С); ДЛЯ русских букв необходимо настроить локаль. Пример: std: : setlocale (LC ALL, rrRussianRussia. 1251 rr) ; std: : isgraph ( 18 1) « std:: endl; std: : isgraph ( 1\ х5 1) « std:: endl; std: : isgraph (1 1) « std:: endl; std: : cout « std: : cout « std: : cout « std: : cout « « / / 4 / / о / / о std: : isgraph ( (unsigned char) I б 1) std: : end1; / / 258 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  20  1712.10 -+ is сп tr 1 ()  возвращает ненулевое значение, если непечатаемым, в противном случае  о. Прототип функции: #include <cctype> int iscntrl(int С); с и мв ол является Пример: std: : cout « std: :iscntrl (18 1) « std: : endl; // о std: : cout « s td: : isc n tr 1 ( I \ х5 I ) « std: : endl; // 32 std: : cout « std: : iscntr 1 ( I '1 « std: : endl; // о Обратите внимание на то, что перед русскими буквами указывается операция приведения к Т1Iпу unsigned char. Если приведение типов не указать, то ПРОИЗВОДИТСЯ попытка преобразования к типу uns igne d int. Так как коды русских букв по умолчанию имеют отрицательные значения, знаковый бит станет причиной 60льшоrо значения, которое ВЫХОДИТ за рамки диапазона значений ДЛЯ типа с har. Например, ДЛЯ буквы" б" значение буд ет равно 4294967265. Пример: std: : cout « (unsigned int) (unsigned char) I б I « std: :end1; // 225 std: : cout « (unsigned int) I б I « std::end1; //4294967265 ССТрОЮI CCтpOKa является массивом символов (ТИП char), последний элемент KOToporo содержит нулевой символ (\0). Обратите внимание на то, что нулевой символ (нулевой байт) не имеет никакоrо отношения к числу о. Коды этих символов разные. ОБЪЯВЛflШf И шпш;иализация СfЧ)ОКИ Объявляется CCтpOKa также как и массив элементов типа с har: char str [7]; При инициализации Сстроки можно перечислить символы внутри фиryp ных скобок char str[7] = {ISI, It l , Ir l , 'i ' , In l , Igl, I\OI}; или указ ать строку внутри двойных кавычек: char str [7] = rrStr ingrr; При использовании двойных кавычек следует уч итывать, что длина строки на один символ больше, так как в конец будет автоматически вставлен нулевой символ. Если Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  21  1712.10 это не предусмотреть и объявить мае сив из шести элементов, вместо семи, то при ко мпиляции будет выведено сообщение об ошибке. Если размер массива при объявлении не указать, то он буд ет определен автоматически в соответствии с ДЛИНОЙ строки: char str [] = rrStr ingrr; Обратите внимание на то, что присваивать строку в ДВОЙНЫХ кавычках можно только при инициализации. Попытка присвоить строку позже приведет к ошибке: char str[7]; str = rrStr ingrr; 11 Ошибка! ! ! Внутри строки в двойных кавычках можно указ ыв ать специальные символы (например, \n, \ r и др.), которые мы уже рассматривали в начале этой rлавы. Если внутри строки встречается кавычка, то ее необходимо экранировать с помощью 06paTHoro слэша: char str [] = rrrруппа \ rrКино\ rr\ n rr ; Если внутри строки встречается обратный слэш, то ero необходимо экранировать. Это обяз ательно следует учитывать при указании пути к файлу: char str1 [] = "С: \ \ temp \ \ new\ \ f i1e. txt"; / / Правильно char str2 [] = rrc: \ temp \ new\ f ile. txt rr; 11 Неправильно! ! ! Обратите внимание на последlПOЮ строку. В этом пути присутствуют сразу три специальных символа: \ t, \ n и \ f. После преобразования специальных символов путь будет выrлядеть следующим образом: с : <Табуляция> етр <Пер е вод с тро ки> ew <Пе ре вод фа рма та> ile . t х t Разме ститъ Ccтpoкy при инициализации на нескольких строках нельзя. Переход на новую строку вызовет синтаксическую ошибку (" error С200 1: newline в константе "): char str[] = rr s tringl string2 rr; 11 Сшибка: error С2 001: newline в :константе Чтобы разместить CCтpOKY на нескольких строках, следует перед символом перевода строки указать символ \: char str[] = rr s tringl \ string2 \ string3 rr; 11 После символа \ не ДОЛ:КНО быть никаких символов std::cout «str «std::endl; 11 stringl string2 string3 Кроме Toro, можно воспользоваться неявной конкатенацией. Если строки расположены подряд внутри одной инструкции, то они объединяются в одну большую строку. Пример: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  22  1712.10 char str[] = rr s tringl rr rr s tring2 rr rr s tring3 rr; std::cout «str «std::endl; 11 stringlstring2string3 Объявление мае сива строк выrлядит так: char str [] [2 О] = {rrStr ingl rr, rrStr ing2 rr, rrStr ing3 rr} ; std::cout «str[O] «std::end1; // String1 std::cout «str[l] «std::end1; // String2 std::cout «str[2] «std::end1; // String3 или так: char *str [] = {rrStr ingl rr , rrStr ing2 rr , rrStr ing3 rr} ; std: : cout « str[O] « std: : endl; // Stringl std: : cout « str[l] « std: : endl; // String2 std: : cout « str[2] « std: : endl; // String3 ДОСТУП к СИ!lmОЛШ\1 ВНУЧШ ССЧ)ОКН После опред еления Сстроки в переменной сохраняется адрес первоrо символа. Иными словами, название переменной является указателе м, который ссылается на первый символ строки. Поэтому доступ к элементу массива может осуще ствляться как по индексу (нумерация начинается с нуля), указанному внутри квадратных скобок, так и с использованием адресной арифметики. Например, следующие две инструкции вывода являются Эlffi ивал е нтн ы:ми : char str [] = rrStr ingrr; std: : cout « str[ 1] « std:: end1; / / t std::cout «*(str + 11 «std::end1; // t Символ можно не только получить таким образом, но и изменить: char str [] = rrStr ingrr; str[O] = 1;з1; 11 Изменение с помощью индекса *(str + 1) = 'Т ' ; 11 Изменение с помощью указателя std::cout «str «std::endl; 11 sTring Обратите внимание на то, что отдельный символ указывается внутри апостроф ов, а не внутри кавычек Если указ ать символ внутри кавычек, то вместо одноrо символа будет два: соб С1Бенно сам символ плюс нулевой символ. Объявить указатель и присвоить ему адрес строки можно следующим образом: char *р = о; char str [] = rrStr ingrr; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  23  1712.10 р = str; *р = 1;з 1; ++р; *р = IT 1 ; std::cout «str «std::endl; 11 sTring Обратите внимание на то, что перед названием строки не указывается оператор &, так как название переменной содержит адрес первоrо символа. Если использовать оператор &, ТО необходимо дополнительно указ ать индекс внутри maдpaTHblX скобок: р = &str[O]; 11 Эквивалентно: р = str; При инициализации указ ателя ему можно присвоить реко мендуется изменять, поэтому обычно перед типом const. Пример: // Перемещаем указатель на второй символ строку. Такие строки не указывaIOТ ключевое слово const char * str = rrStr ingrr; std::cout «str «std::endl; 11 String ПfllfБОll {'U]'IШОЛОВ СfЧIОIШ Для перебора символов удо бно использовать цикл f or. В переменнойсчетчику присваивается значение О (символы в строке условием продолжения является значение переменнойсчетчика символов в строке. Получить количество символов можно с st r 1en (1 . Прототип функц ии: #include <cstring> size t strlen(const char *Str); Функция st r 1en (1 возвращает количество символов без учета нулевоrо символа. Тип 51 ze t определен как 6еззнаковое целое В третье м параметре цикла f or указывается приращение на единицу на каждой итерации цикла. Выведем все символы строки в прямо м И обратном порядке: п ерв о м параметр е нумеруются с нуля), меньше количества помощью функции char str [] = rrStr ingrr; int len = std::strlen(str); 11 ВЫВОД им с и:м:во лы в пр ямом по ряд ке for (int i=O; i<len; ++i) std::cout «str[i] «std::endl; std::cout « rrrr «std::endl; 11 ВЫВОДИМ символы в обратном порядке Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  24  1712.10 for (int j=len 1; j>=O; j 1 std::cout «str[j] «std::endl; { в этом примере количество символов сохраняется в переменной le n вне цикла. Если функцию str 1e n (1 указ ать внутри условия, то вычисление количества символов будет вычислять ся на каждой итерации цикла. Поэтому количество символов лучше получ ать вне цикла или присваивать значение переменной в первом параметре цикла fo r. Пример: for (int i=O, len = std:: strlen (str); i<len; ++i) std::cout «str[i] «std::endl; Пере бор СИМВОЛОВ Сстроки С ПОМОЩЬЮ указателя и цикла fo r выполняется так: char str [] = rrStr ingrr; for (char * p=str; * р; ++р) std::cout «*р «std::endl; { в этом примере начальным значением является адрес первоrо символа. Условием продолжения цикла является значение на которое ссылается указатель. Любой символ трактуется как t rue, кроме нулевоrо символа, который имеет код о. Так как CCтpOKa завершается нулевым символом, то этот символ вернет значение false и цикл завершится. В третьем параметре цикла for указывается приращение указателя на единицу на каждой итерации цикла. В этом случае используются правипа адресной ар и Ф метики. Вме сто цикла fo r всеrда можно использовать цикл while: char *р = о; char str [] rrStr ingrr; р = str; while (*рl std::cout «*р++ «std::endl; р = str; 11 Восстанавливаем положение указателя Вначал е объявляются указатель и строка. Далее указателю присваивается адрес первоrо символа. Цикл while выполняется до тех пор, пока значение, на которое ссылается указатель, не равно нулевому символу. Внутри цикла while выводится символ, на КОТОРЫЙ ссылается указатель, а зате м указ атель перемещается на следJ'lOЩИЙ символ Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  25  1712.10 (* р++). Выражение р++ возвращает текущий адрес, а затем увеличивает ero на единицу. Символ * позволяет получить доступ к символу по указанному адресу. Последовательность выполнения СООТБетствует слеДJ'lOщей расстановке скобок: * (р++) или двум инструкциям: * р и р = р + 1. ОСНОВНЫf фУНКЦIШ для llаботы с ССЧIОЮl!lШ Перечислим основные функции для работы с Сстроками: -+ st r 1en (1  возвращает количество символов в CCтpOKe без учета нулевоrо символа. Прототип функции: #incl ude <cs tr ing> size t strlen(const char *str); Тип SlZ е t определен как 6еззнаковое целое число Пример : char str[7] = rrString rr ; std: : cout « std: : str len (str) « std:: endl; 11 6, а не 7 Определить общий размер массива можно с помощью оператора s iz ео f. Оператор возвращает размер в байтах. Так как тип с har занимает 1 байт, следовательно размер в байтах буд ет равен размеру массива. Пример : char str[20] = rrString rr ; std: : cout « sizeof str « std: : endl; 11 20 -+ st rc ру (1  копирует символы из Сстроки 30 ur се В Ccтpoкy De st и вставляет нулевой символ. В кач естве значения функция возвращает указатель на строку D es t. Если строка 3 our с е длиннее строки De st, то произойдет переполнение буфер а. Прототип функции: #incl ude <cs tr ing> char *strcpy(char *Dest, const char *Source); Пример использования функции: char str [7] ; std: : strcpy (str, rrstring rr ); std: : cout « str « std:: endl; 11 Str ing В VC++ при использовании функции strcpy (1 выводится предупреждающее сообщение ("warning С499б"), поэтому вместо функции strcpy (1 следует использовать функцию s tr ер у s (1 Прототип функции Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  26  1712.10 #incl ude <cs tr ing> errno t strcpy s(char *Dst, rsize t SizelnBytes, const char *Src); Функция st rc ру s (1 копирует символы из строки 3r с в строку D st и вставляет нулевой символ. В параметре S ize 1 nВ yt es указывается максимальное количество элементов массива Ds t. Пример: со nst sho rt S 1: Е 7' , char str [3IZE] ; strcpy s (str, SIZE, rrstring rr ); std: : cout « str « std:: endl; 11 Str ing -+ st rncp у ( 1 копирует первые Count символов из Сстроки 30urc е в CCтpOKY De st. В качестве значения функц ия возвращает указатель на строку De st. Если строка 30 ur се длиннее строки Des t, то про изойдет переполнение буфер а. Прототип функции: #incl ude <cs tr ing> char *strncpy (char *Dest, const char *Source, size t Count); Если количество символов в строке Sourc е меньше числа Count, то строка D es t 6уд ет дополнена нулевыми символа:ми, а если больше, то КОПИРYIOТСЯ ТОЛЬКО Со unt СИМВОЛОВ, при этом нулевой символ автоматически не вставляется. Пример копирования ше сти символов: char str [7] ; std: : strncpy (str, rrstring rr , 6); str[6] = 1\01; 11 Нулевой символ автоматически не вставляется std: : cout « str « std:: endl; 11 Str ing В VC++ при использовании функции s trncp у (1 выводится предупреждающее сообщение ("waming С499б "), поэтому вместо функции s tr nc ру (1 следует использовать функцию s tr nc ру s (1 Прототип функции: #incl ude <cs tr ing> errno t strncpys(char *Dst, rSlze t SlzelnBytes, const char *Src, rsize t MaxCount) Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  27  1712.10 Функция s tr nc ру s (1 копирует первые МахС ount символов из строки Sr с В строку Ds t и вставляет нулевой символ. В параметре Si ze InByt es указывается максимальное количество элементов массива Ds t. Пример: const short SIZE = 7; char str [SIZE] ; strncpys (str, S IZE, rrStr ing rr , 5); std: : cout « str « std:: endl; 11 Str in -+ st rc at (1  копирует символы из Сстроки Sourc е В конец Сстроки D est и вставляет нулевой символ. В качестве значения функция возвращает указатель на строку De st. Если строка De st имеет недостаточный размер, то произойдет переполнение буфера. Прототип функции: #incl ude <cs tr ing> char *strcat(char *Dest, const char *Source) Пример использования функции: char str[20] = rrOnerr; std: : strcat (str, rrТv.Jo rr ); std: : strcat (str, rrThree rr ) std: : cout « str « std:: endl; 11 OneT1iJOThree 06раште внимание на то, что перед копированием в строке Des t обязательно должен быть нулевой символ. Локальные переменные автоматически не инициализируются, поэтому этот код приведет к ошибке: char str[20]; 11 Локальная переменная std: : strcat (str, rronerr); 11 Ошибка, нет нулевоI"О символа! Чтобы избавиться от ошибки можно произвести инициализацию строки нулями следующим образом: char str[20] = {О}; 11 Инициализация нулями std: : strcat (str, rronerr); 11 Все нормально std: : cout « str « std:: endl; 11 Оnе В VC++ при использовании функции strcat (1 выводится предупреждающее сообщение ("warning С499б"), поэтому вместо функции strcat (1 следует использовать функцию s tr са t s (1 . Прототип функции: #incl ude <cs tr ing> Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  28  1712.10 errno t strcat s(char *Dst, rsze t SzelnBytes, const char *Src); Функция str са t s (1 копирует символы из строки Src В конец строки Ds t. В параметре S ize InB yt es указывается максимальное количество элементов мае сива Dst. Пример: const short SIZE = 20; char str [SIZE] = {О{; strcat s (str, SIZE, rrOnerr) ; strcat s (str, SIZE, rrТv.Jo rr ) ; strcat s (str, SIZE, rrThre е rr) std: : cout « str « std: : endl; // Оnе Тv.JoThr е е -+ st rnca t ( ) копирует первые Со unt символов ИЗ Сстроки Sourc е В конец строки D es t и вставляет нулевой символ. В качестве значения функция возвращает указатель на строку Des t. Обратите внимание на то, что перед копированием в строке D es t обязательно должен быть нул евой символ. Если строка Des t имеет недостаточный размер, то произойдет переполнение буфер а. Прототип функции: #incl ude <cs tr ing> char *strncat (char *Dest, const char *Source, size t Count) Пример использования функции: char str[20] = rrOnerr; std: : strncat (str, rrТv.Jo rr , 3); std: : strncat (str, rrThree rr , 3) std: : cout « str « std:: endl; 11 OneТv.JoThr В VC++ при использовании функции s trnca t (1 выводится предупреждающее сообщение ("waming С499б "), поэтому вместо функции s tr nc at (1 следует использовать функцию s tr nc at s (1 Прототип функции: #incl ude <cs tr ing> errno t strncat s(char *Dst, rSlze t SlzelnBytes, const char *Src, rsize t MaxCount) Функция st rnca t s () копирует первые Мах Со иn t символов из строки Sr с В конец строки Ds t. В параметре S ize InB yt es указывается макси мальное количество элементов массива Ds t. Пример: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  29  1712.10 const short SIZE = 20; char str[SIZE] rronerr; strncat s(str, SIZE, rrТv.Jo rr , 3); strncat s (str, S IZE, rrThree rr, 3) std: : cout « str « std:: endl; 11 OneT1iJOThr -+ st rt ok (1  разделяет Ccтpoкy St r на подстроки, используя в каче стве разделителей символы из Сстроки De 1im. При первом вызове указываются оба параметра. В качестве значения возвращается указ атель на первую под строку или нулевой указатель, если символыразделители не найдены в CCтpOKe str. Чтобы получить последующие подстроки необходимо каждый раз вызывать функцию st rto k (1 , указывая в первом параметре нулевой указ атель, а во втором параметре те же самые символыразделители. Прототип функции: #incl ude <cs tr ing> char *strtok(char *Str, const char * Delirn) Пример использования функции: char st r [] = rr а, Ь . c=d rr, * р р = std:: strtok(str, rr, .=rr); о. , while (рl std::cout « р « rrrr. , р = std:: strtok (О, rr,.= rr) 11 Результат: abcd std::cout « std: :endl; В VC++ при использовании функции strtok (1 выводится предупреждающее сообщение ("warning С499б"), поэтому вместо функции strtok (1 следует использовать функцию s tr to k s (1 Прототип функции: #incl ude <cs tr ing> char *strtoks (char *Str, const char *Delim, char **Context); Первые два параметра аналоrичны параметрам функции st rt ok (1. В параметр е Со nte х t передается адрес указ ателя. Пример: char st r [] = rr а Ь с, d rr, * р = О, * сап t ех t о. , р = strtoks(str, while (рl rr rr , , &context) ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  30  1712.10 std::cout « р « rrrr. , р // = strtoks(O, rr rr , , &context) ; Результат: abcd std::cout « std: :endl; Практически все стандартные функции, которые мы рассмотрели в этом разделе выводят предупреждающее сообщение "warning С499б", так как по умолчанию функции не ПрОИ3БОДЯТ никакой проверки корректн ости данных. В этом случае возможно переполнение буф ера. Забота о корректности данных полностью лежит на плечах проrpаммиста. Если вы увер ены в своих действиях, то можно подавить ВЫВОД предупре ждающих сообще ний. Сделать это можно двумя способами: -+ определить макрос с названием С RT  S ЕС URE  ЫО  WARN INGS в самом начале проrpаммы, перед подключением зarол овочных файл ов. При мер: #define CRT SECURE ЫО WARNINGS #incl ude <io st re am> #incl ude <cs tr ing> -+ в ставить пр асму w ar ni ng. Пр И мер: #pragma warning( disak1e : 4996 Обратите внимание По еле дир ектив # de f i nе и # р r а gm а Т очка с запя:rо й не указыва етс я. Вме сто отключения вывода сообщения можно использовать функции, у которых название заканчивается на rr S rr (например, str ер у s () вместо st rcp у ()) или переrpузить функции, чтобы они автоматически прео6разовывались в rr S rr аналоrи Для этоrо необходи мо в начале проrp аммы перед подключением зarоловочных файлов определить макрос CR Т SE CURE  С рр  OVERL OAD  S TANDARD ЫАМЕ S со значением 1. Этот макрос не производит преобразование функций, в которых указывается конкретное количество символов (например, функции st rncp у (1). Чтобы переrpузить эти функции необходимо дополнительно определить макрос с названием С RT  S ЕС URE  СР Р  OVE RLOAD  S TANDARD NAMES С OUNT и значением 1. Пример переrpузки приведен в листинrе б.3. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  31  1712.10 I .1IИСТIПП 6.3. Пере<р),кn (<роковых ф)...к.ций #define CRT SECURE срр OVERLOAD STANDARD NAМES 1     #define CRT SECURE срр OVERLOAD STANDARD NAМES COUNT 1 #include <iostream> #include <cstring> int main(1 { char str1 [7] = {О{, str2 [7] = {О{; std: : strcpy (str 1, rrStr ingrr) ; std::cout «strl «std::endl; 11 String std: : strncpy (str2, rrStr ing rr , 5); std::cout «str2 «std::endl; 11 Strin std: : cin. get (1 ; return о; Поиск и за!llfиа в ССЧ)ОКf Для поиска и замены в CCтpOKe предназначены следующие функции: -+ st rc hr (1  ищет в CCтpOKe Str первое вхождение символа Ch. В кач естве значения функция возвращает указатель на первый найденный символ в CCтpOKe St r или нулевой указатель, если символ не найден. Прототипы функции: #incl ude <cs tr ing> char *strchr(char *Str, int Ch); const char *strchr(const char *Str, int Ch); Пример использования функции: char str[] = rrstring string rr , *р = о; р = s td: : st rc hr (st r, I n I ) ; if (рl std: : cout « rrlndex: rr « р  str « std:: endl; 11 Результат: Index: 4 -+ st rr chr (1  ищет в CCтpOKe Str последнее вхождение символа Ch. В кач естве з н ач е н ия фу нкц ИЯ В ОЗЕр аща ет указ атель н а с и мв ол ИЛИ нул ев о й указ атель, е ел и символ не найден. Прототипы функции: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  32  1712.10 #incl ude <cs tr ing> char *strrchr(char *Str, int Ch); const char *strrchr (const char *str, int Ch); Пример: char str[] = rrstring string rr , *р р = std:: strrchr (str, In 1); о. , if (рl std: : cout « rrlndex: rr « р  str « std:: endl; 11 Результат: Index: 11 -+ тете hr ()  ищет в строке Pv первое вхождение символа с. Максимально просматривается N СИМВОЛОВ. В качестве значения функция возвращает указатель на первый найденный символ в строке Pv или нулевой указатель, если символ не найден. Перед присваиванием результата указателю необходимо выполнить приведение к типу char *. Прототип функции: #incl ude <cs tr ing> vo id *memchr (void * Pv, int С, si ze t Щ; в качестве примера найдем в строке символ rr n rr И выведем ero индекс, используя адресную арифметику (вычитание одноrо указ ателя из друrоrо): char str [] = rrStr ing rr , *р = о; р = (char *) st d: : тете hr (s tr, I n 1, std:: st r le n (s tr) ) ; if (рl std: : cout « rrlndex: rr « р  str « std:: endl; else std: :cout « rrNot found rr « std: :endl; -+ st rpbr k (1  ищет в CCтpOKe Str первое вхождение одноrо из символов (нулевой символ не учитывается), входящих в Ccтpoкy Con tr 01. В качестве значения функц ия возвращает указатель на первый найденный символ или нулевой указатель, если символы не найдены. Прототипы функции: #incl ude <cs tr ing> char *strpbrk(char *Str, const char *Control); const char *strpbrk (const char *str, const char *Control) Пример: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  33  1712.10 char str[] = rrstrng strngrr, *р р = std:: strpbrk (str, rrnrrr); if (рl о. , std: : cout « rrlndex: rr « р  str « std:: endl; 11 Результат: Index: 2 (индекс первой буквы rrr rr) -+ st rc sp n (1  возвращает индекс первоrо символа в CCтpOKe St r, который совпадает с одним из символов, входящих в CCтpOKY Со nt ro 1. Прототип функции: #incl ude <cs tr ing> size t strcspn(const char *Str, const char *Control) Пример: char str[] = rr s tringl string2 rr ; size t index; index = std:: strcspn (str, rringr rr) ; std: : cout « rr Index: rr « index « std: : endl; 11 Результат: Index: 2 (буква rrr rr) -+ strspn (1 совпадает ни функции: #incl ude <cs tr ing> возвращает индекс первоrо символа в CCтpOKe St r, который не с одним из символов, входящих в Ccтpoкy Со nt ro 1. Пр ототип size t strspn (const char *str, const char *Control); Пример: char str[] = rr s tringl string2 rr ; size t index; index = std:: strspn (str, rrsingtr rr ); std: : cout « rr Index: rr « index « std: : endl; 11 Результат: Index: 6 (rrl rr не входит в rrsingtr rr) -+ st rs tr (1  ищет в CCтpOKe S tr первое вхождение целоrо фрarмента из Сстроки SubSt r. В качестве значения функция возвращает указ атель на первое вхождение фраrмента в строку или нулевой указатель  в противном случае. Прототипы функции: #incl ude <cs tr ing> Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  34  1712.10 char *strstr (char * str, const char * Substr) ; со nst char * s tr st r (со nst char * S tr, со ns t char * S ub St r) Пример: char str [] = rrstr ingl string2 rr, * р р = std::strstr(str, rring2 rr ); о. , if (рl std: : cout « rrlndex: rr « р  str « std:: endl; 11 Результат: Index: 11 -+ mems et ()  заменяет первые S ize символов строки Dst символом Val. В каче стве значения функция возвращает указатель на строку Ds t. Пер ед присваиванием результата указателю необходимо выполнить приведение к типу char *. ПрОТОТ1lП функции: #incl ude <cs tr ing> void *memset(void *Dst, int Val, size t Size) Пример: char str [] = rrStr ing rr , *р = о; р = (char *)std: :memset(str, if ('рl std::exit(ll; std::cout « str « std::endl; , * , 41 ; std::cout « р « std::endl; // // ****ng ****ng Сll;lВНflШf СfЧIОК Для сравнения CCтpOK предназначены следующи е функции: -+ st rcmp (1  сравнивает CCтpOKY st r 1 с Сстрокой S tr 2 и возвращает одно из значений: . отрицательное число  если Strl меньше str2; . о  если строки равны; . по ложите ль ное число  если St r 1 больше s tr2 . Сравнение производится с учетом реrистра символов. Прототип функции: #incl ude <cs tr ing> int strcmp(const char *Strl, const char *Str2); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  35  1712.10 Пример: char str1 [] rrабв rr , str2 [] rrабв rr ; int х = о; х = std:: strcmp (str 1, str2); std::cout « х « std::endl; str1[2] = 'б'; // str1[] = "абб", str2[] х = std:: strcmp (str 1, str2); std::cout « х « std::endl; strl[2] = 1['1; 11 strl[] = rrабr rr , str2[] х = std:: strcmp (str 1, str2); std::cout « х « std::endl; / / о rrабв rr ; / /  1 rrабв rr ; / / 1 -+ st rncmp (1  сравнивает Count первых символов в CCтpOKax st r 1 и St r2 . Если нулевой байт встретится раньше, то значение параметра С ount иrнорируется. Функция возвращает одно из значений: . о  если строки равны; . отрицательное число  если Strl меньше str2; . по ложите ль ное число  если St r 1 больше s tr2 . Сравнение производится с учетом реrистра символов. Прототип функции: #incl ude <cs tr ing> int strncmp (const char *strl, const char *str2, size t Count) Пример: char str1 [] rrабв rr , str2 [] rrабr rr ; int х = о; х = std:: strncmp (strl, str2, 2); std::cout « х « std::endl; х = std:: strncmp (strl, str2, 3); std::cout « х « std::endl; / / о / /  1 -+ st rc 011 (1  функция аналоrична функц ии st rcmp (1 , но сравнение производится е учетом значения LC COLLATE в текущей локали Например, буква "е 11 в диапазон между буmами "е 11 и " ж 11 не попадает, так как БJ'Iffiа " ё 11 в кодировке ер 125 1 имеет Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  36  1712.10 код 184, 6yma "е 11  22 g, а 6yma " ж 11  23 о. Если сравнение ПРОИЗВОДИТСЯ с помощью функции strcmp (1 , то буква "е" будет больше буквы "ё" (229 > 184). При использовании функции s tr со 11 () с настройкой локали rr Russ lan R uss la . 1251 rr 6yma Il ё 11 попадет в диапазон между 6J'Iffiами 11 e ll и 11 ж ll , так как ИСПОЛЬЗJ'lOТСЯ локальные настройки по алф авиту. Если локаль не настроена, то эта функция эквивалентна функции s tr стр ( 1. Сравнение производится с учетом реrистр а символов. Прототип функции: #incl ude <cs tr ing> int strcoll(const char *Strl, const char *str2); Пример: std: : setlocale (LC COLLATE, rrRussian Russia. 1251 rr) ; char strl[] = rre rr , str2[] = rrё rr ; int х = std:: strcoll (str 1, str2); std::cout « х « std::endl; / / 1 (без настройки локали: е (код 22 91 больше ё (код 18411 11 1 (после настройки лакали: е меньше ё) -+ st rx frm (1  преобразует CCтpOKY s rc В строку специальноrо формата и записывает ее в Dst. В конец вставляется нул евой символ. Записывается не более МахСо unt СИМВОЛОВ. Если количество символов МахС ount меньше нео6ходимоrо количества символов после преобраз ования, то содер жимое D st не определено. В каче стве значения функция возвращает число необходимых символов. Чтобы просто получить количество необходимых символов (без учета нулевоrо символа), то в параметре МахСо unt указывается число О, а в параметре Dst передается нулевой указатель. Прототип функции: #incl ude <cs tr ing> size t strxfrm (char *Dst, const char *Src, size t MaxCount); Функция s trc 011 (1 прежде чем произвести сравнение неявно выполняет преобразование переданных строк в строки специальноrо формата. Функция st rxf rm ( ) позволяет произвести такое преобразование явным образом. Преобразование строки производится с учетом значения LC COLLA ТЕ в текущей локали. Если локаль не настроена, то просто выполняется копирование. В дальнейшем строки специальноrо формата можно сравнивать с помощью функции st rcmp (1. Результат сравнения будет соответствовать результату сравнения с Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  37  1712.10 помощью функц ии s trc 011 (1. Функцию str xf rm (1 следует использовать, если сравнение строк производится мноrократно. Пример : std: : setlocale (LC ALL, rrRussianRussia. 1251 rr) ; int х = о; char strl[] = rre rr , str2[] = rrё rr ; char buf1[10] = {О{, buf2[10] = {О{; х = std:: strxfrm (О, str 1, О); std: : cout « х « std:: end1; / / 6 (нужен буфер 6 + 11 std: : strxfrm (buf 1, strl, 10); std: : strxfrm (buf2, str2, 10); х = std:: strcmp (str 1, str2); std::cout « х « std::endl; 11 1 (rre rr больше rrё rr ) х = std::strcmp(buf1, buf21; std::cout « х « std::endl; 11 1 (rre rr меньше rrё rr ) -+ str lcmp (1  сравнивает Сстроки без учета реrистра символов. Для русских букв необходимо настроить локаль. Функция доступна только в VC++ и не входит в стандарт. Прототип функции: #incl ude <cs tr ing> in t st r lcmp (с onst char * Str 1, const char * St r2 ) ; Пример: std:: setlocale (LC СТУРЕ, rrRussian Russia.1251 rr ); char 51 [] = rrабв rr , 52 [] = rrАББ rr; std: : cout« str lcmp (51, 52) « std:: endl; 11 о Для сравнения строк можно также использовать функцию тетстр (1. Функция тетстр () сравнивает первые Siz е байтов массивов Ви f 1 и Buf 2. В каче стве значения функ Ц ия В озвр ащ ает -+ отрицательное число  если Buf 1 меньше Buf2; -+ О  если массивы равны; -+ по ложите ль ное число  если Ви f 1 больше в uf 2. Прототип функции: #include <cstring> Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  38  1712.10 int memcmp(const void *Bufl, const void *Buf2, size t Size); Пример: char strl [] = rrabc rr , str2 [] = rrabc rr ; int х = о; х = std::memcmp(strl, str2, sizeof std::cout «х «std::endl; strl [2] = I Ь 1; Х = std::memcmp(strl, str2, sizeof std::cout «х «std::endl; strl [2] = I d I ; Х = std::memcmp(strl, str2, sizeof std::cout «х «std::endl; Функция тетстр ( 1 производит сравнение с учетом реrистра символов. Если необходимо произвести сравнение б ез учета символов, то в VC++ можно воспользоваться функцией memlcmp (1 Для сравнения русских букв следует настроить локаль. Прототип функц ии: #include <cstring> int memicmp(const void *Bufl, const void *Buf2, size t Size); Предн азн ачение параметров и возвращаемо е значение такое же, как у функции тетстр (1 . Пример использования функции: std: : setlocale (LC  ALL, rrRussian  Russia. 1251 rr) ; 11 Настройка лакали char strl [] = rrабв rr , str2 [] = rrАБв rr ; int х = о; х = memicmp(strl, str2, sizeof str2); std: : cout « х « std:: endl; 11 о х = std::memcmp(strl, str2, sizeof str2); std: : cout « х « std:: endl; 11 1 Для сравнения строк без учета реrистра символов можно использовать функции st r lcmp (1 и  memlcmp ( 1 . Кроме Toro, можно воспольз оваться функцией st r icmp (1 , но эта функция объявлена устаревшей. Однако, все эти функции не входят в стандарт, следовательно в дрyrих компиляторах они MOryт быть недоступны. По этой причине напишем свою функцию (cas естр (1) для сравнения без уч ета реrистра символов (листинr БА). str2) ; // о str2) ; // 1 str2) ; // 1 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  39  1712.10 .1IИСТIПП 6.4. Ср nвнение етро к без )"Четn реrие тpn еИI>m олов # include <iostream > #include <clocale> #include <cstring> #include <cctype> int casecmp(const char *strl, const char *str2); int main (1 char sl[] = rrабв rr , s2[] = rrАБв rr ; std::cout «std::strcmp(sl, 52) «std::endl; std::cout «casecmp(sl, 52) «std::endl; std::cout «саsесmр(rrаб rr , rrаб rr ) «std::endl; std: : cout « casecmp (sl, rrАБ rr ) «std:: endl; std::cout «саsесmр(rrаба rr , 52) «std::endl; std: : cin. get (1 ; return о; // 1 // о // о // 226 // 2 int casecmp(const char *strl, const char *str2) std: : setlocale (LC  СТУРЕ, rrRussian Russia. 1251 rr) ; int chl = О, ch2 = О, result = о; while (11 chl = std::tolower((unsigned char)*strl); ch2 = std::tolower((unsigned char)*str2); result = chl  ch2; 11 Если значения не равны, то возвращаем результат if (result) return result; 11 Если достиrнут конец строк, то строки равны if (! chl && ! ch2) return о; ++strl; 11 Перемещаем указатели ++str 2; return о; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  40  1712.10 Функция case стр (1 принимает в качестве параметров адреса двух строк (s tr 1 и st r2) и возвращает О  если строки равны, отрицательное число  если str 1 меньше s tr2 , и положительное число  если str 1 больше str 2. Чтобы в качестве параметра можно было передать строковую константу, перед параметрами указывае м ключевое слово const (например, const char *str 1). Внутри функции производим настройку локали и перебор всех символов в строках в бесконечном цикле. Внутри цикла оба символа приводим к одному реrистру с помощью функции to 10we r ( 1 , а затем символ первой строки вычитаем из символа второй строки. Если результат вычитания не равен нулю, то возвращаем это значение из функц ии. Если результат равен нулю, то проверяем не достиrнут ли конец двух строк В этом случае строки равны и можно вернуть значение о. Если конец строк не достиrнут, то перемещаем указ атели на следующий символ и ОПЯТЬ ПРОИЗВОДИМ сравнение. KlIacc stl'iпg Сстроки являются мае сивами, поэтому работать с таЮI ми строками не очень уд 06но. Например, нельзя присвоить строку В ДВОЙНЫХ кавычках после объявления строки: char str 1 [] = rr аЬс rr; 11 Нормально char str2 [7]; str2 = rrabc rr ; / / СШибка Кроме Toro, нельзя увеличить размер строки после объявления или соединить две строки в одну с помощью операторов: char strl[] = rrabc rr , str2[7] = rrdefrr; char str3[] = str1 + str2; // Ошибка Класс st r ing предоставляет более удобный интерфей с доступа, который избавляет проrpаммиста ОТ необходимости следить за размером символьноrо массива и предоставляет множество методов для обработки строки. При необходимости можно прео6разовать объект кл асса st r ing в CCтpOKY. Название класса st r ing является лишь псевдонимом шаблонноrо класса bas lC s tr lng typedef baslc strlng<char, char tralts<char>, allocator<char> > string; Для использования класса str ing необходимо подключить файл string: # include <string> ОБЪЯВЛflШf И шпш;иализация fЧ1ОКИ Объявить объект кл асса s tr ing можно следующими способами: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '. 41  1712.10 -+ объявить экземпляр класс а без инициализации. переменной указывается название класса. Размер Пример объявления без инициализации: std: : str ing str; Для этоrо перед названием строки указывать не нужно. -+ указать Ccтpoкy внутри крyrлых ско бок или после оператора произведя инициализацию объекта. Пример: std: : str ing str 1 (rrStr ingl rr) ; std::string str2 = rrString2 rr ; Если ВО втором параметре передать ЧИСЛО, ТО МОЖНО присвоить только часть строки, а не всю СТРОКУ: тем самым std: : str ing str (rrstring rr , 3); 11 Str -+ указать объект класс а st r ing внутри крyrлых скобок или после оператора =: std: : str ing str 1 (rrStr ingrr) ; std: : str ing str2 (strl) ; std::string str3 = strl; Можно присвоить не все содержимое объекта, а ero часть. Для этоrо ВО втором параметре следует передать начальный индекс, а в третьем параметре конечный индекс. Если конечный индекс не указан, то копируется фраrмент до конца строки. Пример: std: : str ing str 1 (rrStr ingrr) ; std: : str ing str2 (strl, 31 ; // ing std: : str ing str3 (strl, О, 31 ; // Str -+ указать в первом параметре количе ство СИМВОЛОВ, а во втором параметре символ з ап ол н итель : st d: : s tr ing str (5, I s I ); 11 ss sss Присвоить значение переменной уже после объявления можно с помощью оператора =. Следить за размер ом строки не нужно. Если производится присваивание объекта класса st r ing, то создается копия исходноrо объекта, а не присваивается ссылка на Hero. Пример: std::string strl, str2; str 1 rrstring rr; 11 Присваивание сстроки str 1 = rr new str ing rr; 11 Следить за размером строки не нужно Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  42  1712.10 str2 = str 1; Вме сто оператора as sign (1 Название Прототипы метода: string &aSslgn(slze type Count, char Ch); string &assign(const char *ptr); string &assign(const char *ptr, size type Count); string &assign(const string &Right); string &assign(const string &Right, Slze type Roff, Slze type Count); template<class It> strlng &aSslgn( It First, It Last); strlng &aSslgn(const pOlnter Flrst, const pOlnter Last); strlng &aSslgn(const lterator First, const iterator Last); 11 Присваивание объекта класса string ДЛЯ присваивания значения можно воспользоваться метод о м метода указывается после имени переменной через точку. Первый прототип присваивает С оиn t символов Ch. Второй прототип позволяет присвоить Ccтpoкy целиком, а трешй прототип  только Count первых символов ИЗ Сстроки Ptr. Четвертый прототип позволяет присвоить объект класса st r ing целиком, а пятый прототип  только Со иn t символов, начиная с индекса Rof f. Остальные прототипы позволяют указать начальнJ'lO F irs t и конечнJ'lO Las t позиции с помощью итераторов. Пример: std: : str ing strl, str2 (rrBC rr) ; char str3 [] = rrDEF rr ; strl.assign(2, 1* 1) ; // Прототип 1 std: : cout « strl « std: : endl; // н strl.assign(str3); // Прототип 2 std: : cout « strl « std: : endl; // DEF strl.assign(str3, 21 ; // Прототип 3 std: : cout « strl « std: : endl; // DE strl.assign(str2); // Прототип 4 std: : cout « strl « std: : endl; // Бе strl.assign(str2, О, 11 ; // Прототип 5 std: : cout « strl « std: : endl; // Б strl.assign(str2.begin(), str2 . end (11 ; // Прототип 6 std: : cout « strl « std: : endl; // Бе Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  43  1712.10 Ввод и вывод СЧ1ОК Объекты класса string можно ВВОДИТЬ и ВЫВОДИТЬ с помощью операторов » и « соответственно. Следует учитывать, что с помощью оператора » можно BBecТ1l только фрarмент до первоrо пробельноrо символа. Пример ввода и вывода значений: std: : str ing str; std::cout « rrstr = rr; std::cin » str; 11 Получаем строку до первоrо пробела std: : cout « str « std:: endl; 11 ВЫВОДИМ строку Чтобы ввести строку необходимо воспользоваться функц ией ge t1ine ( 1 . В первом параметре указывается объект std:: cin, ВО втором параметре  объект класса st r ing, а в третьем параметре  СИМВОЛ, до KOToporo ПРОИЗВОДИТСЯ считывание. Если третий параметр не указ ан, то считывание ПРОИЗВОДИТСЯ до символа перевода СтрОЮI. Пример ввода строки: std: : str ing str; std::cout « rrstr = rr; std: :getline (std: :cin, str, I\n l ); std: : cout « str « std:: endl; 11 Получаем строку / / ВЫВОДИМ строку ПllfобllазоваlШf оБЪfкта в ССЧIОКУ ИЛИ В lШ1ССИВ сmmолов Для преобразования объекта класса s tr ing в дрyrо й тип предназначены следующие методы: -+ с  s tr ()  возвращает указатель типа const char *. Ero можно использовать в тех случаях, коrда необходимо передать Ccтpoкy (например, в функцию), вместо объекта класса str ing. Пзменять такую строку нельзя. Кроме Toro, следует учитывать, что после изменения объекта указ атель может стать некорректным, поэтому после изменения объекта необходимо обновить значение указателя. Прототип метода: #nclude <strng> const char *с str () const; Пример преобразования объекта клас са s tr ing в Ccтpoкy: std: : str ng str 1 (rrStr ngrr) ; char str2 [8 О] ; strcpy s (str2, 8 О, strl. с str () ) ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 44  1712.10 std::cout « str2 « std: :endl; 11 String -+ da ta ()  возвращает указатель типа с ons t char * В отличие от метод а с st r (1 метод da ta (1 возвращает указатель на массив символов (нулевой символ не до бавляется), а не на CCтpOKy. Если необходимо получить строку, заканчивaIOЩYIOСЯ нулевым СИМВОЛОМ, то следует использовать метод с str () . Следует учитывать, что после изменения объекта указатель может стать некорректным, поэтому после изменения объекта необходимо обновить значение указателя. Прототип метода: #include <string> const char *data () const; Пример: std::string str(rrString rr ) const char *р = о; р = s tr . dat а ( 1 ; std::cout « р[О] « std: :end1; // s std::cout « р[5] « std: :end1; // g -+ со ру ()  копирует Со unt СИМВОЛОВ, начиная с индекса Off, в символьный массив pt r. Если индекс не указан, то символы копируются с начала строки. Нулев ой символ автоматически не добавляется. В кач естве значения метод возвращает количество скопированных СИМВОЛОВ. Прототип метода: #include <strng> Slze type сору (char *ptr, Slze type Count, sze type Off=O) const; Пример использования метода сор у ( 1 : std: : str ng str 1 (rrStr ngrr) ; char str2[20] = {О{, str3[20] = {О{; std::baslc strlng<char>: :Slze type count; count = str1.copy(str2, 5); std: : cout « count « std:: endl; / / 5 / / Strin std::cout « str2 « std: :endl; str1. copy(str3, 3, 1); std::cout « str3 « std: :endl; / / tr i Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  45  1712.10 в VC++ при использовании метода сор у (1 выводится предупреждающее сообщение ("warning С499б "), поэтому вместо метода со ру (1 следует использовать метод Сор у s (1 Прототип метод а #incl ude <cs tr ing> Slze type Copys(char *Dest, Slze type Dest slze, size type Count, Slze type Off=O) const; Метод Со ру s (1 копирует Count символов, начиная с индекса Of f, в символьный массив D est. Если индекс не указ ан, то символы КОПИРYIOТСЯ С начала строки. В параметре De st 51 ze указывается размер символьноrо массива De st Пример: std: : str ing str 1 (rrStr ingrr) ; char str2[20] = {О{, str3[20] = {О{; std::baS1C strlng<char>: :Slze type count; count = strl. Сору s (str2, slzeof str2, 5); std: : cout « count « std:: endl; 11 5 std: : cout « str2 « std: : endl; 11 Strin strl. Сору s (str3, sizeof str3, 3, 1); std::cout « str3 « std: :endl; / / tr i ПОЛУЧflШf И ИЗlllfИflШf II;lЗlllfll;l fЧ1ОКИ Для получ ения и изменения размера строки предназначены следующие методы: -+ si "е (1 и 1ength (1  возвращают текущее количество символов в строке. Прототипы методов: #include <string> Slze type size () const; Slze type length () const; Пример: std::string str(rrstring rr ); std: : cout « str. size () «std:: endl; 11 6 std: : cout « str .1ength (1 «std:: end1; / / 6 -+ capacity ()  возвращает количество символов, которое можно записать в строку без перераспределения памяти. Прототип метода: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  46  1712.10 #nclude <strng> Slze type capacity () const; Пример: std::string str(rrstring rr ); std: : cout « str. size () «std:: endl; std: : cout « str. capacity () « std:: endl; / / 6 / / 15 str += rr string2 stringз rr ; std: : cout « str. size (1 «std:: end1; / / 22 std: : cout « str. capacity (1 « std:: end1; / / 31 -+ re se rve ()  позволяет задать :минимальное количество символов, которое можно записать в строку без перераспределения памяти. Как видно из предыдущеrо примера, выделение дополнительной па:мяти ПРОИЗВОДИТСЯ автоматически с некоторым запасом. Если дозапись в строку ПРОИЗВОДИТСЯ часто, ТО ЭТО мож ет снизить э фф ективность проrpаммы, так как перераспределение памяти будет выполнено несколько раз. Поэтому, если количество символов зар анее известно, то следует указ ать ero с помощью метода r es erve () . Прототип метода: #include <string> void reserve(size type Newcap = О); Пример указ ания минимальноrо размера строки: std::string str(rrString rr ) str.reserve(50); std: : cout « str. size () «std:: endl; 11 6 std: : cout « str. capacity (1 « std:: end1; / / 63 str += rr strng2 strngзrr; std: : cout « str. size (1 «std:: end1; / / 22 std: : cout « str. capacity (1 « std:: end1; / / 63 -+ shr ink  t о  f it (1  уменьшает размер строки до минимальноrо значения. Прототип метода: #nclude <strng> vod shrnk to ft(); Пример: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 47  1712.10 std::strng str(rrStrngrr) str.reserve(50); std: : cout « str. capacity (1 « std:: end1; / / 63 str.shrink to fit(); std: : cout « str. capacity (1 « std:: end1; / / 15 -+ re si ze ()  задает количество символов в строке, равное числу Newsi z е. Если указанное количество символов меньше текущеrо количества, ТО лишние символы будут удалены. Если количество символов необходимо увеличить, то в параметре Ch можно указать символ, который заполнит новое пространство. Прототипы метода: #include <string> void reSlze (slze type Newsize); vo id re 51 ze (s 1 ze t уре News iz е, char Ch); Пример: std::string str(rrString rr ) str. resize (4) std::cout « str « std::endl; / / Str i str.resize (8, 1* 1); std::cout « str « std::endl; 11 Stri**** -+ c1ear (1  удаляет все символы. Прототип метода: #include <string> void clear () ; Пример: std::string str(rrString rr ) str.clear (); std: : cout « str. size () «std:: endl; / / о -+ empt у ()  возвращает значение true, если строка не содержит символов, и false  в противном случае. Прототип метода: #nclude <strng> bool empty () const; Пример: std::strng str(rrstrngrr); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  48  1712.10 if (str. empty (11 std::cout « rrCTpoKa пустая,r « std: :endl; else std::cout « rrCTpOKa содержит символы,r « std::endl; -+ тах SlZ е ()  возвращает максимальное количество символов, которое может содержаться в строке. Прототип метод а: #nclude <strng> Slze type тах size () const; Пример: std::string str(rrstring rr ); std: : cout « str. ,"ах size (1 « std:: end1; / / 4294967294 ПОЛУЧflШf И ИЗ!llfИflШf fОДfllЖИ!llоrо fЧ1ОКИ К любому символу объекта класса str ing можно 06рашться как к элементу массива. Достаточно указать ero индекс в квадратных скобках. Нумерация начинается с нуля. Можно как получить символ, так и изменить ero. Если индекс ВЫХОДИТ за rраницы диапазона, ТО возвращаемое значение не определено. Пример доступа к символу по и нд ексу: std::string str(rrC rr ); std::cout «str[O] «std::end1; // С str[O] = 'D ' ; std::cout «str[O] «std::end1; // D Получить количество символов в строке позволяет метод s iz е () . в каче стве примера выведем все символы по одному на строке: std::string str(rrstring rr ); for (int i=O, с = str.size (); i<c; ++i) std::cout «str[i] «std::endl; Для объектов кл асса st r ing определена операция конкатенации (объединения строк). Оператор + позволяет объединить: -+ два объекта класса s tr ing: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 49  1712.10 std:: string strl (rrA rr ) str2 (rrB rr) str3; str3 = str1 + str2; / / АВ -+ объект кл асса s tr ing с символом: std:: string strl (rrA rr ) char ch = I В I ; str2, str3; str2 str3 strl + ch; ch + strl; // АВ // ВА -+ объект кл асса s tr ing с Сстрокой: std: : str ing strl (rrA rr ), str2, str3; str2 strl + rrB rr ; // АВ str3 rrB rr + strl; // ВА Обратите внимание на то, что оператор + для объединения двух CCтpOK применятъ нельзя. Чтобы объединить две Сстроки они указ ываются без операторов между ними. Пример: str3 ; Ошибка Нормально Нормально Помимо оператора + доступен оператор += который производит конкатенацию с присваиванием: std: : str ing strl (rrA rr ) , str2, str2 rrc rr + rrB rr ; // str2 rrc rr + strl + rrB rr ; // str3 rrc rr rrB rr ; // std: : str ing strl (rrA rr ) , str2 (rrB rr ) ; strl += rrc rr ; // АС str2 += strl; // ВАС str2 += strl + rrD rr ; // BACACD Для получ ения и изменения сод ержимоrо строки предназначены следующие методы: -+ at (1  возвращает ссылку на символ, расположенный по индексу ОН. Метод позволяет как получить символ, так и изменить ero. Если индекс ВЫХОДИТ за rpаницы диапазона, ТО метод rенерирует исключение. Прототипы метода: #include <string> reference at (size type Off); const reference at (slze type Off) const; Пример: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  50  1712.10 std: : str ing str 1 (rrStr ingl rr) const std:: str ing str2 (rrStr ing2 rr) std::baslc strlng<char>: :reference rstrl = strl.at(O); std::baslc strlng<char>: :const reference rstr2 = str2.at(6); rstrl = I S 1; str1. at (61 13 1; std: : cout « strl « std: : endl; // str ing3 std: : cout « str1.at (11 « std: : endl; // t std: : cout « rstr2 « std: : endl; // 2 (метод at (11 std: : cout « s tr2 [6] « std: : endl; // 2 ( оператор []I -+ fr оп t (1  возвращает ссылку на первый символ в строке. Метод позволяет как получить символ, так и изменить ero. Прототипы метода: #include <string> reference front () ; const reference front () const; Пример: std::string str(rrString rr ) str.front() 1;з1; std: : cout « str. front () « std:: endl; 11 s -+ back (1  возвращает ссылку на последний символ в строке. Метод позволяет как получить символ, так и изменить ero. Прототипы метода: #include <string> reference back(); со nst re fe r еnс е back () const; Пример: std::string str(rrString rr ) str.back() IG 1 ; std: : cout « str. back (1 «std:: end1; / / G -+ subs tr (1  возвращает фрarмент строки, состоящий из С ount символов, начиная с индекса Off. Если начальный индекс не задан, то предполarается, что индекс равен Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  51  1712.10 о. Если длина не задана, то возвращается фраrмент, начиная с индекс а ОН до конца строки. Прототип метода: #nclude <strng> string substr (size type Off=O, Slze type Count=npos) const; Пример: std: : str ing str 1 (r'123 4yr) str2 = strl.substr(); std::cout « str2 « std: :endl; str2 ; // 12345 str2 = str1.substr(21 std::cout « str2 « std: :endl; st r2 = s tr 1 . subs tr (2, 2); std::cout « str2 « std: :endl; / / 345 / / 34 -+ push  back (1  добавляет символ Ch в конец строки. Прототип метода: #include <string> void pushback (char Chl Пример: std::string str(rrString rr ) str.pushback (111); std: : cout « str « std:: endl; 11 Str ingl -+ ар ре nd (1  доб авляет символы и строки в конец исходной строки. Метод можно использовать для конкатенации вместо операторов + и +=. Прототипы метода: #incl ude <st r ing> string &append (Slze type Со unt, char Chl string &append (const char *ptr) ; string &append (const char *ptr, size type Count) ; string &append (const string &Right 1 ; string &append(const string &Right, size type Roff, Slze type Count); templa te <с las s It> strlng &append( It First, It Last 1 string &append(const pOlnter First, const pOlnter Last) Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  52  1712.10 string &append (const lterator Flrst, const iterator Last); Первый прототип доб авляет Со un t символов Ch в конец строки. Второй прототип позволяет добавить Ccтpoкy целико М, а третий прототип  только Count первых символов из Сстроки Ptr. Четвертый прототип позволяет добавить объект класса st r ing целиком, а пятый прототип  только Со unt СИМВОЛОВ, начиная с индекса Ro ff. Остальные ПрОТОТ1lПЫ позволяют указ ать начальнYIO F ir st и кон ечнJ'lO L ast позиции с помощью итераторов (указателей). Пример: std: : str ing strl (rrA rr ) str2 (rrBc rr ) ; char str3 [] rrDEF rr ; str1.append(2, 1* I ) ; // Прототип 1 std: : cout « strl « std: : endl; // АН str1.append(str31; // Прототип 2 std: : cout « strl « std: : endl; // A**DEF strl.append(str3, 21 ; // Прототип 3 std: : cout « strl « std: : endl; // A**DEFDE strl = rrA rr ; str1.append(str21; // Прототип 4 std: : cout « strl « std: : endl; // АВС strl.append(str2, О, 11 ; // Прототип 5 std: : cout « strl « std: : endl; // АВСВ str1.append(str2.begin(l, str 2 . end ( 1 1 ; // Прототип 6 std: : cout « strl « std: : endl; // АВСВВС -+ inse rt ()  вставляет символы и строки в позицию указаннJ'lO индексом или итератором (указателем). Остальные элементы сдвиrаются к концу строки. Прототипы метода: #incl ude <st r ing> strlng &lnsert(slze type Off, Slze type Count, char Ch); 11 1 iterator insert (const iterator Where, char Ch); 11 2 void insert (const iterator Where, Slze type Count, char Ch); string &lnsert(slze type Off, const char *ptr); string &lnsert(slze type Off, const char *ptr, // 3 // 4 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  53  1712.10 Slze type Count) ; string &lnsert (slze type Off, const string &Rightl ; string &lnsert (slze type Off, const string &Right, Slze type Roff, size type Count) ; template<class It> void insert(const iterator Where, It F irst, It L ast) ; void insert (const iterator Where, const pOlnter First, const pOlnter Last); void insert(const iterator Where, const iterator First, const iterator Last); it era t or ins er t (со nst it е ra t or Whe re) ; // 5 // 6 // 7 // 8 // 9 // 10 // 11 Прототип 1 вставляет Count символов Ch в позицшо с индексом Of f. Прототип 2 вставляет символ Ch в позицию на которую указывает константный итератор Whe re. Прототип 3 вставляет Count символов С h в позицию на которую указывает константный итератор Whe re. Прототип 4 позволяет вставить CCтpOKY р tr целиком в позицию с индексом Off, а прототип 5  только Со иn t первых символов из c строки Р tr. Прототип 6 позволяет вставить объект класса st r ing Right целиком в позицию с индексом Of f, а ПрОТОТ1lп 7  только Со unt символов, начиная с индекса Ro Н. Прототипы 8, 9 и 1 О позволяют указать начальную F ir st и кон ечную L ast позиции с помощью итераторов (указателей). Символы будут вставлены в позицию на которую указывает константный итератор Whe re. Прототип 11 вставляет нулевой символ в позицию на KOTOpJ'lO указывает константный итератор Wher е. Пример : std: : str ing str 1 ("123 4У') str2 ("### ") ; char str3 [] "+++" ; str1.insert(2, 5, 1*1); std::cout « str1 « std: :endl; str1 = "123 4У'; str1. insert (str1.begin () + 2, 1 * 1) std::cout « str1 « std: :endl; str1 = "123 4У'; str1. insert (str1.begin () + 2, 5, 1 * 1) std::cout « str1 « std: :endl; // Про то тип 1 // 12*****345 // Про то тип 2 // 12*345 // Про то тип 3 // 12*****345 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  54  1712.10 strl = rr 123 4yr; strl. insert (2, str3); std::cout « strl « std: :endl; strl = rr 123 4yr; strl. insert (2, str3, 1); std::cout « strl « std: :endl; strl = rr 123 4yr; strl. insert (2, str2); std::cout « strl « std: :endl; strl = rr 123 4yr; strl. insert (2, str2, О, 1); std::cout « strl « std: :endl; strl = rr 123 4yr; strl. insert (strl.begin () + 2, str2 .begin (1, str2. end (11 ; std::cout « strl « std: :endl; strl = rr 123 4yr; str1. insert (str1.begin (1 + 21 ; / / Прототип 11 std: : cout « str1. с str (1 «std:: end1; / / 12 / / Прототип 4 / / 12+++345 / / Прототип 5 // 12+345 / / Прототип 6 // 12###345 / / Прототип 7 // 12#345 / / Прототип 8 // 12###345 -+ ро р Ьас k (1  удаляет последний символ в строке Прототип метода: #include <string> vOld рор back (1 ; Пример: std:: string str ("12345"); str.pop back(l; std::cout « str « std::endl; str.pop back(l; std::cout « str « std::endl; / / 1234 / / 123 -+ er as е (1  удаляет один символ или фраrмент. Остальные элементы сдвиrаются к началу строки. Прототипы метода: #include <string> Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  55  1712.10 iterator erase(const iterator Where); it era t or erase (с ons t i te r at о r F irs t, const i te r at о r Last); st r lng & eras е (51 ze typ е Off= О, SlZ е typ е Со иn t= пр о s) ; Первый прототип удаляет символ, на который указывает итератор (указатель) Where. Второй прототип позволяет удалить фр асмент строки между итераторами F irst и Last. Третий прототип удаляет фрarмент ДЛИНОЙ С ount, начинaIOЩИЙСЯ с индекса Off . Если начальный индекс не указ ан, то предполаrается, что индекс равен о. Если длина не указ ана, то уд аляется фрarмент от индекса ОН до конца строки. Пример: std:: string str ("12345"); str.erase(str.begin() + 21 ; // Прототип 1 std: : cout « str « std: : endl; // 1245 str = r'12 34yr; str.erase(str.begin() , str .begin (1 + 21 ; // Прототип 2 std: : cout « str « std: : endl; // 345 str = r'12 34yr; str.erase (3); // Прототип 3 std: : cout « str « std: : endl; // 123 str = r'12 34yr; str. erase (О, 21 ; // Прототип 3 std: : cout « str « std: : endl; // 345 -+ swap (1  меняет содержимое двух строк местами. Прототип метода: #include <string> void swap(string &Right); Пример: std: :string strl(rr1234yr), str2 ("67890 r ,); strl.swap(str2); std::cout « str1 « std: :end1; // 67890 std::cout « str2 « std: :end1; // 12345 -+ re p1ac е ( 1 заменяет фр асме нт строки отдельным символом или под строкой . Если вставляемая под строка меньше фрarмента, то остальные символы сдвиrmoтся к Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  56  1712.10 началу строки, а если больше, то раздвиrmoтся таким образом, чтобы вместить всю вставляе мую подстроку. Прототипы метода: #include <string> string &replace(slze type Off, Slze type МО, Slze type Count, char Ch); // 1 string &replace(const lterator Flrst, const iterator Last, Slze type Count, char Ch); string &replace(slze type Off, Slze type МО, const char *ptr); string &replace(slze type Off, size type МО, const char *ptr, Slze type Count); // 2 // 3 // 4 const char *ptr); string &replace(const lterator Flrst, const iterator Last, // 5 string &replace(const lterator Flrst, const iterator Last, // 6 const char *ptr, size type Count); string &replace(slze type Off, Slze type МО, const string &Right); string &replace(slze type Off, Slze type МО, const string &Right, Slze type Roff, Slze type Count 1; / / 8 // 7 string &replace(const lterator Flrst, const iterator Last, // 9 const string &Right); template<class It> string &replace(const iterator First, const iterator Last, It First2, It Last21; // 10 string &replace(const lterator Flrst, const iterator Last, const pOlnter Flrst2, const pOlnter Last2); 11 11 string &replace(const lterator Flrst, const iterator Last, const iterator First2, const iterator Last2); Прототип 1 наЧИНaIOщеrо // 12 вставляет С ount символов с индекса ОН. Прототип 2 С h вместо фр асмента длиной ЫО, вставляет Count символов Ch вместо Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  57  1712.10 фраrмента, оrpаниченноrо элемента:ми на которые указыв aIOT итераторы F irs t и Last. Пр ототип 3 позволяет вставить Ccтpoкy Р tr целиком вместо фраrмента ДЛИНОЙ МО, наЧИНaIOщеrося с индекса Off, а прототип 4  только Count первых символов из Сстроки pt r. Прототип 5 вставляет CCтpOKY pt r целико м вместо фраrмента, оrpаниченноrо элемента:ми на которые указыв aIOT итераторы F irs t и Last, а прототип 6  только Со иn t первых символов из Сстроки pt r. Прототип 7 позволяет вставить объект класса str ing Right целиком вместо фраrмента ДЛИНОЙ МО, наЧИНaIOщеrо с индекса Off, а ПрОТОТ1lП 8  только Count СИМВОЛОВ, начиная с индекса Roff. Прототип 9 вставляет объект класса str ing Right целиком вместо фраrмента, оrpаниченноrо элемента:ми на которые указыв aIOT итераторы F irs t и Last. Прототипы 1 О, 11 и 12 позволяют указать начальную F ir st и конечную L ast ПОЗИЦИИ заменяемоrо фрarмента с ПОМОЩЬЮ итераторов. Вставляемая под строка задается с помощью итераторов F ir st 2 и Last 2. Пример : std: :string strl(rr1234yr), str2 ("67890"); char str3[] = "abcd"; str1.replace(0, 3, 4, 1 * 1) ; // Про то тип 1 std: : cout « str1 « std: : endl; // ****45 str1.replace(str1.begin() , str1.begin (1 + 3, 3, 1+ 1); // Про то тип 2 std: : cout « str1 « std: : endl; // +++*45 str1.replace(0, 4, str3) ; // Про то тип 3 std: : cout « str1 « std: : endl; // abcd45 str1.replace(0, 4, str3, 31 ; // Про то тип 4 std: : cout « str1 « std: : endl; // аЬс45 str1.replace(str1.begin() , str1.begin (1 + 3, "0123") ; // Про то тип 5 std: : cout « str1 « std: : endl; // 012345 str1.replace(str1.begin() , str1.begin (1 + 1, str3, 21 ; // Про то тип 6 std: : cout « str1 « std: : endl; // аЫ2345 str1.replace(0, 5, str2) ; // Про то тип 7 std: : cout « str1 « std: : endl; // 6789045 str1.replace(0, 5, str2, 1, 21 ; // Про то тип 8 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  58  1712.10 std::cout « strl « std: :endl; str1.rep1ace(str1.begin(l, str1.begin(1 str2) ; std::cout « strl « std: :endl; str1. rep1ace (str 1. begin (1, str1. end (1, str2 .begin (1, str2. end (11 ; std::cout « strl « std: :endl; Поиск в СЧ1ОКf // 7845 + 1, // Про то тип 9 // 67890845 // Про то тип 10 // 67890 Перечислим методы, предназначенные ДЛЯ поиска в строке: -+ f ind (1  производит поиск символа или фр асме нта с начала строки. Возвращает индекс первоrо совпадения, если фраrмент найден, или значение константы std: : str ing: : npos  В противном случае. Поиск зависит от реrистра СИМВОЛОВ. Прототипы метода: #include <string> Slze type f ind (char Ch, Slze type Off=O) const; Slze type f ind (const char *ptr, Slze type Off=O) const; Slze type f ind (const char *ptr, Slze type Off, Slze type Count) const; Slze type flnd(const strlng &Rlght, Slze type Off=O) const; Первый прототип ищет в строке символ С h, начиная с индекса Of f. Второй прототип позволяет произвесТ1l поиск Сстроки целиком, начиная с индекса Off, а третий прототип  только С оиn t первых символов Сстроки. Четвертый прототип ищет объект класса s tr ing, начиная с индекса Off. Если индекс Off не задан, то предполarается, что ero значение равно о. Пример: std: : str ing str ("123454321"1, str2 (rr2 rr ); std: : cout « str. find (121) « std: : endl; // 1 std: : cout « (intlstr.find( '6'1 « std: : endl; // 1 std: : cout « str. find (121, 31 « std: : endl; // 7 std: : cout « str. find (rr2 rr) « std: : endl; // 1 std: : cout « (int)str.find(rr6 rr ) « std: : endl; // 1 std: : cout « str. find (rr2 rr, 31 « std: : endl; // 7 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  59  1712.10 std: : cout « str. find (rr2 oorr, 3, 11 « std: : endl; // 7 std: : cout « str. find (str21 « std: : endl; // 1 std: : cout « str.find(str2, 31 « std: : endl; // 7 -+ rf ind (1  производит поиск символа ипи фр асмента с конца строки. Возвращает индекс первоrо с конца совпадения, если фр arMeHT найден, или значение константы std: : str ing: : npos  В противном случае. Поиск зависит от реrистра СИМВОЛОВ. Прототипы метода: #include <string> Slze type rfind (char Ch, Slze type Off=npos) const; Slze type rfind (const char *ptr, Slze type Off=npos) const; Slze type rfind(const char *ptr, Slze type Off, Slze type Count) const; 51 ze t ур е r f ind (с onst st r ing & Righ t, siz е type Of f= пр 05) С ONS t; Первый прототип ищет в строке символ С h, начиная с индекса Of f. Второй прототип позволяет произвесТ1l поиск Сстроки целиком, начиная с индекса Off, а третий прототип  только С оиn t первых символов ССтрОКИ. Четвертый прототип ищет объект класса st r ing, начиная с индекса Off. Поиск производится от индекса Of f к началу строки. Если индекс Of f не задан, то предполarается, что ero значение равно индексу последнеrо элемента. Пример : std:: string str ("123454321") str2 ("2"); std: :cout « str.rfind( 121) « std: :endl; 11 7 std::cout« (intlstr.rfind('б'l «std::end1; // 1 std: : cout « str. rf ind ( 12 1, 3) « std:: endl; 11 1 std: : cout « str. rf ind ("2 ") « std:: endl; 11 7 std: : cout « (int) str. rf ind ("6 ") « std:: endl; 11 1 std::cout «str.rfind("2", 3) « std::endl; 11 1 std: : cout « str. rf ind ("200", 3, 1) « std:: endl; 11 1 std: : cout « str. rf ind (str21 «std:: end1; / / 7 std::cout « str.rfind(str2, 31 « std: :end1; // 1 -+ f ind f irs t  of (1  производит поиск символа ипи входящеrо в указ анную строку. Поиск производится С возвращает индекс первоrо совпадения, если символ какоrоли60 символа, начала строки. Метод найден, или значение Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  60  1712.10 константы std: : string: : npos  В противном случае. Поиск зависит от реrистра СИМВОЛОВ. Прототипы метода: #include <string> Slze type f ind f irst of (char Ch, Slze type Off=O) const; Slze type find first of(const char *ptr, Slze type Off=O) const; Slze type find first of(const char *ptr, Slze type Off, Slze type Count) const; Slze type find first of(const strlng &Rlght, Slze type Off=O) const; Первый прототип ищет в строке символ С h, начиная с индекса Of f. Второй прототип позволяет найти совпадение с какимли60 символом из Сстроки, начиная с индекса Of f, а третий прототип  учитывает только Со иn t первых СИМВОЛОВ ССтрОКИ. Четвертый прототип ищет совпадение с какимли60 символом из обь екта кл асса st r ing, начиная с индекса Off. Если индекс Off не задан, то предполarается, что ero значение равно о. Пример: std: :string str ("123454321") str2 ("862"); std: : cout « str.find first of ( '2 '1 « std: : endl; // 1 std: : cout « (int 1 str. find f ir st of ( '6' 1 « std: : endl; // 1 std: : cout « str.find first of ( 12 1, 31 « std: : endl; // 7 std: : cout « str.find first of (" 8 62 ") « std: : endl; // 1 std: : cout « str.find first of (" 8 62 " , 31 « std: : endl; // 7 std: : cout « str.find first of (" 2 50" , 3 , 21 « std: : endl; // 4 std: : cout « str.find first of (str21 « std: : endl; // 1 std: : cout « str.find first of (str2, 31 « std: : endl; // 7 -+ f ind f irs t по t of (1  возвращает индекс первоrо символа, который не совпадает ни с одним из символов, входящих в указанную строку. Если ничеrо не найдено, то возвращается значение константы std: : str ing: : npos. Поиск зависит от реrистра символов. Прототипы метода: #include <string> Slze type f ind f irst not of (char Ch, Slze type Off=O) const; Slze type find first not of(const char *ptr, Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  61  1712.10 Slze type Off=O) const; Slze type f ind f irst not of (const char *ptr, Slze type Off, Slze type Count) const; Slze type find first not of(const strlng &Rlght, Slze type Off=O) const; Первый прототип ищет в строке символ, который не совпадает с символом Ch. Второй прототип возвращает индекс первоrо символа, который не с ОБпадает ни с одним ИЗ символов, входящих в Ccтpoкy pt r, а третий прототип  учитывает только Со иn t первых символов Сстроки Р tr. Четвертый прототип возвращает индекс первоrо символа, который не совпадает ни с ОДНИМ ИЗ СИМВОЛОВ, ВХОДЯЩИХ В объект класса s tr ing. Поиск ПРОИЗВОДИТСЯ начиная с индекса Of f. Если индекс Of f не задан, то предполarается, что ero значение равно о. Пример: std: : str ing str ("123454321"1, str2 ("8621"); std: : cout « str.find first not of( 12 I ) « std: : endl; // о std: : cout « str.find first not of( 12 I , 31 « std: : endl; // 3 std: : cout « str.find first not of ("8621") « std: : endl; // 2 std: : cout « str.find first not of("8621", 3 1 « std: : endl; // 3 std: : cout « str.find first not of ("250", 3 , 21 « std: : endl; // 3 std: : cout « str.find first not of(str21 « std: : endl; // 2 std: : cout « str.find first not of(str2, 31 « std: : endl; // 3 -+ f ind 1ast о f (1  метод аналоrичен методу f ind  f irst of (1, НО поиск ПрОИЗБОДИТСЯ С конца строки, а не с начала. Пр ОТОТИПЫ метода: #include <string> Slze type f ind last of (char Ch, Slze type Off=npos) const; Slze type find last of(const char *ptr, SlZ е type Of f= пр os) с onst; Slze type find last of(const char *ptr, Slze type Off, Slze type Count) const; Slze type find last of(const strlng &Rlght, SlZ е type Of f= пр os) с onst; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  62  1712.10 -+ f lnd 1ast not of (1  метод аналоrичен методу f lnd f lrs t not о f (1, но ПОИСК ПрОИЗБОДИТСЯ С конца строки, а не с начала. Пр ототипы метода: #nclude <strng> Slze type f ind last not of (char Ch, Slze type Off=npos) const; Slze type find last not of(const char *ptr, Slze type Off=npos) const; Slze type find last not of(const char *ptr, Slze type Off, Slze type Count) const; Slze type find last not of(const strlng &Rlght, Slze type Off=npos) const; В качестве при мера проверим состоит ли строка только из цифр или содержит также буквы: std::string str(rrS487 rr ); int index = о; index = str.find last not of(rr01234567sg rr ); if (index == std: :string: :npos) std::cout « rrCTpOKa содержит только цифры,r « std::endl; else std: :cout « rrИет rr « std: :endl; Сll;lВНflШf fЧ1ОК Для сравнения двух объектов класса st r ing или объекта класса s tr ing и Сстроки предназначены операторы == (равно), ,= (не равно), < (меньше), > (больше), <= (меньше или равно) и >= (больше или равно). Пример сравнения строк std: : string strl (rrabc rr ), str2 (rrabcd rr ) ; if (str1 == str21 std::cout « rr s trl str2 rr « std::endl; e1se if (str 1 < str21 std::cout « rr s trl < str2 rr «std::endl; e1se if (str 1 > str21 std::cout « rr s trl > str2 rr «std::endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  63  1712.10 { // Результат: str1 < str2 Обратите внимание на то, что сравнивать с помощью ЭТ1lХ операторов Сстроки нельзя, так как будут сравниваться адре са, а не символы в строках. Для сравнения CCтpOK необходимо использовать специальные функции, например, st rcmp (1. Чтобы операторы работали корректно, необходимо, чтобы справа ипи слева от оператора находипся объект класса str ing. Пример: char а[] = rrabc rr , Ь [] = rrabc rr ; std: : str ing с (rrabc rr) ; std::cout « (а == Ь) «std::endl; 11 Сравниваются адреса!!! std::cout «std::strcmp(a, ы «std::end1; //ОК (равныl std::cout « (а == сl «std::end1; //ОК (равныl std::cout « (с == ы «std::end1; //ОК (равныl Для сравнения объекта класса st r ing с дрyrим объектом класса str ing или Сстрокой можно использовать метод сотр ar е () . Прототипы метода: #include <string> int compare(const char *ptr) const; int compare(Slze type Off, Slze type МО, int compare(Slze type Off, Slze type МО, Slze type Count) const; int compare(const string &Right) const; int compare(Slze type Off, Slze type МО, const string &Right) const; int compare(Slze type Off, Slze type МО, const string &Right, Slze type Roff, Slze type Count) const; 11 6 Прототип 1 сравнивает объект класса str ing с Сстрокой. Прототип 2 сравнивает фрarмент объекта кл асса s tr ing длиной ЫО начиная с индекса ОН с Сстрокой, а прототип 3 позволяет дополнительно указ ать длину фраrмента в CCтpOKe с начала строки. Прототип 4 сравнивает два объекта класса str ing. Прототип 5 сравнивает фрarмент объекта класс а s tr ing длиной ЫО начиная с индекса ОН с дрyrим объектом кл асса str ing, а прототип 6 позволяет дополнительно указать длину Со unt и начальный индекс Rof f в строке Righ t. Сравнение производится с учето м реrистра символов. В качестве зн ачения метод возвращает: const char * ptr) const char * Ptr, const; // 1 // 2 // 3 // 4 // 5 -+ отрицательное число  если объект класса string меньше строки, переданной в качестве параметра; -+ О  если строки равны; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  б4  1712.10 -+ по ложите ль ное число  если объект класса st r ing больше строки, переданной в кач е ств е параметр а. Пример сравнения строк std: : string strl (rrabc rr ), str2 (rrabd rr ) ; std: : cout « strl. compare (rrabd rr ) «std:: endl; std: : cout « strl. compare (О, 2, rrab rr ) «std:: endl; std: : cout « strl. compare (О, 2, rrabc rr , 2) « std:: endl; std::cout «strl.compare(str2) «std::endl; std::cout «strl.compare(O, 2, str2) «std::endl; std::cout «strl.compare(O, 2, str2, О, 2) « std:: endl; // Прототип 1 // Прототип 2 // Прототип 3 // Прототип 4 // Прототип 5 // Прототип 6 ИТflНПОllЫ Итератор  это объект, выполняющий в контейнере роль указателя. С помощью итератора можно перемещаться внутри контейнера и получать доступ к отдельным элементам. В классе st r ing определены следующи е типы итераторов: -+ it er at or  итератор. При увеличении значения итератор перемещается к концу строки. Пример объявления переменной: std::baS1C strlng<char>: :lterator t; -+ со ns t t era t or  константный итератор. lЬменить значение, на которое ссылается итератор, нельзя. Пример объявления переменной : std: : baslc str lng<char>: : const lterator lt; -+ reve rs е lt е ra t or  обратный итератор При увеличении значения итератор перемещается к началу строки. Пример объявления переменной: std: : baslc s trlng<char>: : reverse lterator lt; -+ const reverse terator  константный о бр атн ы й итер атор. Из ме н ить Пример объявления переменной: значение, на которое ссылается итератор, нельзя. std: : baslc str lng<char>: : const reverse lterator lt; Присвоить значения переменным позволяют следующи е методы: -+ Ье gin (1  возвращает итератор, установленный на первый символ строки. Прототипы метода: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  65  1712.10 iterator begin(); const lterator begln () const; Выведем первый символ строки: std::string str(rrstring rr ); std::baS1C strlng<char>: :iterator it; it = str.begin(); std: : cout « * it « std:: endl; 11 s -+ сЬ eg in ()  возвращает константный итератор, установленный на первый символ строки. Прототип метода: со nst lt er а to r сЬе gln () с ons t; -+ rb eg in (1  возвращает обратный итератор, установленный на последний символ строки. Прототипы метода: rever s е lt е ra t or rbe gln ( ) со nst reve r se lt er а to r rbe gln () с ons t; Выведем последний символ строки: std::string str(rrstring rr ); std: : baS1C str lng<char>: : reverse iterator it; it = str.rbegin(); std: : cout « * it « std:: endl; 11 9 -+ crbegin (1 возвращает константный обратный итератор, установленный на последний символ строки. ПрОТОТ1lП метода: const reverse lterator crbegln () const; -+ end (1  возвращает итератор, установленный на позицшо после последнеrо символа СтрОЮI. Прототипы метода: iterator end () ; const iterator end () const; Выведем последний символ строки: std::strng str(rrstrngrr); std::baslC strlng<char>: :terator t; t = str.end(); std:: cout « * (itl «std: :end1; / / g Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  бб  1712.10 -+ се nd ()  возвращает константный итератор, установленный на позицию после последнеrо символа строки. Прототип метода: const iterator cend () const; -+ re nd (1  возвращает обратный итератор, установленный на позицию перед первым символом строки. Прототипы метода: reverse iterator rend(); со nst reve r se it er а to r rend () со ns t; Выведем первый символ строки: std::string str(rrstring rr ); std: : baS1C str lng<char>: : reverse iterator it; it = st r. re nd ( ) ; std:: cout « * (itl «std: :end1; / / s -+ cr end ()  возвращает константный позицию перед первым символом строки. о бр атн ы й итер атор, Прототип метода: установленный на со nst reve r se it er а to r cre nd () const; Над итераторами можно производить такие же операции, как и с указателями. Чтобы получить или изменить значение, на котор ое с сылается итератор, перед названием переменной указывается оператор * (* i t). Перемещение итератора осуществляется с помощью операторов ++ и . Кроме Toro, итераторы можно сравнивать с помощью операторов сравнения. В каче стве при мера изменим значение первоrо символа, а затем выведем все символы строки в прямо м И обратном порядке с помощью цикла fo r (листинr б. 5). .1IИСТIПП 6.5. Пер ебор СИI>mоJЮВ в с трОК е с ПОМОЩЬЮ пrер nTop ОВ #include <iostream> #include <string> int main (1 std::string str(rrString rr ); std::baslc strlng<char>::lterator itl, it2; std::baslc strlng<char>::reverse lterator it3, it4; it1 = str.begin(l; *itl = ISI; 11 Изменение значения Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  б7  1712.10 11 Перебор символов в прямом порядке for (it1=str .begin (1, it2=str. end (1; it1'=it2; ++it11 std::cout «*itl «std::endl; std::cout « rrrr «std::endl; 11 перебор символов в обратном порядке for (itЗ=str.rЬеgin(), it4=str.rend(); it3!=it4; ++it3) std::cout «*it3 «std::endl; std: : cin. get (1 ; return о; Расшпренные СПI\IВОЛЫ П строкп ПОМИМО обычных СИМВОЛОВ, имеющих тип char, язык С++ поддерживает расширенные символы, имеющие тип wc har t Тип wc har t занимает в па:мяти два байта Диапазон значений от О ДО 65 535. Строки, состоящие из расшир енных СИМВОЛОВ, также как и обычные Сстроки, завершаются нулевым символом. Для более уд обной работы с расширенными строками можно воспользоваться ша6л онным классом wstr ing. Для вывода расширенных символов и строк вместо объекта с ои t следует использовать объект wc ои t, а для ввода Д анных объект wcin. Предварительно необходимо настроить локаль. Пример вывода расширенноrо символа и строки: std: : setlocale (LC  ALL, rrRussian  Russia. 1251 rr) ; std::wcout «L1п l «std::endl; std: :wcout « LrrCTpoKa rr « std:: endl; ОБЪЯВЛflШf И шпш;иализация llаПlпqlflШоrо fИ!lШOJШ Пере менной, имеющей тип wchar t, можно присвоить числовое значение (код символа) или указ ать символ внутри апостро фов, перед которыми добавлена букв а L. Внутри апострофов можно указать специальные символы, например, \ n, \ t и др. Пример объявления и инициализации расширенноrо символа: wchar t ch1 = 1087, ch2 = L I П I ; std::wcout «ch1 «std::endl; 11 п std::wcout «ch2 «std::endl; 11 п Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  68  1712.10 Коды первых 128 символов совпадают с кодами символов в кодировке АSСП (табл. б.1). Коды русских букв приведены в табл. б.3. Обратите внимание на то, что КОДЫ букв 11 ё" И "Ё" выпадmoт из последовательности код ОБ. Табшш,а 6.3. КDды русских буке при использоеаii1iii расширенных сuмеолое б)'"в код А 1040 Б 1041 В 1042 r 1043 Д 1044 Е 1045 Ё 1025 Ж 1046 3 1047 И 1048 Й 1049 К 1050 Л 1051 М 1052 Н 1053 О 1054 П 1055 б)'"в код р 1056 С 1057 Т 1058 У 1059 Ф 1060 Х 1061 Ц 1062 Ч 1063 Ш 1064 Щ 1065 Ъ 1066 Ы 1067 Ь 1068 Э 1069 Ю 1070 Я 1071 б)'"в код а 1072 б 1073 в 1074 r 1075 Д 1076 е 1077 ё 1105 ж 1078 з 1079 и 1080 й 1081 к 1082 л 1083 м 1084 н 1085 о 1086 п 1087 б)'"в код р 1088 с 1089 т 1090 у 1091 Ф 1092 х 1093 Ц 1094 ч 1095 ш 1096 Щ 1097 ъ 1098 ы 1099 ь 1100 э 1101 ю 1102 я 1103 ФУНКЦIШ для ll;lботы f II;lПIШllfШIЫIIШ fll!lШOJШIIШ Функции для работы с расширенными символами являются аналоrами функций, предназначенных для работы с обычными символами. В названии таких функций добавляется буква "w", например, расширенная функция iswa1pha( 1 является Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  69  1712.10 аналоrом функции is a1p ha ( 1. Названия обычных функций и прототипы соответствующих им расширенных функций приведены в табл. БА Таблица 6.4. ФУЮЩ1iii для работы с расшupеЮiыми символами ООЫЧlC)Я фУНКЦИЯ П"ОТОТIШ РЖШII,,НlЮЙ ФункЦlШ isa1num() int iswalnum( wint  t С); i еа1р щ) int iswalpha( wint  t С); iscntrl() int iswcntrl( win t  t С); i s digit() int iswdigi t( wint  t С); i s graph() int iswgra ph( wint  t С); i slowerQ int iswlower(wintt С); i ерrin t() int iswprint( wint  t С); i ерunсЮ int iswpunct( wint  t С); i "рас е() int iswspac е( wint  t С); i еирр щ) int iswup р er( wint  t С); i sxdi git() int iswxdigi t( wint  t С); to 10wer() wint  t towlower( wint  t С); to ирр щ) wintt towupper(wintt С); Прежде чем использовать расширенные функции необходимо подключить зarоловочный файл cwctype Тип wlnt t определен следующим образом typedef unslgned short wlnt t; В качестве примера проверим реrистр символа и выведем соотве ствующе е соо бщение, а зате м преобразуем символ к верхнему реrистру и выведем ero в окно консоли (листинr б. б). .1IНСТIПП 6.6. ПрНI>reр р nOOTbl С pnc IlIIIJ' НlIЪThIН СНI>mОJmШ #include <iostream> #include <clocale> #include <cwctype> Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  70  1712.10 int main (1 std: : setlocale (LC  ALL, rrRussian  Russia. 1251 rr) ; wchar t ch = L I П I ; if (std:: isw10wer (chll std: :wcout « LrrСтрочная rr « std:: endl; e1se { std: :wcout « LrrПрописная rr « std:: endl; } 11 Результат: Строчная ch = std:: towupper (ch 1 ; std: : wcout « ch « std:: endl; 11 п std: : cin. get (1 ; return о; Для проверки типа содержимоrо символа вместо функций, перечисленных в табл. БА, можно воспользовать ся функцией iswct ур е ( 1 . Прототип функции: #include <cwctype> lnt lswctype(Wlnt t С, wctype t Туре); В первом параметре указ ывается расширенный символ, а во втором параметре результат выполнения функц ии wctyp е ( 1 . Прототип функции: #include <cwctype> wctype t wctype(const char *Attr); Функция wc type (1 принимает в качестве пара метра CCтpOKY, сод ержащую название проверки: "alnu.m 11, Ilalpha ll , "cntrlll, "digit " , Ilgraph", "lower " , "print ll , "pu.nct ll , Ilspace ll , 11 ир р er 11 или "х digi t 11 . Для изменения реrистра символа можно воспользоваться функцией towct r ans ( ) . Прототип функции: #include <cwctype> wint t towctrans(wint t С, wctrans t Туре); В первом параметре указ ывается расширенный символ, а во втором параметре результат выполнения функц ии wctr ans (1 . Прототип функции: #include <cwctype> wctrans t wctrans(const char *Attr); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  71  1712.10 Функция wc tr ans (1 принимает в каче стве параметра Ccтpoкy, содержащую название трансф ормации: "tolower" (преобраз ование в нижний реrистр) ипи "toupper" (преобразование в верхний реrистр). В качестве примера переделаем предыдущий пример (листинr б. б) и используе м функции iswct ур е (1 и towct rans (1 вместо функций isw10wer (1 и towupper (1 (листинr б.7). .1IИСТIПП 6.7. ПрИI>reр ИСIЮЛЪЗОВnНИЯ ф)'икций i""'ct)l'eO и IO"'СU'Ш,"О #include <iostream> #include <clocale> #include <cwctype> int main (1 std: : setlocale (LC  ALL, rrRussian  Russia. 1251 rr) ; wchar t ch = L I П I ; if (std::iswctype(ch, std::wctype(rrlowerrr))) std: :wcout « LrrСтрочная rr « std:: endl; e1se { std: :wcout « LrrПрописная rr « std:: endl; } 11 Результат: Строчная ch = std::towctrans(ch, std::wctrans(rrtoupper rr )); std::wcout «ch« std::endl; 11 П std: : cin. get (1 ; return о; ПllfобllазоваlШf llаПlпqlflШЫХ сmmолов в оБы'lыыf И иаоБОllОТ Для преобразования расширенных символов (тип wchar t) в обычные (тип с har) и наоборот предназначены две функции: -+ bt owc (1  преобразует обычный символ в расширенный. В случ ае ошибки функц ия возвращает зн ачение макроопределения WE OF (65 535). Прототип функции: #include <cwchar> wint t Ь towc (int Ch); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  72  1712.10 -+ wc tob (1  преобразует расширенный символ в обычный. В случ ае ошибки функц ия возвращает значение  1 и устанавливает значение макроопределения er rno соответствующим значению Е IL SE Q (равно 42). Прототип функции: #nclude <cwchar> int wctob(wint t WCh); Прежде чем производить преобразования необходимо настроить локаль. Пример п реобразования приведен в листинrе б.8. I .1IИСТIПП 6.8. Преобрюовnние СИI>mолов # include <iostream > #include <clocale> #include <cwchar> int main (1 std: : setlocale (LC  ALL, rrRussian  Russia. 1251 rr) ; wchar t weh = о; char ch = I П I ; 11 Преобразование обычноrо символа в расширенный wch = std:: btowc (chl ; if (wch == WEOF 1 std: : cout « rrОшибка rr « std:: endl; e1se { std::wcout «weh« std::endl; 11 п { 11 Преобразование расширенноrо символа в обычный ch = std::wctob(wchl; if (ch == 11 std: : cout « rrОшибка rr « std:: endl; e1se { std::cout «ch« std::endl; // п std: : cin. get (1 ; return о; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  73  1712.10 ФУНКЦIШ для ll;lботы f II;lПIШllfШIЫIIШ fЧIОЮ1IIШ Расширенные строки, являются массивами, содержaIЦИ ми символы типа wchar t. Последним символом расшир енной строки является нулевой символ. Объявляется расширенная строка также как и массив элементов типа wchar t wchart str[7]; При инициализации расширенной строки можно перечислить расширенные символы внутри фиrурных скобок или указать строку внутри двойных кавычек, перед которыми добавлена буква L: wchar t strl[7] = {L'S ' , L't ' , L'r ' , L1l 1 , L'n ' , L'g', L'\O'}; wchar t str2 [] = L rrStr lngrr; Функции для работы с расширенными строками являются аналоrами функций, предназначенных для работы с обычными строками. В названии таких функций фрarмент 11 str ll заменяется комбинацией символов 11 wcs ll , например, расширенная функция wc slen (1 является аналоrом функции s tr 1en ( 1. Прежде чем использовать расширенные функции необходимо подключить зarол овочный файл cwchar. Названия обычных функций и прототипы соответствующих им расширенных функций приведены в табл. б. s. Таблица 6.5. ФУiilЩUИ для работы с расшupеЮiЫМU строками ООЫЧlC)Я ф)'нкция П"ОТОТIШ I'жrшq)НlЮй ф)'нкЦlШ Ос>ювНЫ<' ф)'нкЦlШ strcat() wchart *wcscat(wchart *Dest, const wchart *Source); strcat  е() erшо  t wcs сal  е( wchar  t *D st, rsize  t Siz eIn W ords, соnе! wchart *Src); strcpy() wchart *wcscpy(wchart *Dest, const wchart *Source); strcpys() erшо  t wcs сру  е( wchar  t *D st, rsize  t Siz eIn W ords, const wchart *Src); strIen() sizet wcsIen(const wchart *Str); еtшсаЮ wchar  t *wc sncat( wchar  t *D est, с onst wchar  t * S ourc е, sizet Count); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  74  1712.10 еtшса!  е() erшо  t wcsncat  е( wchar  t *D st, rsiz е  t SizeIn W ords, const wchart *Src, rsizet МaxCount); еtшсру() wchar  t *wc еnсру( wchar  t *D est, с onst wchar  t * S ourc е, sizet Count); еtшсруе() erшо  t wcsncpy  е( wchar  t *D st, rsiz е  t SizeIn W ords, с оnе! wchar  t * Src, rsize  t мах С ount); strtok() wchart *wcstok(wchart *Str, const wchart *De1im); strtok e() wchart *wcstoks(wchart *Str, соnе! wchart *De1im, wchart **Context); по ИfК И ЗI'rI?'К"I В (ТРОКI?' strchr() wchart *wcschr(wchart *Str, wchart Ch); const wchart *wcschr(const wchart *Str, wchart Ch); strc spn() size  t wcs серn( соnе! wchar  t * Str, с onst wchar  t * С ontro 1); strp brk() wchart *wcspbrk(wchart *Str, const wchart *ControI); с onst wchar  t *wc ер brk( с оnе! wchar  t * Str, const wchart *ControI); strrchr() wchart *wcsrchr(wchart *Str, wchart Ch); const wchart *wcsrchr(const wchart *Str, wchart Ch); strspn() size  t wcsspr( с оnе! wchar  t * Str, с оnе! wchar  t * С ontroI) ; strstr() wchart *wcsstr(wchart *Str, соnе! wchart *SubStr); const wchart *wcsstr(const wchart *Str, соnе! wchart *SubStr); с), ВЮ"lII'" СТI'О К strcmp() int wcscmp(const wchart *StrI, const wchart *Str2); strcoII() int wcscoII(const wchart *StrI, const wchart *Str2); еtшстр() int wcsncmp(const wchart *StrI, соnе! wchart *Str2, sizet МaxCount); strxfnn() size  t wcsxfnr( wchar  t *D st, с оnе! wchar  t * Src, siz е  t МахС о unt); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  75  1712.10 Рбот (" 1'r&"l("("ИВI'rШ Р("ШIq)1?' lПIЬ1\'" (Иl'rШОЛОВ тетсщ) wchart *wmemchr(wchart *8, wchart С, еше! N); тетстр() int wшетстр(соnе! wchart *81, const wchart *82, еше! N); тетсру() wchart *wmemcpy(wchart *81, соnе! wchart *82, еше! N); тетсру  е() erшо! wmemcpys(wchart *8 1, rsizet Nl, const wchart *82, rsizet N); memmove() wchar  t *wmemmove( wchar  t * 8 1, с оnе! wchar  t * 8 2, еш е  t N); memmoves() erшо! wmemmoves(wchart *81, rsizet Nl, соnе! wchart *82, rsizet N); тете et() wchart *wmemset(wchart *8, wchart С, еше! N); П" обl' зов НИ<' СТI'О кв в число strtod() double wcstod(const wchart *8tr, wchart **EndPtr); strtol() long wcstol(const wchart *8tr, wchart **EndPtr, int Radix); strtoul() unsign ed long wc stoul( с оnе! wchar  t * 8tr, wchar  t * * EndPtr, int Radix); Основные операции с расширенными строками показаны в листинrе 6.9. -Тшст IПП 6.9. Осно B:ньre оперtlЦIШ с pn cIlIIIp еlПlЫl'rlИ стр ОК;[II'rШ #define CRT SECURE срр OVERLOAD STANDARD NAМES 1 #include <iostream> #include <clocale> #include <cwchar> int main (1 std: : setlocale (LC ALL, rrRussian  Russia. 1251 rr) ; wchar t strl [] = LrrCTpOKa rr , str2 [100] = {О}; std::wcout «std::wcslen(strl) «std::endl; 11 Длина std: : wcscpy (str 2, L rrодинrr) ; 11 КоПИРОВ9.ние std: : wcscat (str2, L rr ДВ9. rr ); 11 Конкатенация std: : wcout « str2 « std:: endl; 11 ВыВОД Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  76  1712.10 std: :wcin. get () ; return о; КТlaСС "'Sh'illg Класс wstr ing предоставляет уд обный интерфейс для работы со строками, состоящими из расширенных СИМВОЛОВ. Название клас са wst r ing является ЛИШЬ псевдонимом ша6лонноrо класса bas lC s tr lng typedef baS1C strlng<wchar t, char traits<wchar t>, allocator<wchar t> > liJString; Для использования класса wst r ing необходимо ПОДКЛЮЧИТЬ файл string: # include <string> Классы str ing и wst r ing являются псевдонимами ша6лонноrо кл асса Ь aS1C s tr lng Поэтому С экземплярами класса wstr ing можно ПрОН:ЗБОДИТЬ такие же операции, как и с эк:зеплярами класса s tr ing, а также использовать те же самые методы. Различие заключается в типах данных. Тип char ВО всех прототипах методов заменяется типом wc har t. Так как дрyrих различий практически нет мы не буд ем повторно рассматривать эти операции и методы. За подробной информацией обращайтесь к описанию класс а s tr ing. Основные операции с экземплярами класс а wst r ing показ аны в листинrе б.l о. -ТШСТIПП 6.10. Основные ОIrepnЦИИ С '}кзеIlrIIlЛЯJlШ"IИ K..тrnCCn ,"'SU'П-.g #include <iostream> #include <clocale> #include <string> int main (1 std: : setlocale (LC ALL, rrRussian  Russia. 1251 rr) ; std::wstring str1(L rr String1 rr ), str2(L rr String2 rr ), str3; str3 = str1 + str2; 11 Конкатенация std: : wcout « str3 « std:: endl; 11 Str ing1Str ing2 str 1[0] = L I S 1; 11 Доступ по индексу std: : wcout « str 1 « std:: endl; 11 str ing1 std::wcout «str1.size() «std::endl; 11 Длина str2 = str1.substr(2, 3); 11 Получение фраrмента Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  77  1712.10 std: : wcout « str2 « std:: endl; strl. replace (О, 4, L rr **** rr) ; std::wcout «strl «std::endl; std: :wcin. get () ; return о; / / rin / / Замена 11 ****ngl Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  2  1712.10 Основные функции для работы с датой и временем в языке С++ объявлены в зarоловочном файле ctime (файл time. h в языке С). В этом файле определены также следующи е типы данных: -+ Sl "е t  используется в функции str ft ше (1 Размер зависит от настроек По умолчаншо 4 байта. Определение типа: typedef unsigned int size t; typedef unsigned int64 size t; -+ c10c k  t  возвращается функцией с 10 ck (1 Определение типа: typedef long clockt; -+ tlme t  используется для представления времени в виде целочисленноrо значения Размер типа зависит от настроек По умолчанию занимает 8 байт. Определение типа: typedef time32 t time t; typedef time64 t time t; Определение типов ti,"e 32 t и typedef long time32 t; typedef int64 ti,"e64 t; t ime 6 4 t выrл яд ит так: Некоторые функции в кач естве значения возвращают указ атель на структуру t'". Определение структуры t'" выrлядит следующим образом: struct t'" { int t'" sec; // Секунды (число от О до 59, изр ед ка до 611 int t'" min; // Минуты (число от О до 591 int t'" hour; // Час (число от О до 231 int tmmday; // День месяца (число от 1 до 311 int t'" nюn; // Мес яц (число от О (январы до 11 (декабрь 11 int t'" year; // roд, начиная с 1900 roдa int tmwday; // День недели (число от О до 6 (О  Э'ro воскресенье, // 1  это по нед е ль НИК, ..., 6  это субботаll int t'" yday; // День в roдy (число от О до 3651 int t'" is dst ; // Если больше О, значит действует летнее время // Если О, значит летнее время не установлено // Если ме ньше О, то инфJ рмации нет {; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  3  1712.10 Полученпе тек')'щеlI даты п вреl\Iенп Получить текущую дату и время позволяют следующие функции: -+ time (1  возвращает количество секунд, прошедших с начала эпохи (с 1 января 1970 r.). Прототип функции: #incl ude <ct ше> time t tirne(time t *Tirne); Функцию можно вызвать двумя способами, передавая в качестве параметра нулевой указатель или адрес переменной, в KOTOpJ'lO 6уд ет записано Бо:звращае мое значение. Пример: std::time t tl = std::time (О); 11 Передаем нулевой указатель std: : cout « t 1 « std:: end1; / / 1285559288 std: : time t t2; std:: time (&t21; 11 Передаем адрес переменной std::cout « t2 « std: :endl; / / 1285559288 в VC++ вместо функции time (1 можно использовать функции time 32 (1 и time 64 (1 . Число перед открывающей круrлой ско бкой означает количество бит. Прототипы функций: time32 t time32 ( time32 t *Timel; time 64 t time64 ( time 64 t *Timel; Пример использования: time32 t tl; time32 (&t11; std::cout « tl « std: :endl; / / 1285559288 time 64 t t2; time64 (&t21; std::cout « t2 « std: :endl; / / 1285559288 -+ gmtime (1  возвращает указ атель на структуру tm с универсальным временем (ИТС) или нулевой указ атель в случ ае ошибки. В кач естве параметра указ ывается адрес переменной, которая содержит количество секунд, прошедших с начала эпохи. Что б ы п олуч ить текущую Д ату в к ач е ств е пар аметр а сл едует пер ед ать резуль тат выполнения функции t ше (1 . Прототип функции: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  4  1712.10 #incl ude <ct ше> struct tm *grntirne(const tirne t *Time); Пример использования функции: std::tm *ptm = о; std: : time t t = std:: time (О 1 ; ptm = std::gmtime(&tl; if ('ptml std::cout « rrError rr « std: :endl; std: :exit(ll; std: : cout « ptm >tm sec « std: : endl; std: : cout « ptm>tmmin « std: : endl; std: : cout « ptm >tm hour « std: : endl; std: : cout « ptm>tmmday « std: : endl; std: : cout « р tm >tm  топ « std: : endl; std: : cout « ptm >tm year « std: : endl; std: : cout « ptm>tmwday « std: : endl; std: : cout « ptm >tm yday « std: : endl; std: : cout « ptm >tm lsdst « std: : endl; // 56 // 54 // 23 // 27 // 8 (сентябрь 1 // 110 (2010 r.1 // 1 (понедельник) // 269 // О в VC++ вместо функции gmt ше (1 можно использ овать функции gmt J.тe 32 (1 и gmt J.тe 64 (1 Число перед открывающей крyrлой скобкой означает количество бит Прототипы функций: struct tm * grntlme32(const struct tm * grntlme64(const time32 t * Тше) ; time 64 t * Тше) ; в VC++ при использовании функции gmt ше (1 Са также при использовании функц ий gmt J.тe 32 (1 и gmtlme 64 (1 ) выводится предупреждающее сообще ние ("warning С499б"), поэтому вместо функции gmtime (1 следует использовать функц шо gmtlme s (1 С gmtlme 32 s (1 и gmtlme 64 s (1 вместо gmt J.тe 32 (1 и gmt J.тe 64 ( 1 соответственно) Прототипы функций: #incl ude <ct ше> errno t grntlme s(struct tm *Тт, const tirne t *Time); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  5  1712.10 errno t gmtlrne32 s(struct tm *Тт, const errno t gmtlrne64 s(struct tm *Тт, const time32 t *Тше); time 64 t *Тше); Если ошибок нет, то функции возвращают значение О. При наличии ошибки возвращается значение макроса Е INVAL (значение равно 22) и переменная errno устан авливается равной Е I NVAL. Пример использования функции gmt J.тe s (1 std: : tm ptm; std: : time t t = std:: time (О 1 ; errno t err = grntlrne s(&ptm, &t); if (енl std::cout « rrError rr « std: :endl; std: :exit(ll; std: : cout « ptm. tm sec « std: : endl; // std: : cout « ptm. tmmin « std: : endl; // std: : cout « ptm. tm hour « std: : endl; // std: : cout « ptm. tmmday « std: : endl; // std: : cout « ptm. tmmon « std: : endl; // std: : cout « ptm. tm year « std: : endl; // std: : cout « ptm. tmwday « std: : endl; // std: : cout « ptm. tm yday « std: : endl; // std: : cout « ptm. tm lsdst « std: : endl; // 56 54 23 27 8 (сентябрь 1 110 (2010 r.1 1 (понедельник) 269 О -+ 10 ca1t ше (1  возвращает указатель на структуру tm с локальным временем или нулевой указатель в случае ошибки. В качестве параметра указывается адрес переменной, которая содержит количество секунд, прошедших с начала эпохи. Что б ы п олуч ить текущую Д ату в к ач е ств е пар аметр а сл едует пер ед ать резуль тат выполнения функции t ше (1 . Прототип функции: #incl ude <ct ше> struct tm *localtirne(const time t *Time); Пример использования функции: std::tm *ptm = о; std: : time t t = std:: time (О 1 ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  б  1712.10 ptm = std::localtime(&t); if ('ptml std::cout « rrError rr « std: :endl; std: :exit(ll; std: : cout « ptm >tm sec « std: : endl; // std: : cout « ptm>tmmin « std: : endl; // std: : cout « ptm >tm hour « std: : endl; // std: : cout « ptm>tmmday « std: : endl; // std: : cout « р tm >tm  топ « std: : endl; // std: : cout « ptm >tm year « std: : endl; // std: : cout « ptm>tmwday « std: : endl; // std: : cout « ptm >tm yday « std: : endl; // std: : cout « ptm >tm lsdst « std: : endl; // 56 54 4 28 8 (сентябры 110 (2010 r.1 2 (вторникl 270 1 (летнее время) В VC++ вместо функции 10ca1t ime (1 можно использовать функции 10c a1 time 3 2 (1 и 10ca1 time 64 (1 . Число перед открывающей крyrлой скобко й означает количество бит. Прототипы функций: struct tm * localtime32(const struct tm * localtime64(const time32 t *Тше); time 64 t *Тше); в VC++ при использовании функции 10ca1time (1 (а также при использовании функц ий 10c a1 time 32 ( 1 и 10ca1 tlme 64 ( 1) выводится предупреждающее сообщение ("warning С499б "), поэтому вместо функции 10c a1 time (1 следует использовать функцию 10c a1 tlme s (1 ( 10 ca1t lme 3 2 s (1 и 10 ca1t ше 64 s ( 1 вместо 10 ca1t ime 32 (1 и 10c a1 t ше 6 4 ( 1 соответственно). Прототипы функций: #incl ude <ct ше> errno t localtirne s(struct tm *Тт, const time t *Time); errno t localtime32 s(struct tm *Тт, const errno t localtime64 s(struct tm *Тт, const time32 t *Тше); time 64 t *Тше); Если ошибок нет, то функции возвращают значение о. При наличии ошибки возвращается значение макроса Е INVAL (значение равно 22) и переменная errno устан авливается равной Е I NVAL. Пример использования функции 10c a1 tlme s ( 1 std: : tm ptm; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  7  1712.10 std: : time t t = std:: time (О 1 ; errno t err = localtlrne s(&ptm, &t); if (енl std::cout « rrError rr « std: :endl; std: :exit(ll; std: : cout « ptm. tmmday « std: : endl; // std: : cout « ptm. tmmon « std: : endl; // std: : cout « ptm. tm year « std: : endl; // 28 8 (сентябрь 1 110 (2010 r.1 -+ mk time (1  возвращает количество секунд, прошедших с начала эпохи. В качестве параметра передается указатель на структуру tm. В случае ошибки возвращается значение  1. Прототип функции: #incl ude <ct ше> time t mktime(struct tm *Тrn); Пример использования функции: std: : tm ptm; st d: : t ше t t 1 = std:: time (О 1, t2 = о; errno t err = localtlrne s(&ptm, &tl); if (енl std::cout « rrError rr « std: :endl; std: :exit(ll; t2 = std: :mktime (&ptml ; std: : cout « t1 « std: : endl; // 1285636288 std: : cout « t2 « std: : endl; // 1285636288 в VC++ вместо функции mkt ше (1 можно использ овать функции mkt ше 32 (1 и mkt J.тe 64 (1 Число перед открывающей крyrлой скобкой означает количество бит Прототипы функций: time32 t  mktime32 (struct tm *Тm); time 64 t  mktime64 (struct tm *Тm); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  8  1712.10 -+ difftime (1  возвращает разность между двумя датами (Тше 1 Тше2). В случае ошибки возвращается значение О и переменная е rr по устанавливается равной Е INVAL. Прототип функции: #include <ctime> do uble diff t ше (time t Тше 1, time t Тше2); Пример: st d: : t ше t t 1 = std:: time (О 1, t2 = 12 зз 3 68623 ; douk1e resu1t = std:: difftime (t1, t21; std: : cout « result « std:: endl; В VC++ вместо функции difftime (1 можно использовать функции dif ft ше 32 (1 и dif ft ше 64 (1. Число перед открывающей крyrл ой скобкой означает количество бит. Прототипы функций: douk1e difftime32 ( time32 t Time 1, time32 t Тше21; do uk1e difftime 64 ( time 64 t Time 1, time64 t Тше21; Выведем текущую дату и время таки м образом, чтобы день недели и месяц были написаны порусски (листинr 7.1). I .1IИСТIПП 7.1. Вывод теК)'IЦeй Д<lTЫ И ВI"'relШ #include <iostream> #include <clocale> # inc 1 ude <с time > #inc1ude <iomanip> // Для setfi11(1 и setw(1 int main (1 std: : setlocale (LC  ALL, rrRussian  Russia. 1251 rr) ; std: : tm ptm; std::time t t = std::time(OI; char d [] [25] {rrвоскресеньеrr, rrпонедельникrr, rrВ'КIрник rr , rrсредаrr, rrчетверrrr, rrпятницаrr, rrсуббота rr }; char т[] [25] {rrянваряrr, rrфевраля rr , rrиартаrr, rrапреляrr, rrмаяrr, rr ИЮНЯ rr, rr ИЮЛЯ rr, rr aвryc та rr, rr С ент яб р я rr, rr О кт яб Р я rr , rrНQябряrr, rrдекабряrr}; errno t err = localtJ..I(Je s (& ptm, & t); 11 Получаем текущее время Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  9  1712.10 if (еп 1 std::cout « rrError rr «std::endl; std: : exit (11 ; std::cout « rrСеrодня: rr «std::endl « d[ptm.tm wday] « rr rr « ptm.tmmday « rr rr «m[рtm.tmnюn] « rr rr « (ptт.tmyear + 1900); std::cout «std::setfll('O') « rr rr «std::setw(2) « ptm.tmhour « rr: rr « std: :setw(2) «ptm.tmmin « rr: rr « std: :setw(2) «ptm.tmsec « std: :endl «std::setw(21 «ptm.tmmday «rr.rr« std::setw(2)« (рtт.tmnюn + 1) «rr rr « (ptm.tmyear + 19001 «std::end1; std: : cin. get (1 ; return о; Резуль тат в ып ол н ен ия: Сеrодня: вторник 28 сентября 2010 16:01:05 28.09.2010 В этом примере мы использовали манипуляторы se tf i11 (1 и se tw (1 , объявленные в зarоловочном файле iomanip. Манипулятор se tf i11 (1 предназначен для указания символа'Заполнителя, а манипулятор setw ()  для указ ания ширины поля. Если эти манипуляторы не использовать, то время "lб:О 1:05" будет выведено так: "1 б: 1:5". ФОРI\НlТпрованпе даты п временп Получить форматированный вывод даты и времени позволяют следующи е функции: -+ as ct ше (1  возвращает указатель на CCтpOKY специальноrо формата или нулевой указ атель в случае ошибки. В конец строки вставляется символ перевода строки (\n) И нулевой символ (\ о). Прототип функции: #incl ude <ct ше> char *asctime(const struct tm *Тт); Пример использования функции: std: : tm ptm; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  10  1712.10 char *р = о; std: : time t t = std:: time (О 1 ; errno t err = localtlrne s(&ptm, &t); if (енl std::cout « rrError rr « std: :endl; std: :exit(ll; р = std::asctime(&ptm); if ('рl std::cout « rrError rr « std: :endl; std: :exit(ll; std::cout « р « std::endl; // Тие Sep 28 17:08:56 2010\n\0 В VC++ при использовании функции asct ше (1 выводится предупреждающее сообщение ("waming С499б "), поэтому вместо функции asc time (1 следует использовать функцию asc tlme s (1 Прототип функции: #incl ude <ct ше> errno t asctirne s(char *Buf, Slze t SlzelnBytes, const struct tm *Тm); в первом параметре передается указатель на строку, во втором параметре  максимальный размер строки, а в третьем параметре  указ атель на структуру tm. Если ошибок нет, то функция возвращают значение о. При наличии ошибки возвращается значение макроса EINVAL (значение равно 22). Пример использования функции: std: : tm ptm; const short SIZE = 80; char str [SIZE] = {О{; std: : time t t = std:: time (О 1 ; errno t err = localtlrne s(&ptm, &t); if (енl std::cout « rrError rr « std: :endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 11  1712.10 std: :exit(ll; err = asctme s(str, SIZE, &ptm); if (енl std::cout « rrError rr « std: :endl; std: :exit(ll; std::cout « str « std::endl; // Тие Sep 28 17:20:32 2010\n\0 -+ ct ше (1  функция аналоrична asct ше (1 , но в кач естве параметра принимает количество секунд, прошедших с начала эпохи. Прототип функции: #incl ude <ct ше> char *ctime(const tirne t *Tirne); Пример использования функции: char *р = о; std: : time t t = std:: time (О 1 ; р = std:: ctime (&tl; if ('рl std::cout « rrError rr « std: :endl; std: :exit(ll; std::cout « р « std::endl; // Тие Sep 28 17:34:13 2010\n\0 В VC++ при использовании функции ctime (1 выводится сообщение ("warning С499б"), поэтому вместо функции использовать функцию с tlme s (1 . Прототип функции: #include <ctime> errno t ctirne s(char *Buffer, size t SizelnBytes, const time t *Time); предупреждающее с time ( 1 следует Если ошибок нет, то функция возвращают значение о. При наличии ошибки возвращается значение макроса Е I NV М. Пример использования функции: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  12  1712.10 const short SIZE = 80; char str [SIZE] = {О{; std: : time t t = std:: time (О 1 errno t err ctime s(str, SIZE, &t); if (енl std::cout « rrError rr « std: :endl; std: :exit(ll; std::cout « str « std::endl; // Тие Sep 28 17:40:13 2010\n\0 -+ st rf time () записывает СтрОКОБое представление даты в СОО1Бетствии со строкой формата в Ccтpoкy в uf. Пр ототип функц ии: #incl ude <ct ше> size t strftirne(char *Buf, Slze t SlzelnBytes, const char *Format, const struct tm *Тт) ; в первом параметре передается указатель на символьный массив, в который буд ет записан результат выполнения функции. В параметре S iz е I nB yt е s задается максимальный размер символьноrо массива. В параметре Fo rmat указывается строка специальноrо формата, а в последнем параметре передается указ атель на структуру tm с представлением даты. Функция возвращает количество записанных СИМВОЛОВ. В случае ошибки возвращается значение О и переменная err по устан авливается равной Е 1 NVAL; -+ wc sf time (1  функция аналоrична функции строковое представление даты не в CCтpOKY, Прототип функции: #include <ctime> s trf t ше ( ), но записывает а в расширенную строку Ви f. size t wcsftirne(wchar t *Buf, size t SizelnWords, const wchar t *Format, const struct tm *Тт); в параметре Fo rmat в функциях st rf time (1 и wc sft ime (1 помимо обычных символов Moryт быть указаны слеДJ'lOщие комбинации специальных символов: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  13  1712.10 -+ %у  rод из двух цифр (от "00" до "99"); -+ %у  rод из четырех цифр (например, "2 010 ,,); -+ %т  номер месяца с предваряющим нул ем (от rr О 1 rr до rr 12 rr); -+ %Ь  аббревиатура месяца в зависимости от настроек локали (например, rr сен rr В локали "RussianRussia.12S111 или rrSeprr В локали 11 С" для сентября); -+ %В  название месяца в зависимости от настроек локали (например, rrСентябрь rr ИЛИ rrS ер te:mb er rr); -+ %d  номер дня в месяце с предваряющим нулем (от "О 1" до "31 ,,); -+ % j  день с начала rода (от rr 001 rr до rrз 66 rr); -+ % u  номер недели в rоду (от rro О rr до rr 5 3 rr). Неделя начинается с воскресенья; -+ %W  номер недели в rоду (от rroorr до r'53 rr). Неделя начинается с понедельника; -+ %w  номер ДНЯ недели CrO rr  для воскрес енья, rr 6 rr  ДЛЯ су660ТЫ); -+ % а  аббревиатура дня недели в зависимости от настроек локали (например, "Ср" или rrWed rr для среды); -+ %А  название ДНЯ недели в зависимости от настроек локали (например, rrсредаrr или rrWedne sday rr); -+ % н  часы в 24часовом формате (от "О О" до "23 ,,); -+ % I  часы в 12часовом формате (от "О 1" до "12 ,,); -+ %М  минуты (от rroo rr до rr 59 rr); -+ % S  секунды (от rro О rr до rr 59 rr, изредка до rr 61 rr); -+ % Р  Эlffiивалент значениям.дМ и РМ в текущей локали; -+ %с  представление даты и времени в текущей локали (налример, "29. 09 .2 О 1 О 14:37: 02" или "09/29/10 14 :38: 05"); -+ %# с  расширенное представление даты и времени в текущей локали rr29 Сентябрь 2010 I". 14: 4 6: 08 rr или rrwednesday, September 14 :46: 36"); (н апр имер, 29, 2010 -+ % х  представление даты в текущей локали (например, "29. 09. 2 О 1 О" или "09/29/10"); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  14  1712.10 -+ %# х  расшир енное представление даты в текущей локали (например, "29 Се нтяб рь 2 О 1 О I". rr или rrWedne sday, Sep te:mb er 2 g, 2 О 1 О rr) -+ % Х  представление времени в текуще й локали (например, "14: 41: 2 4"); -+ %:  название часовоrо пояса или пустая строка (например, rrMo СКОБе:ко е вр емя (летоl ,,); -+ %%  символ rr%rr. Если после символа % указан символ # в комбинациях % #d, %#н, %# I, % #j, %#т, %#М, %# S, %# u, % #w, %#W, %#у и %#У, то предваряющие нули выводиться не будут. В кач естве примера использования функции str ft ше ( 1 выведем текущую дату и время (листинr 7.2). I .1IИСТIПП 7.2. Фор mтировn ине Д<lTЫ И вреrelШ #include <iostream> #include <clocale> # inc 1 ude <с time > int main (1 std: : setlocale (LC  ALL, rrRussian  Russia. 1251 rr) ; std: : tm ptm; const short S IZE = 100; char str[SIZE] = {О{; std::timet t = std::time(OI; lnt err = localtlme s(&ptm, &t); if (енl std::cout « rrError rr «std::endl; std: : exit (11 ; err = std:: strftime (str, S IZE, "Сеrодня: \n%A %d %Ь %у %н: %М: %S\n%d. %т. %У", &ptml; if ('епl std::cout « rrError rr «std::endl; std: : exit (11 ; std::cout «str «std::endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  15  1712.10 std: : cin. get (1 ; return о; Резуль тат в ып ол н ен ия: Сеrодня: cpa 29 сен 2010 14:57:11 29.09.2010 tt 'Засыпанпе tt проrр Ш\II\IЫ WinАРIфункция Sleep (1 позволяет прерывать выполнение проrpаммы на указанное время. По истечении срока проrpамма продолжит работу. Прототип функции: #include <windows.h> void Sleep(DWORD dwМi11isecondsl; В параметре d1AlМillise с onds указыв ается количество миллис екунд, на которое прерывается выполнение проrp аммы. Тип данных DWORD определен так typedef unsigned long DWORD; ДЛЯ при мера выведем числа от 1 до 10 (листинr 7.3). Между выводом чисел "заснем" на о дну секунду. I .1IИСТIПП 7.3. "Зnс ъпmНIre" проrрn "'IЫ # include <iostream > #include <windows.h> int main (1 for (int i=l; i-:::=10; ++i) std: :cout « rr\r... rr« i « rr%rr; Sleep (1000); 11 rr Засыпаем,r на 1 секунду std::cout « rr\rEnd std: : cin. get (1 ; return о; rr « std:: endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  16  1712.10 ПЗI\Iеренпе временп выполненпя фраrментов кода в некоторых случаях необходимо измерить время выполнения фрarментов кода, например, с целью оптимизации проrpаммы. Измерить вре:мя выполнения позволяет функция с 10c k (1 . Прототип функции: # inc 1 ude <с time > clockt clock(void); Функция возвращает приблизительное время выполнения проrp аммы до вызова функции. Если время получить не получилось, функция возвращает значение  1. Чтобы из мер ить вр е мя в ып ол не н ия фр arMe нта сл еду ет вызв ать Ф ун кц ию пер ед Ф р ar ме нто м кода и сохранить результат. Затем вызвать функцию после фрarмента и вычислить разность между двумя значениями. Чтобы получить значение в секундах необходимо разделить результат на значение макрос а CLOC KS РЕ R S ЕС. Определение макроса выrлядит следующим образом: #define CLOCKS PER SEC 1000 Для примера имитируем фрarмент кода с помощью WinAPIфункции Sleep (1 и произведем измерение времени выполнения (листинr 7.4). I .1IИСТIПП 7.4. Изrepение вреrelШ въпюлнення #include <iostream> # inc 1 ude <с time > #include <windows.h> int main (1 std::clock t tl, t2, t3; t1 = std::c1ock(l; / / М=тка 1 std::cout « rrtl = rr «tl «std::endl; Sleep (20001 ; t2 = std::c1ock(l; 11 Имитация фраrмента кода / / М=тка 2 std: : cout « rrt2 t3 = t 2  t 1; std: : cout « rrt3 std: : cout « (t3 std: : cin. get (1 ; = rr «t2 «std::endl; 11 Разница между метками = rr « t3 « std:: endl; I CLOCKS PERSEC) « rr sec. rr « std: :endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  17  1712.10 return о; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  2  1712.10 Функция  это фр асме нт кода, который можно неоднократно вызвать из любоrо места проrpаммы. В предыдущих rлавах мы уже не один раз использовали встроенные функции, входящие в состав стандартной библиотеки. Например, с помощью функции st r len () получали количество символов в CCтpOKe. В этой rл аве мы рассмотрим создание пользовательских функций, которые позволят уменьшить избыточность проrpаммноrо кода и повысить ero структурированность. Созданпе функцпп п ее вызов Описание функции состоит из двух частей: объявления и определения. Объявление функции (называемое также прототипом функции) содержит информацию о типе. Используя эту информацию компилятор может найти несоответствие типа и количества параметров. Формат прототипа функции: <Тип результата> <Название функции>([<Тип> [<Название параметраl>] [, ..., <Тип> [<Название параметраN>]]]); Параметр <Тип резуль тата> задает тип значения, которое возвращает функция с помощью оператора r etur n. Если функция не возвращает никакоrо значения, то вместо типа указывается ключевое слово void. Название функции ДОЛЖНО быть допустимым идентификатор ом, к которо му предъявля::ются такие же требования как и к названиям переменных. После названия функции, внутри круrлых скобок, указывается тип и название параметров через запятую. Названия параметров в прототипе функции можно не зад авать вообще, так как компилятор интересует только тип данных и количеС1БО параметров. Если функция не принимает параметров, то указыв аются только круrлые ско бки или внутри круr-лых скобок задается ключевое слово void (в языке С ключевое слово void является обязательным). После объявления функции должна стоять точка с запятой. Пример объявления функций: int sum(int х, int у); 11 или int sum(int, int); void print(const char *str); 11 или void print(const char *); void prlllt ok(l; // или void prlllt ok(vOldl; Определение функции содержит описание типа и названия параметров, а также реализацию. Определение функции имеет следующий формат: <Тип результата> <Название функции>([<Тип> <Название параметраl> [, """, <Тип> <Название параметраМ>]]) <Тело функции> Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  3  1712.10 [return[ <Возвращаемое значение>];] { в отличие от прототипа в опред ел ении функции после типа обязательно должно быть указ ано название параметра, которое является локальной переменной. Эта переменная создается при вызове функции, а после выхода из функции она удаляется. Таким образом, локальная переменная видна только внутри функции. Если название локальной переменной совпадает с названием rло бальной переменной, ТО все операции будут ПРОИЗВОДИТЬСЯ С локальной переменной, а значение rло6альной не изменится. Чтобы в этом случае обратиться к rлобальной переменной, необходимо перед названием указ ать оператор ::. Пример: int sum(int х, int у) int z = х + У; 11 Обращение к локальной переменной х z = ::х + У; 11 Обращение к rлобальной переменной х return z; После описания параметров, внутри Ф иryрных ско бок, размещаются инструкции, которые будут выполняться при каждом вызове функции. Фиrурные скобки указыв aIOТСЯ в любом случ ае, даже если тело функции состоит только из ОДНОЙ инструкции. Точка с запятой после закрывающей фиrурной скобки не указывается. Вернуть значение из функции позволяет оператор re turn. После исполнения этоrо оператора выполнение функции останавливается и управление передается обратно в точку вызова функции. Это означает, что инструкции после оператора r eturn никоrда не будут выполнены. При использовании оператора ret ur n не должно быть неоднозначных ситуаций. Например, в этом случае возвращаемо е значение зависит от условия: int sum(int х, int у) if (х > 01 return х + У; Если переменная х имеет значение больше нуля, то все будет нормально, но если переменная равна нулю или имеет отрицательное значение, то возвращаемое значение не определено и функция вернет произвольное значение, так называемый Ilмycopll. В этом случае при компиляции выводится предупреждающее сообщение: "warning С471 5: sum: значение возвращается не при всех путях выполнения ll . Чтобы избежать подобных Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  4  1712.10 неоднозначностей, следует в конце тела функции вставить оператор ret ur n СО значением по умолчанию: int sum(int х, int у) if (х > 01 return х + У; return о; Если перед названием функции указан о ключевое слово vo id, то оператора re turn может не быть. Однако, если необходимо досрочно прервать выполнение функции, то оператор re turn указывается без Бозвращаемоrо значения. Пример: void рПllt ok (1 std: : cout « rrOK rr « std:: endl; return; 11 Преждевременное завершение функции std: : cout « rrэта ИНСТРУКЦИЯ НИI'ЮI"да не будет выполнена! ! ! rr; При вызове функции из проrp аммы указывается название функции, после KOToporo внутри крyrлых скобок передаются значения. Если функция не принимает параметров, то указываются только круrлые скобки. Если функция возвращает значение, то ero можно присвоить переменной или просто проиrнорировать. Необходимо заметить, что количе ство и тип парамеТРОБ в определении функции ДОЛЖНЫ совпадать с количеством и типом параметров при вызове, иначе будет выведено сообщение об ошибке. Пример вызова трех функций: pr int (rrMessage rr) ; рПllt ok (1 ; z = sum (10, 2 О 1 ; 11 Функция выведет сообщение Мessage 11 Вызываем функцию б е з па раме тр о В 11 Переменной z будет присвоено значение 30 Переданные значения присваиВaIOтся переменным, расположенным в той же позиции в определении функции. Так при использовании функции sum (1 переменной х будет присвоено значение 10, а переменной у  значение 2 о. Результат выполнения функции присваивается переменной z. В качестве примера создадим три разные функции и вызовем их (листинr 8.1). Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  5  1712.10 I .1IИСТIПП 8.1. Создюmе Ф )...к.ций и их BЪnOВ #include <iostream> 11 сб ъявле ния функций int sum(int х, int у); 11 или int sum(int, int); void print(const char *str); 11 или void print(const char *); void prlllt ok(l; // ИЛИ void prlnt ok(voldl; int main (1 / / Выз о в фуНКЦИЙ pr int (rrMessage rr) ; prlllt ok (1 ; std::cout «sum(10, 20) «std::endl; std: : cin. get (1 ; return о; // Message // ОК / / 30 { 11 Определения функций int sum(int х, int у) return х + У; / / Два цараметра void print(const char *str) std::cout «str «std::endl; / / QцИН цараметр void pr lllt ok (1 std: : cout « rrOK rr « std:: endl; 11 Без парамеТРОБ Расположенпе объявленпЙ п определенпЙ функцпЙ Ве е инструкции в проrpамме выполняются последовательно сверху вниз. Это означает, что прежде чем использовать функцию в проrpамме, ее необходимо предварительно объявить. Поэтому объявление функции должно быть расположено перед вызовом функции. Обратите внимание на то, что размещать определение одной функции внутри друrой нельзя. Таким образом, название функции всеrда является rлоб альным ид е нти Ф икатор ом. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  б  1712.10 Внебольших проrpаммах допускается объявление функции не указывать, при условии, что определение функции расположено перед функцией main (1 (листинr 8.2). Кстати, функция main (1 также не требует объявления, так как она вызывается первой. .1IИСТIПП 8.2. р"СIЮложение определения ф)...к.ЦlШ перед ф)...к.u;иeй юап,О # include <iostream > int S1..Шl (int х, int у) return х + У; int main (1 std::cout «sum(10, 201 «std::end1; //30 std: : cin. get (1 ; return о; При увеличении количества функций возникает ситуация, коrд а внутри функции вызывается вторая функция, а внутри второй вызывается третья и т. д. В результате приходится решать вопрос что было раньше курица или яйцо. Чтобы избежать такой ситуации объявления функций следует размещать в начале проrpаммы перед функцией main (1 , а определения  после функции main (1 (листинr 8.3). В этом случае порядок следования определений функций не имеет значения. I .1IИСТIПП 8.3. р"С IЮло жение объявлений и определений Ф )...к.ций # include <iostream > int S1..Шl (int, int); 11 сб ъявление int main (1 std::cout «sum(10, 201 «std::end1; //30 std: : cin. get (1 ; return о; int sum(int х, int у) { 11 Определение return х + У; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  7  1712.10 При ув еличении раз мера проrpаммы объявлений и определений функц ий становится все больше и больше. В этом случае проrpамму разделяют на несколько отдельных файлов. Объявления функций выносят в заrоловочный файл с расширением h (иноrда hpp), а определения функций размещают в одноименном файле с расширением срр. Все файлы располarают в одной папке с основным файл ом, содержащим функцию main (1 . В дальнейше м с помощью директивы # inc lude ПОДКЛЮЧaIOТ заrоловочный файл ВО всех остальных файлах. Если в директиве #inc lude название зarол овочноrо файла указыв ается внутри уrловых скобок, то поиск файл а осуще ствляется в системных папках. Если название указано внутри кавычек, то поиск вначале ПрОИ3БОДИТСЯ в папке с основным файл ом, а затем в системных папках. В кач естве примера вынесем функцию sum (1 в отдельный файл (например, с названием "mymodu1e "), а затем подключим ero к основному файлу. Для создания файл а туто dule. срр в окне ОБОЗ})l?'ватl?'Jn. })I?'Шl?'шоп"i щелкае м правой кнопкой мыши на пункте Фаiiлы ПfХО,ll;Ноrо :кода и из KOHTeKCTHoro меню выбираем пункт Добавить I Создать ')ЛI?'I'o-Ie'НТ. В результате откроется окно ДОQаВЛl?'lПII?' HOBoro ')ЛII?'IП:;). Выделяем пункт ФаЙл С++ (.е!'!'), вводим название файла ("туто dule ") и нажимаем кнопку До6авптъ. В результате файл будет добавлен в папку проекта и ero название отобразится в окне ОБОЗ})l?'ватl?'Jn. })I?'ШI?'IПIii, а сам файл будет открыт на отдельной вкладке. Вставляем в э тот файл код из листинrа 8.4. I .1IИСТIПП 8.4. Файл lfi)'lno,lпlе .ер!, #include rrmуnюdulе. h rr int sum(int х, int у) { 11 Определение return х + У; Для создания файла туто dule.h в окне 060з!,еватеJTh !,ешеШПI щелкае м правой кнопкой мыши на пункте Заrоловочныl?' фаiiлы и из KOHTeKCTHoro меню выбираем пункт Добавить I Созда ть ')ЛI?'I'o-Ie'НТ. В результате откроется окно ДОQавлI?'Ш-!е' HOBoro ')Лl?'l'o-le'нта Выделяем пункт Заrоловочныii фm:"iл (.11), ВВОДИМ название файла ("mymodule ") и нажимаем кнопку До6авптъ. В ставляем в этот файл код из листинrа 8. s. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  8  1712.10 I .1IИСТIПП 8.5. Фnйл lfi)'lno,lпlе .1, #ifndef MYМODULE н #define MYМODULE н #include <iostream> int sum(int х, int у); # endif Вс е содержимое файла туто dule.h расположено внутри усл овия, которое проверяется перед компиляцией. Условие выrлядит следующим образом: #ifndef MYМODULE н / / Ине трукции # endif Это условие следует читать так Il если не существует макр оопределения MYМOD UL Е Н, то вставить инструкции в то место, rде подключается Ф айл ll . Название макроопределения обычно совпадает с названием зarоловочноrо файла. Только все 6Ylffibl указЫВaIOТСЯ в верхнем реrистре и точка заменяется символом подчеркивания Условие начинается с директивы #i fnde f и заканчивается директивой #е ndi f. Все это необходимо, чтобы объявления идентификаторов не вставляпись дважды. Для этоrо в первой инструкции внутри условия объявляется макр оопределение MYМODUL Е н с помощью директивы #def ine. В этом случае повторная проверка условия вернет ложное значение. Для однократноrо включения файла можно также воспользоваться директивой #р ragma: #pragma оnсе Теперь, чтобы использовать функцию s um ( 1 , достаточно подключить файл mymodule.h к основной проrpамме. Пример подключения приведен в листинrе 8. б. I .1IИСТIПП 8.6. Фnйл lfinП'.срр #include rrmуnюdulе. h rr int main (1 std::cout «sum(10, 201 «std::end1; //30 std: : cin. get (1 ; return о; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  9  1712.10 в директиве # incl ude допускается указывать не только название файла, но и абсолютный или относительный путь к нему. Это позволяет размещать файлы по различным папкам. Примеры указания а6солютноrо и относительноrо пут: #inc1ude "C:\\book\\test\\test\\mymodu1e.h" #include rrC :/Ьооk/tеst/tеst/mуnюdulе. h rr #include rr /Ьооk/tеst/tеst/mуnюdulе. h rr #include rrfоldеr/mуnюdulе. h rr При использовании больших проrpамм создают статическую (файлы с расширением lib в VC++) или динамическую (файлы с расширением d11) библиотеку. Статические библиотеки становятся частью проrpаммы при КОМПИЛЯЦИИ, а дина:мические библиотеки подrpуж аются во время выполнения проrpаммы. Процесс создания библиотек мы буде м изучать HeMHoro позже, а сейчас рассмотрим способ указания пути к папкам с о статич е ски ми 6 и бл и отеками. При использовании СThТ1lческих библиотек зarоловочные файлы обычно размещают в папке include, а сами библиотеки  в палке lib. Далее добавляют пути к этим папкам в свойства проекта. Для этоrо запускаем проект и из меню Вид выбираем пункт Дисинчl' СВОЙСТВ. В окне Дисинчl' своЙств раскрываем список, например, ПЬпg I \\';i1l32, и щелкаем правой кнопкой мыши на строке J\Iiпоsоft.('I'I',\\';i1l32.пS1'. IЬ KOHTeKCTHoro меню выбираем пункт CBoii("ТE:;). В открывше мся окне выделяем пункт Каталоrп \.C++. Выделяем строку Каталоrп ВКJIЮЧI?НПЯ. Щелкаем мышью на появившейся кнопке со стрелкой вниз и выбираем пункт ][змmIТЪ. Добавляем путь к папке include и нажимаем кнопку ОК. Далее выделяем строку КаТ;),JIоrп бпбJПIОТI?К. Щелкаем мышью на появившейся кнопке со стрелкой вниз и выбираем пункт ][змmIТЪ. Добавляем путь к папке lib и нажимаем кнопку ОК. Сохраняем все файлы проекта. В результате все измениения будут сохранены в файле C:\DocUffients алd Settings \<Пользователь>\Lосаl S ettings \Applic ation Data\Мicros oftIlvfSBui1d \v4. O\М:icros oft. Срр. Win32. и, er. Этот файл будет подключаться ко всем проектам определенноrо пользователя. Содержимое файла выrлядит примерно так: <7 IOLIl version= rr 1. О rr encoding= rrutf 8 rr7> <Project DefaultTargets=rrBuild rr ToolsVersion=rr4. orr xm.l.ns= rЪttр: // schemas. microsoft. сот/ developer /msbuild/2 003 rr> <PropertyGroup> <Inc1udepath>C:\book\inc1ude;$(Inc1udepathl</Inc1udepath> </PropertyGroup> <PropertyGroup> Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  10  1712.10 <LibraryPath>C:\book\lib;$(LibraryPathl</LibraryPath> <! PropertyGroup > <1 proj ect > Способы передачп параl\Iетров в функцпю Как вы уж е знаете, после названия функции, внутри круrлых скобок, указывается тип и название параметров через запятую. Если функция не принимает параметров, то указыв aIOТСЯ только круrлые скобки или внутри круrлых скобок задается ключевое слово void (в языке С ключевое слово void является обязательным). В определении функции после типа обяз ательно должно быть указ ано название параметра, которое является локальной переменной. Эта переменная создается при вызове функции, а после выхода из функции она удаляется. Таким образо м, локальная переменная видна только внутри функции и ее значение между вызовами не сохраняется (исключением являются статические переменные). Если название локальной переменной совпадает с названием rло6альной переменной, ТО все операции будут ПрОИ3БОДИТЬСЯ С локальной переменной, а значение rло6альной не изменится. Чтобы в этом случае обратиться к rло6альной переменной, необходимо перед ее названием указать оператор : :. При вызове функции указ ывается название функции, после KOToporo внутри крyrлых ско бок передаются значения. Количе ство и тип параметров в определении функции должны совпадать с количеством и типом параметров при вызове, иначе будет выведено сообщение об ошибке. Пер еданные значения присваиваются переменным, расположенным в той же позиции в определении функции. Так при вызове функции sum ( 10, 2 О 1 (прототип in t sum (int х, int yl) переменной х буд ет присвоено значение 10, а переменной у  значение 2 о. Если функция не принимает параметров, то указЫВaIOтся только круr-л ые скобки. По умолчанию в функцию передается копия значения переменной, а не ссылка на переменную. Таким образом, изменение значения внутри функции не затронет значение исходной переменной. Пример передачи параметра по значению приведен в листинrе 8.7. I .1IИСТIПП 8.7. Пер eД<l'ffi Шlрnreтр n IЮ Зlffiчению #include <iostream> void func (int х); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 11  1712.10 int main (1 int х = 10; func (хl ; std::cout «х «std::endl; 11 10, а не 30 std: : cin. get (1 ; return о; void func (int х 1 х = х + 20; 11 Значение ниrде не сохраняется! Передача копии значения ДЛЯ чисел является хор ошим реше ни ем, но при использовании массивов и объектов, а также при нео6ходи мости изменить значение исходной переменной, лучше применятъ передачу указателя. Для этоrо при вызове функции перед названием переменной указывается оператор & (взятие адр еса), а в пр ототип е Ф ун кц И И объявляет ся указ ате ль. В это м случ ае в фу нкц ию пер ед ается н е значение переменной, а ее адрес. Внутри функции вместо переменной используется у каз атель. Пр и мер пер ед ач и ук аз ат еля пр ив ед ен в л исти Hre 8. 8. I .1IИСТIПП s.s. Пер eД<l'ffi )'" юnтеля в Ф )...к.цИIO #include <iostream> void func (int * у) ; int main (1 int х = 10; func (&х 1 ; std: : cout « х « std:: endl; std: : cin. get (1 ; return о; 11 Передаем адрес / / 30, а не 10 void fUnC(int *уl { *у = *у + 20; 11 Изменяется значение переменной х Однако, если функция большая, то разыменовывать указатель при каждой операции не очень уд обно. В языке С++ суще ствует еще один способ передачи параметров  Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  12  1712.10 механизм ССЫЛОК. Суть ero заключается в ТОМ, ЧТО внутри функции переменная является псевдонимом ИСХОДНОЙ переменной. Любые изменения псевдонима отражaIOТСЯ на ИСХОДНОЙ переменной. При использовании механизма ссылок перед названием переменной в объявлении и определении функции указывается оператор &, а при вызове  только название переменной. Пример использования механизма ссылок приведен в листинrе 8.9. l.тшст IПП' 8.9. Не поль ЗОВ;[I mre I'rre:хаНИ'Зl'rlil ссылок #include <iostream> void func (int & у) ; int main (1 int х = 10; func (хl ; std::cout «х «std::endl; 1130, а не 10 std: : cin. get (1 ; return о; void fUnC(int &уl 11 Переменная у является псеЕЩОНИМОМ переменной х у = у + 20; 11 Изменяеrк:я значение переменной х Передача I\IaCCIIBOB В ФУНКЦIIЮ Передача одномерных массивов и CCтpOK осуществляется с помощью указателей. Обратите внимание на то, что при вызове функции перед названием переменной не нужно добавлять оператор &, так как название переменной содержит адрес первоrо э лемента массива. Пример передачи Сстроки приведен в листише 8.10. I .1IИСТIПП 8.10. ПереД<l'ffi Сстроки в ф)"ИКЦИЮ #include <iostream> void funcl (char *s); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  13  1712.10 void func2(char s[]I; int main (1 char str [] = rrStr ingrr; std::cout «sizeof(str) «std::endl; 117 func 1 (str); 11 Оператор & перед str не указывается! ! ! func2 (str) ; std::cout «str «std::endl; 11 strinG std: : cin. get (1 ; return о; void funcl(char *5) 5[0] = 1;з1; 11 Изменяется значение элемента массива str std: : cout « sizeof (s) « std:: endl; 11 4, а не 7!!! void func2 (char s [] 1 5[5] = IG 1 ; 11 Изменяется значение элемента массива str Объявление char * s эквивалентно объявленшо char s [ ] . и в том и в дрyrом случ ае о бъявл яется указ атель н а тип с ha r. О 6р атите в н иман и е н а з н ач е н ИЯ, БО:ЗВР ащ ае мы е оператором si "е of вне и внутри функции. Вне функц ии оператор возвращает размер Bcero символьноrо массива, в то вре:мя как внутри функции оператор si ze of возвращает только размер указателя. Это происходит потому что внутри функции переменная s является указателем, а не мае СИВОМ. Поэтому е ели внутри функции необходимо знать размер массива, то количество элементов (или размер в байтах) ел еду ет пер ед ав ать в Д о п ол нитель н о м пар аметр е. При передаче MHoroMepHoro массива необходи мо явным образ ом указывать все размеры (н алример, in t а [4] [ 4] [4] ). Самый первый размер допускается не указывать (например, in t а [] [ 4] [4]). Пример передачи двухмерноrо массива в функц ию п риведен в листинrе 8.11. I .1IИСТIПП 8.11. ПереД<l'ffi ДВ)'XI>leplЮr о mссивn # include <iostream > void func (int а[][ 4] 1 ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  14  1712.10 int main (1 const short ARR ROWS = 2, ARR COLS = 4; int i, j; int arr[ARRROWS][ARRCOLS] = { {l, 2, 3, 4}, {5, 6, 7, 8 { {; func (arr); 11 ВЫВОД им з наче ния for (i=O; i<ARRROWS; ++i) for (j=O; j<ARRCOLS; ++jl std::cout.width(21; std::cout «arr[i][j]; 11 Ширина по л..q std::cout «std::endl; std: : cin. get (1 ; return о; void fUnC(int а[][4]1 { // или void fUnC(int а[2][4]1 а [О] [О] = 80; Такой способ передачи MHorOMepHoro массива нельзя назвать универсальным, так как суще ствует жесткая привязка к размеру. Одним из способов решения проблемы является создание дополнительноrо массива указ ател ей. В ЭТОМ случ ае в функцию передается адрес первоrо элемента массива указателей, а объявление параметра в функ Ц И И выrлядит так int *а[] ИЛИ так: int **а Пример передачи массива указателей приведен в листинrе 8.12. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  15  1712.10 I-тшст IПП 8.12. Передnчtl IIrlilССИВ;[l :'r"К;[IЗ ;[Iтеrnй # include <iostream > void fUnC(int *а[], short rows, short соlз); int main (1 const short ARRROWS = 2, ARRCOLS int arr[ARRROWS][ARRCOLS] = { {1, 2, 3, 4}, {5, 6, 7, 8 { 4' , {; 11 Со=щаем массив указателей int *parr[] = {ап[О], ан[1]{; 11 передаем ацрес массива указателей func(parr, ARRROWS, ARRCOLS); std: : cin. get (1 ; return о; void fUnC(int *а[], short rows, short соlз) 11 или void func(int **а, short rows, short cols) int i, j; for (i=O; i<rows; ++i) for (j=O; j<co1s; ++jl std::cout.width(21; std::cout «a[i][j]; std::cout «std::endl; Однако и этот способ имеет недостаток, так как нужно создавать дополнительный массив указ ателей. Наиболее прие:млемым способом является передача MHorOMepHoro массива как одномерноrо. В этом случ ае в функцию передается адр ес первоrо элемента массива, а в параметре объявляется указатель. Так как все элементы MHorOMepHoro массива располarmoтся в па:мяти последовательно, зная количество элементов или размеры можно вычислить положение текущеrо элемента, используя aдpecHJ'lO Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  16  1712.10 арифметику. Пример передачи двухмерноrо массива как одномерноrо показан в листинrе 8.13. .1IИСТIПП 8.13. ПереД<l'ffi ДВ)'XI>leplЮr О mссивn KnK ОДlЮ leplЮr О # include <iostream > void func(int *а, short rows, short cols); int main (1 const short ARR ROWS = 2, ARR COLS = 4; int arr[ARRROWS][ARRCOLS] = { {l, 2, 3, 4}, {5, 6, 7, 8 { {; 11 Передаем в функцию адрес первоrо элемента массива func(arr[O], ARRROWS, ARRCOLSI; std: : cin. get (1 ; return о; void func (int * а, short roliJS, short соl.s) int i, j; for (i=O; i<rows; ++i) for (j=O; j<co1s; ++jl std::cout.width(21; std: : cout « а [i * cols + j]; 11 Вычисляем положение элемента std::cout «std::endl; Передача в функцию мас сива CCтpOK осуществляется также как передача массива указ ателей. Чтобы в функцию не передавать количество элементов можно при инициализации мае сива CCтpOK последнему элементу присвоить нулевой указатель. Этот элемент будет служить ориентиром конца массива. В качестве примера выведем все строки внутри функции (листинr 8.14). Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  17  1712.10 I .1IИСТIПП 8.14. ПереД<l'ffi mссивn CтpOK # include <iostream > void func(char *s[]I; int ,"ain (1 char * str [] = {rrStr ingl rr, rrStr ing2 rr, rrStr ing3 rr , О 11 Вставляем нулевой указатель, чтобы был ориентир {; func (str) ; std: : cin. get (1 ; return о; void func (char * s [] 1 { / / или void func (char * * sl while (* s) { 11 ВЫВОДИМ все строки std: : cout « *s « std:: endl; ++5; Необязательные параl\Iетры Чтобы сделать некоторые параметры необязательными, следует в объявлении функции присвоить параметру начальное значение. В этом случае, если при вызове функции параметр не указ ан, то переменной будет присвоено начальное значение. Обратите внимание на то, что начальное значение указывается только в объявлении функции. Повторять ero в определении функции не нужно. Следует такж е заметить, что нео6язательные параметры ДОЛЖНЫ следовать после обязательных, иначе будет выведено сообщение об ошибке. В качестве примера сделаем второй параметр функции s u," (1 необяз ательным (листинr 8.1 S). I .1IИСТIПП 8.15. Необязnтельные rmpnreтpbl #include <iostream> int sum(int х, int у=2); 11 Указываем начальное значение Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  18  1712.10 int ,"ain (1 std: : cout « S1..Шl( 10, std: : cout « sum( 101 std: : cin. get (1 ; return о; 201 «std::end1; « std:: endl; / / 30 / / 12 int sum(int х, int у) 11 Начальное значение в определении не указывается! ! ! return х + У; Переl\Iенное КОЛIIчество параметров Количество параметров в функции может быть произвольным, при условии, что суще ствует один обязательный параметр. В объявлении и определении функции переменное число парамеТРОБ 060ЗН ачается тре:мя точками. Получить доступ к этим параметрам внутри функции можно несколькими способами. Первый способ заключается в передаче количества парамеТРОБ в обязательном параметре. В этом случае адр ес последнеrо обязатель Horo параметра и сохраняют ero в указ ателе. Далее с помощью указателя происходит перемещение к следующе му параметру. В качестве примера напишем функцию суммирования произвольноrо количе ства целых чисел (листинr 8.1 б). -Тшст IПП' 8.16. С:'r'1'rПrпqIOВtlНие :проlfЗ вольноrо ко..тшчеств;[I цeJlЬ1\': чисел #include <iostream> int sum(int х, ...); int ,"ain (1 std: : cout « sum(2, 20, 30) « std:: endl; std: : cout « sum(З, 1, 2, 3) « std:: endl; std: :cout «sum(4, 1, 2, 3, 4) « std: :endl; std: : cin. get (1 ; return о; // 50 // 6 // 10 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  19  1712.10 int S1..Шl(int Х, ...) int result = о; int *р = &Х; for (int i=O; ++р; result += 11 Получаем адрес последнеrо параметра i<x; ++i) 11 П=ремещаем указатель на следующий параметр *р; 11 Прибавляем очередное число return result; в этом при мере тип 06язательноrо параметра совпадает с типом остальных парамеТРОБ. Если мы захотим просуммировать произвольное количество вещесmенных чисел, ТО можно изменить тип 06язательноrо параметра, с ПОМОЩЬЮ KOToporo передается количе ство парамеТРОБ, или при перемещении указ ателя выполнять приведение типов (листинr 8.17). -Тшст IПП' 8.17. С:'r'1'rПrпqIOВtlНие :проlfЗ вольноrо ко..тшчеств;[I веIl.f'!ствеlПlbl\': чисел #include <iostream> double S1..Шl(int Х, ...); int ,"ain (1 std: : cout « S1..Шl(2, 20.2, 3.6) «std:: endl; std: : cout « S1..Шl(З, 1., 2.8, 3.4) «std:: endl; std: : cin. get (1 ; return о; // 23.8 // 7.2 doUble sum(int х, double result .. .1 int *pi = &Х; ++pi; pd = relnterpret for(int i=O; i<x; 0.0, *pd = о; 11 ПОлучаем ацрес последнеrо параметра 11 Перемещаем указатель до приведения ТИПОВ! I I cast<double *> (pl); 11 Приведение типов ++il result += *pd; 11 Прибавляем очередное число ++pd; 11 Пе ремещаем указ а те ль на с ледующий па раме тр Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  20  1712.10 return result; { При передаче в функцию произвольноrо количества строк в последнем параметре можно зад ать нулевой указатель. В этом случае передавать количество парамеТРОБ явным образо м не нужно. Для примера передадим в функцию несколько строк (листинr 8.18). Внутри функции выведем содержимое строк в окно консоли. .1IИСТIПП 8.18. ПереД<l'ffi произволыюrо коJШЧeСТВn CCTpOK # include <iostream> void func (char *5, ...); int ,"ain(1 { char strl[] = rr s tringl rr , str2[] = rr s tring2 rr ; func (str 1, str 2, О); 11 Нулевой указатель func (str 1, str 2, str 1, О); 11 в последнем параметре ! std: : cin. get (1 ; return о; void func (char *5, ...) char **р = &5; while (*рl std::cout «*р «std::endl; ++р; СледJ'lOЩИЙ способ состоит в использовании специальных макросов va  st ar t ( ) va arg (1 и va end (1 . Прототипы макросов: #include <cstdarg> void va start(va list <Указатель>, <ПОследний параметр» <Тип> va arg(va list <Указатель>, <Тип данных» void vaend(valist <Указатель» Тип va llst определен следующи м образ ом typedef char * valist; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  21  1712.10 Вначал е объявляется указатель типа va list. Далее должна ПРОИЗВОДИТЬСЯ инициализация указателя с помощью макрос а va s tar t ( 1. В первом параметре передается указатель, а во втором  название последнеrо 06язательноrо параметра. Доступ к параметрам осуще ствляется с помощью макро са va arg (1, который возвращает значение текущеrо параметра и перемещает указатель на следующий параметр. В первом параметре макроса va  ar g (1 передается указатель, а во втором  название типа данных. Макро с va  end (1 сообщает об окончании перебора параметров. Пример использования макросов va  st ar t ( 1, va  arg (1 и va  е nd (1 приведен в листинrе 8.19. -ТШСТIПП 8.19. ИспользовnIOre I'rrnкpOCOB ,"иSt.."H.tO, ,"иШ"gО И,"иешIО #include <iostream> #include <cstdarg> int S1..Шl(int Х, ...); int ,"ain (1 std: : cout « S1..Шl(2, 20, 30) « std:: endl; std: : cout « S1..Шl(З, 1, 2, 3) « std:: endl; std: :cout «S1..Шl(4, 1, 2, 3, 4) « std: :endl; std: : cin. get (1 ; return о; // 50 // 6 // 10 int S1..Шl(int Х, ...) int result = о; std: :valist р; vastart (р, х); for (int i=O; i<x; ++il result += va  arg (р, int); vaend(pl ; return result; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  22  1712.10 Переrружа ФУНКЦIIII в предыдущих раздел ах мы создали функцию sum (1, предназначенную для суммирования двух целых чисел. В один прекрасный момент возникнет ситуация, коrд а потребуется произвести суммирование вещественных чисел. Что в этом случае делать ? Создавать функцию с дрyrим названием? В языке С++ существует решение этой ситуации, называемое переrpузкой функции. Переgpузка функции  это возможность использования одноrо названия для нескольких функций, разЛИЧaIOЩИХСЯ типом парамеТРОБ или их количеством. lЬменение только типа Бовращаемоrо значения неодостаточно для переrpузки функции. В качестве примера переrpузим функцию sum () таким образом, чтобы ее название можно было использовать ДЛЯ суммирования к ак целых чисел, так и вещественных (листинr 8.20). I .1IИСТIПП 8.20. Переrp),кn ф)",кций #include <iostream> int sum(int х, int у); douk1e sum (douk1e х, douk1e yl; int main () 11 Суммирование целых чисел std: : cout « sum (10, 201 « std:: end1; / / 30 11 Суммирование вещественных чисел std::cout «sum(1O.5, 20.71 «std::end1; // 31.2 std: : cin. get (1 ; return о; int sum(int х, int у) return х + У; douk1e sum (douk1e х, douk1e уl return х + У; При вызове переrpуж енной функции может возникнуть неоднозначность, при которой ко мпилятор не может выбрать, какую функцию следует вызвать. В иновниками таких ситуаций бывaIOТ значения по умолч анию, автоматическое прео6разование типа при Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  23  1712.10 передаче значения в функцию, а также возможность множеС1Бенной записи при объявлении параметра. Пример проблемы при использовании значений по умолчанию: int S1..Шl(int х); int sum(int х, int у=2); std::cout «sum(10, 20) «std::endl; 11 Нормально std::cout « sum(10) « std::endl; 11 Неоднозначность В следующе м примере нельзя сделать выбор в какой тип данных СВ тип f 10 at или do uk 1e) следует автоматически преобр аз ов ать целое число: float sum(float х, float у); douk1e sum (douk1e х, douk1e yl; std::cout «sum(10.5, 20.41 «std::end1; // Нормально std::cout « sum(10, 20) « std::endl; 11 Неоднозначность Если бы существовала функция только с параметрами, имеющими тип do uk 1e, то целое число было бы автоматически преобразовано в тип do uk 1e. Аналоrичная проблема возникает при одновременном использовании знакОБоrо и 6еззнаковоrо типов: void pr int (char ch); void print(unsigned char ch); print (131); 11 Нормально print (119); 11 Reоднозначность Следующий пример демонстрирует проблему изза возможности множественной записи при объявлении параметра С объявление char * st r эквивалентио char st r [ ]): void print(char *str); void print(char str[]I; print (rrString rr) ; 11 НеQДнозначность Кроме Toro, следует уч итывать, что разный способ передачи параметров в функцию также может ПрИБОДИТЬ к неоднозначности: void print(int х); void print(int &х); int n = 25; print (nl ; 11 НеQДнозначность Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  24  1712.10 Шаблонные (обобщенные) ФУНКЦIIII Если присмотреться к реализации функции su," ( 1, то можно заметить, что вне зависимости от типа параметров внутри функции будет одна и та же инструкция re turn х + У;, так как оператор + позволяет сложить числа лю60rо типа. Для таких случаев в языке С++ вместо переrpузки функции следует применять uш6ЛOliiiые функции. Шаблонные функции называют также 0606ИjJ3iiНЫМU. Компилятор на основе шаблонной функции автоматически созд аст переrpуженные версии функции в зависимосТ1l ОТ имеющихся способов ее вызова в проrpамме. Описывается шаблонная функция по следующе й схеме: te:mplate<class Тип 1 [, ..., class ТипN] > Тип Название функции(Тип Название переменнойl [, ..., Тип Название переменнойN]) Ис ТРУ:КЦИИ; После ключевоrо слова templat е внутри уrловых скобок через запятyIO указЫВaIOТСЯ обобщенные названия ТИПОВ. ЭШ названия ИСПОЛЬЗJ'lOТСЯ для описания типов параметров и MOryт использоваться внутри функции. При компиляции обобщенные типы будут заменены реальными типами данных. Перед названием обобщенноrо типа Moryт быть указаны ключевые слова clas s или type пате, которые 060значaIOТ ОДНО и то же. Остальное описание шаблонной функции совпадает с описанием обычной функции, только вместо реальных типов данных указывaIOТСЯ названия обобщенных типов, перечисленных после ключевоrо слова temp la te. В каче стве при мера создадим ш аблонную функцию для сложения чисел (листинr 8.21). I .1IИСТIПП 8.21. шnблоIolые ф)...к.ЦlШ #include <iostream> template<class Туре> Туре sum(Type х, Туре yl; int ,"ain (1 std::cout «sum(10, 20) «std::endl; std::cout «sum(10.5, 20.41 «std::end1; std::cout «sum(10.5f, 20.7fl «std::end1; / / 30 // 30.9 // 31.2 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  25  1712.10 std: : cin. get (1 ; return о; template<class Туре> Туре sum(Type х, Туре уl return х + У; Компилятор на основе шаблонной функции и способах ее вызова автомашчески создаст следующие переrpуженные версии функции: int sum(int х, int у); float sum(float х, float у); douk1e sum (douk1e х, douk1e yl; Шаблонная функция s um (1 из листинrа 8.21 позволяет складывать числа только одноrо типа. Ч то6ы можно было складывать числа разных типов, например, int и do ub le, следует объявить два разных обобщенных типа: template<class Туреl, class Туре2> Туре1 sum(Type1 х, Туре2 уl { return х + У; Обобщенные и реальные типы можно смешивать в объявлении парамеТРОБ шаблонной функции. Шабл онные функции допускается переrpужать. Существуют два способа переrpузки. Первый способ заключается в определении обычной функции с конкретными параметрами. Определение функц ии во втором случае выrлядит так: te:mplate<> Тип Название функции<Типl, ..., ТипМ>(Типl Название переменнойl [, ..., ТипN Название переменной М]) ИНСТРУКЦИИ; После ключевоrо слова templa te указывaIOТСЯ пустые уrловые скобки, а после названия функции внутри yrловых скобок через запятую перечисляются реальные типы данных. Пример переrpузки шабл онных функций приведен в листинrе 8.22. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  26  1712.10 I .1IИСТIПП 8.22. Переrp),кn lШIблоIOlЫХ ф)"НlЩИЙ # include <iostream > template<class Туреl, class Туре2> Туре1 sum(Type1 х, Туре2 yl; int sum(int х, int у); te:mplate<> douk1e sum<douk1e, douk1e>(douk1e х, douk1e yl; te:mplate<class Туреl, class Туре2> Туре1 sum(Type1 х, Туре2 у, int zl; int ,"ain (1 std::cout «sum(10, 201 «std::end1; //30 std::cout «sum(10.5, 20.41 «std::end1; //30.9 std: : cout « sum( 10. 5f, 20. 7fl «std:: end1; / / 31.2 std: : cout « sum( 10.5, 201 « std:: end1; / / 30.5 std: : cout « sum( 10.5, 2.3, 101 « std:: end1; / / 22.8 std: : cin. get (1 ; return о; te:mplate<class Туреl, class Туре2> Туре1 sum(Type1 х, Туре2 уl { return х + У; int sum(int х, int у) return х + У; / / Способ 1 te:mplate<> douk1e sum<douk1e, douk1e>(douk1e х, douk1e уl { // Способ 2 return х + У; { 11 Переrрузка и смешивание обобщенных и явных типов te:mplate<class Туреl, class Туре2> Туре1 sum(Type1 х, Туре2 у, int "l return х + у + z; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  27  1712.10 Встрапваеl\Iые функцпп Передача управления в функцию сопряжена с потерей скор ости выполнения проrpаммы, так как вызов функции, передача в нее параметров и возврат значений требуют дополнительных затрат времени. Если размер функции небольшо й, то име ет смысл объявить такую функцию встраиваемой. В этом случае при компиляции содержимое функции будет вставлено в место вызова функции. Тем не менее следует помнить, что при ЭТОМ ПРОИСХОДИТ увеличение размера исполняемоrо файла. Поэтому, если большая функция вызывается MHoro раз, то лучше ее оставить обычной функцией, в то время как функция, состоящая из одной инструкции, являтся первым кандидатом ДЛЯ в стр аНЕ ания. Чтобы объявить функц ию встраиваемой, следует перед функцией добавить ключевое слово inline. Следует учитывать, что ключевое слово inline является ЛИШЬ реко мендацией компилятору и может быть проиrнорировано. В качестве примера о бъявим функцию su," (1 встраиваемой (листинr 8.23). I .1IИСТIПП 8.23. Встрnивnе1Ыe ф)"НlЩIШ # include <iostream > inline int sum(int х, int у); int ,"ain (1 std::cout «sum(10, 20) «std::endl; std: : cin. get (1 ; return о; inline int sum(int х, int у) return х + У; Создать встраиваемую функцию можно такж е с помощью директивы #de f ine. Значение, указ анное в этой директиве, подставляется в место вызова функции до КО мпиляции. Название, указ анное в директиве # de f ine, принято называть макроопределением ипи макрОСОМ. Директива имеет следующий формат #define <Название функции> «Параметры» <Инструкция> Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  28  1712.10 Пример использования директивы #def ine приведен в листинrе 8.24. -ТШСТIПП 8.24. ИспользовnIOre директивы #(lеfПlе #include <iostream> #define SUМ(x, уl (х + уl int ,"ain (1 std::cout «SUМ(10, 201 «std::end1; std: : cin. get (1 ; return о; Обратите внимание на то, что в конце инструкции точка с запятой не указ ывается. КОНЦОМ инструкции является конец строки. Если точку с запятой указать, то значение вместе с ней будет вставлено в выражение. Например, если определить макрос так: define SUМ(x, уl (х + yl; то после подстановки значения, инструкция std::cout «SUМ(10, 201 «std::end1; будет выrлядеть следующим образом: std::cout « (10 + 201; «std::end1; Точка с запятой после закрывающей круrлой скобки является концом инструкции, поэтому этот код вызовет ошибку при компиляции. Однако в следующе м примере ошибки не будет, но результат буд ет совершенно дрyrи м. Инструкция int z = SUМ( 10, 201 + 40; после подстановки будет выrлядеть следующим образом: int z = (10 + 201; + 40; Подо бная ситуация приводит к ошибкам, которые трудно найти, так как в этом случ ае инструкция + 40; не возбуждает ошибку при компиляции. Обратите также внимание на то, что выражение внутри тела макроса расположено внутри крyrлых скобок Если скобки не указ ать, то это может привести к недоразумениям, так как никакоrо вычисления выражения не производится. Все выражение внутри тела макроса после подстановки формальных параметРОБ целико м вставляется в место вызова макроса. Например, если определить макр ос следующи м образом: #define SUМ(x, уl х + у Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  29  1712.10 то после подстановки значения, инструкция int z = SUМ( 10, 201 * 40; будет выrлядеть следующим образом: int z = 10 + 20 * 40; Приоритет оператора умно жения выше приорнтета оператора сложения, поэтому число 2 О будет умножено на 4 О, а затем к результату прибавлено число 10. Таким образ ом, результат буд ет 8 10, а не 1200. При указ ании длинноrо выражения внутри тела функции следует учитывать, что определение макроса должно быть расположено на одной строке. Если нужн о размесТ1l1Ь выражение на нескольких строках, то в конце строки необходимо добавить обратную косую черту. После косой черты не должно быть никаких символов, в том числе и комментариев. Пример: #define SUМ(x, уl \ (х + уl Константные параl\Iетры Если внутри функции зн ачение параметра не изменяется, то такой параметр следует объявить константным. Для этоrо при объявлении перед параметро м указывается ключевое слово со nst. Например, функция sum (1 , предназначенная для суммирования чисел, не ПРОИЗВОДИТ изменение значений парамеТРОБ, поэтому параметры можно объяв ить к о не таити ы ми: int sum(const int х, const int у) return х + У; { При использовании указателей важно учитывать местоположение ключевоrо слова со ns t. Например, слеДJ'lOщие объявления не Эlffiивалентны: void print(const char *s); void print(char const *s); void print(char * const s); void print(const char * const s); Первые два объявления являются Эlffiивалентными. В ЭТОМ случае изменить значение, на которое ссылается указ атель, нельзя, но указ ателю можно присвоить дрyrой адрес: void print(con8t char *8) char 82 [] = rrNew rr ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  30  1712.10 s = 52; 5[0] = 1;з 1; std::cout «s «std::endl; / / Но рмаль но / / Ошибка При третьем объявлении изменить значение, на которо е ссылается указатель, можно, но указ ателю нельзя присвоить дрyrой адрес: void print(char * const 5) char 52 [] = rrNew rr ; s = 52; 5[0] = 1;з 1; // Ошибка // Нормально std::cout «s «std::endl; Четвертое объявление запрещает изменение значения, на которое ссылается указатель, и присвоение дрyrоrо адреса: void print(const char * const 5) char 52 [] = rrNew rr ; s = 52; 5[0] = 1;з 1; std::cout «s «std::endl; / / Ошибка // Ошибка { с помощью оператора со ns t cast можно отменить действие ключевых слов со nst и vo 1a ti1e. Формат оператора: const cast< <Тип результата> > «Выражение» Пример приведения KOHcTaHTHoro указ ателя в обычный внутри функции: void print(const char *5) //s[O] = 's'; / / Ошибка char *р = const cast<char *> (s); р[О] = 1;з 1; std::cout «s «std::endl; / / Но рмаль но Пример удаления действия ключевоrо слова с onst у ссылки внутри функции: void func(const int &х) //х = 50; // Ошибка'" 11 Теперь можно изменить значение const cast<int &> (х) = 30; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  31  1712.10 Статпческпе переl\Iенные Пере менные, указанные в параметрах, а также переменные, объявленные внутри функции, являются локальными переменными. Эш переменные создается при вызове функции, а после выхода из функции они уд аляется. Таки м образом, локальная переменная видна только внутри функции. Если внутри функции при объявлении локальной перменной не было присвоено начальное значение, то переменная будет содержать произвольное значение, так называемый "мусор". Если название локальной переменной совпадает с названием rло6 альной переменной, ТО все операции будут ПРОИЗВОДИТЬСЯ С локальной переменной, а значение rло6альной не изменится. Чтобы в этом случае обратиться к rло6альн ой переменной, необходимо перед названием переменной указать оператор ::. Пример сохранения промежуточноrо значения между вызовами функции в rлобальной переменной приведен в листинrе 8.25. -Тшст IПП 8.25. СОЧ-nЮ?! mre :прОl'rrem.)"Т очноr о ЗlffiчеlШЯ В r ло бnльной переl'rleшroй #include <iostream> int х = о; void S1..Шl(int х); int ,"ain(1 { sum( 101 ; sum(201; std::cout «х «std::end1; //30 std: : cin. get (1 ; return о; void S1..Шl(int х) :: х += Х; СтаrпuЧ,ескuе переменные позволяют отказаться от использования rлоб альных переменных, для сохранения промежуточных значений между вызовами функции. Инициализация статической переменной производится только при первом вызове функции. Если при объявлении статической переменной не присвоено начальное Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  32  1712.10 значение, то переменная автоматически инициализируется нулевым значением. После завершения работы функции статическая переменная сохраняет СБое значение, котор ое доступн о при следующем вызове функц ии. При объявлении статической переменной перед типом данных указ ывается ключевое слово st at ic. В каче стве примера переделаем предыдущий пример и используем статическую переменную вместо rлобальной (листинr 8. 2б). -ТШСТIПП' 8.26. ИспользовnIOre СТ;[IТических переl'rlelПlbl\': #include <iostream> int S1..Шl(int у); int ,"ain(1 std: : cout « sum( 101 « std: : endl; // 10 std: : cout « sum(201 « std: : endl; // 30 std: : cin. get (1 ; return о; int sum (int уl static int х = о; 11 Статическая переменная х += У; return Х; Способы возврата значеНIIЯ IIЗ ФУНКЦIIII Вернуть значение из функции позволяет оператор re turn. После исполнения этоrо оператора выполнение функции останавливается и управление передается обратно в точку вызова функции. Это означает, что инструкции после оператора r eturn никоrда не будут выполнены. Если внутри функции нет оператора r etur n, то по достижении закрывающей фиrурной скобки управление будет передано в точку вызова функции. В этом случае возвращаемое значение не определено. Если функция не возвращает никакоrо значения, то вместо шпа данных в объявлении и определении функции указыв ается ключевое слово void. Внутри такой функции оператора r eturn может не быть, однако ero можно использовать без указания значения для преждевременноrо выхода из функции. Вызов функции, не возвращающей Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  33  1712.10 никакоrо значения, нельзя размещать внутри какойли60 инструкции. Только в отдельной инструкции. Пример функции, которая не возвращает никакоrо значения: void print(const char *5) std::cout «s «std::endl; { в остальных случ аях в объявлении и определении функции перед названием функции задается возвращаемый тип данных. Значение этоrо типа ДОЛЖНО быть указано в операторе r eturn. В этом случае возвращается копия значения. Функция может вернуть значение лю60rо типа, кроме массива. Работать с массивами необходимо через пар аметр ы Ф ункц ии, пер ед ав ая указ атель н а н ero, ил и в озвр ащая указ атель н а конкретный элемент. В ызов функции, БозвраЩaIOщей какоели60 значение, можно разместить внутри выражения с правой стороны от оператора . Если функция возвращает ссылку, то допускается размещение функции и с левой стороны от оператора ==. Возвращаемое значение можно присвоить переменной или просто проиrнорировать. Пример функции, возвращающей копшо значения: int sum(const int х, const int у) return х + У; При использовании оператора r et ur n не ДОЛЖНО быть неоднозначных ситуаций. Например, в этом случае Бо:звращае мое значение зависит от уел овия: int sum(int х, int у) if (х > 01 return х + У; Если переменная х имеет значение больше нуля, то все будет нормально, но если переменная равна нулю или имеет отрицательное значение, то возвращаемое значение не определено и функция вернет произвольное значение, так называемый Ilмycopll. В этом случае при компиляции выводится предупреждающее сообщение: "warning С471 5: sum: значение возвращается не при всех путях выполнения ll . Чтобы избежать подобных неоднозначностей, следует в конце тела функции вставить оператор ret ur n со значением по умолчанию: int sum(int х, int у) if (х > 01 return х + У; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  34  1712.10 return о; Функция может возвращать указатель. В этом случае в объявлении и определении функции указывается соответствующий тип указ ателя. В качестве примера вернем указ атель на последний символ строки или нулевой указ атель, если строка пустая (листинr 8.27). I-тшст IПП 8.27. ВОЗВрtlТ :'r"К ;[IЗ;[Iтеля # include <iostream > #include <cstring> char *func(char *s); int ,"ain (1 char *р = О, str[] = rrstring rr ; р = func (strl ; if (р) { 11 Если не нулевой указатель std: : cout « *р « std:: endl; 11 9 else std:: cout « rrИULL rr « std:: endl; std: : cin. get (1 ; return о; char *func(char *5) int len = std::strlen(s); if (! len) return о; else return & s [len  1]; 11 Получаем длину строки 11 Нулевой указатель, если пусто 11 Указ а тель на по с лед ний симво Л { в языке С++ функции MOryт возвращать также ссылки. В этом случае допускается размещение функции как с правой, так и с левой стороны от оператора =. Чтобы функция возвращала ссылку необходимо в объявлении и определении после типа данных указать оператор &. В качестве при мера налише м функцию, которая позволяет получить или изменить значение элемента массива по указанному индексу (листинr 8.28). Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  35  1712.10 I .1IИСТIПП 8.28. Возврnт ссылки # include <iostream > int &at(int *а, int i); int ,"ain (1 int ан[] = {10, 20, 30{; at(arr, 01 = 800; for (int i=O; i<3; ++i) { std::cout «at(arr, i) « rr rr; { // 800 20 30 std::cout «std::endl; std: : cin. get (1 ; return о; int &at(int *а, int i) return а [i] ; 1>Т каз ;пелп на функцпп Фунщии также как и переменные имеют адрес, который можно сохр анить в указателе. В дальнейше м через указатель можно вызвать эту функцию. Кроме Toro, допускается передавать указ атель на функцию в качестве параметра друrой функции. Объявление указ ателя н а фун кц ию В ыrляд ит так: <ТJoШ> (*<название указателя» ( [<Типl> [, ..., <ТJoШМ>]]); Чтобы присвоить указателю адрес функции, необходимо указать название функции без параметров и круrлых скобок справа от оператора =. Тип параметров указателя и функции должен совпадать. Пример объявления указателя и присваивания адреса функции: int (*р) (int, int); р = S1..Шl; Вызвать функцию через указ атель можно двумя способами: х = (* р 1 (10, 201; / / Аналоrично х = sum (10, 201; у = р (30, 101; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  З6  1712.10 Пример объявления указателя, вызова функции чер ез указ атель и передачи указ ателя в к ачестве параметра функции приведен в листинrе 8.29. I .1IИСТIПП 8.29. УкnзnтеJШ lffi ф)",кЦlШ # inc 1 ude <ios t r е am> int sum(int х, int у); int func (int х, int у, int (*р) (int, int)); int main () int (*р) (int, int); 11 Объявление указателя на функцию р = sum; 11 Присваивание ацреса функции std: : cout « (*рl (10, 201 « std:: end1; / / 30 std::cout «р(ЗО, 101 «std::end1; //40 std::cout «func(5, 10, suml «std::end1; // 15 std: : cin. get (1 ; return о; int sum(int х, int у) return х + У; int func (int х, int у, int (*р) (int, int)) return (*р) (х, у); РеhЛНIIЯ Рекурсия  ЭТО возможность функции вызывать саму себя. При каждо м вызове функции создается новый набор локальных переменных. Рекурсию удобно использовать для пере бора объекта, имеющеrо заранее неизвестную структуру, или выполнения неопределенноrо количества операций. Типичным применением рекур сии является вычисление факториала числа (листинr 8. зо). Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  37  1712.10 I .1IИСТIПП 8.30. Вычисление фnк тор ию", #include <iostream> unsigned long long factorial(unsigned long n); int ,"ain (1 for (int i=3; i<11; ++i) std::cout «i« rr! = rr «factorial(i) «std::endl; std: : cin. get (1 ; return о; unsigned long long factorial(unsigned long n) if (n -С= 1) return 1; else return n * factorial(n  1); Резуль тат в ып ол н ен ия: 3' = 6 4' = 24 5' = 12 О 6' = 72 О 7' = 5040 8' = 4032 О 9' = 362880 10' = 3628800 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  2  1712.10 Объектноориеитированное проrpаммирование (ООП)  это способ орrанизации проrpаммы, ПОЗВОЛЯЮЩИЙ использовать один и тот же код MHoroкp атно. В отличие от функций ООП позволяет не только разделить проrpамму на фр асменты, но и описать предметы реальноrо мира в виде объектов, а также орrанизовать связи между ЭТ1lМИ объектами. Основные ПОНЯТIIЯ ОСНОВНЫМ "кирпичиком" ООП является класс. Класс включает набор переменных и функций для управления этими переменными. Переменные называют атрибутами (свойствами, перемеiiiiымu,леiiами или даiiiiымu,леiiами), а функции  методами (ипи фУiiiщuями'!Леiiами). В совокупности атрибуты и методы называются '!Леiiами класса. После создания кл асса ero название становится новым типом данных. Тем самым пользовательские классы расширяют возможности языка С++. На основе класса можно создать множество 06ъектов. При этом для каждоrо объекта создается свой набор локальных переменных. Например, при изучении строк мы рассматривали класс st r ing. При объявлении переменной название класса указывалось вместо типа данных: std::string strl(rrStringl rr ), str2(rrString2 rr ); В этом при мере определены два объекта st r 1 и st r2 , которые являются эк:зе:млярами кл асса st r ing. Каждый объект хранит ин формацию о своей строке, указанной при инициализации. IЬменение одноrо объекта не з атрarивает значение друrоrо объекта. Внутри каждоrо объекта, незаметно для нас, про изводятся операции по выделению, увеличению и освобождению объема памяти, необходимоrо для хранения строки. Тем самым при создании объ екта или ero изменении нам не нужно указывать конкретный объем па:мяти и следить за освобождением па:мяти. Чтобы иметь возможность манипулировать строкой клас с str ing предоставляет множество методов. Например, с помощью метод а si ze () мы получ али количество символов в строке. При вызове метода ero название указывается после названия объекта через точку: std::cout «strl.size() «std::endl; Помимо методов, класс s tr ing переrpужает некоторые операторы. Например, для конкатенации используется оператор +: strl = strl + str2; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  3  1712.10 Переrpузка операторов производится с помощью методов, имеющих специальные названия. Определив в классе Ilоператорныйll метод можно изменить поведение оператора по своему вкусу. Например, переrpузив оператор + можно вместо сложения ПрОН:ЗБОДИТЬ вычитание. Однако польз ователи класса врядли положительно оценят TaкJ'lO инициаТ1lВУ. Тем не менее в некоторых случаях изменение смы ела оператора ДОВОЛЬНО полезно. Например, класс cout переrpужает оператор по6итовоrо сдвиrа « ДЛЯ вывода данных в ОКНО консоли. ПрОБОДЯ аналоrию с реальным миром можно сказать, что телевизор является экз емпляром класса (объектом), а проект по котор ому создавался телевизор является кл ассом. По этому проекту можно создать множество телевизоров (множество экз емплятор класс а). Кнопки и разъемы на корпусе телевизора, да и сам корпус являются отдельными объектами соотвеТСТВYIOщеrо клас са. Сам процесс нажатия кнопки, ПрИБОДЯЩИЙ К включению или выключению телевизора, переключени:ю канала и Т. д. выполняется с помощью методов. Для сохранения текущеrо состояния кнопки, а также размеров кнопки, ее цвета и др. предназначены атрибуты. Одна и та же кн опка может выполнять разные действия. Например, одиночное нажатие кнопки выполняет одно действие, а уд ержание кнопки (переrpузка метода) в течении пяти секунд приводит к выполнению совершенно друrоrо действия. Вс е сод ержимое телевизора находится внутри корпуса и скрыто от rлаз. Чтобы пользоваться телевизором абсолютно не нужн о знать как он устроен внутри, достаточно иметь кнопки (интерф ейс доступа) и руководство пользователя (документация к кл ассу). Точно также разработчик класса может предоставить иитерф ейс доступа, а остальную часть кода защитить от изменения (сокрытие данных в ООП называется инкапсуляцией). В дальнейшем разработчик кл асса имеет возможность изменить внутреннюю реализацию клас са, при этом не изменяя интерфейс доступа. При необходимости пользователь может попытаться изменить класс. Это можно сравнить с попыткой снять заднюю КРЫIIЖу телевизора и попытаться чтото внутри сделать. Результат этоrо действия зависит от mалификации исполнителя. Если это мастер, то телевизор возможно будет лучше работать, но если любитель, то скоре е Bcero придется покупать новый телевизор. В один прекр асный момент разраб отчик телевизора решает выпустить новую модель, просто добавив внутрь корпуса DVDплеер. Большинство блоков внутри телевизора останутся от предыдущей модели. Основные изменения коснутся корпуса. Таким образом, телевизор с DVD плеером наследует конструкцию предыдущей модели, добавляет новую функциональность (DVD плеер) и переопределяет некоторые методы (изменяет корпус). Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  4  1712.10 в результате наследования в ПрОН'ЗБОДНОМ кл ассе может измениться поведение KaKoro либо метод а. Например, автобус и rусеничный трактор являются наследниками класса автомобиль, в котором определен метод, ОПИСЫВaIOЩИЙ способ движения. Совершенно очевидно, что движение автобус а отличается от движения rусеничноrо трактора. Поэтому клас с автобус может наследовать метод от класса автомобиль не переопределяя ero, а класс ryce ничный трактор должен переопределить метод. Во всех этих кл ассах теперь имеется доступ к одноименному методу, но реализация этоrо метода отличается. Тем не менее, этот метод выполняет одно и то же действие  движение транспортноrо средства. В ООП такое явление называется полиморфизмом Итак, мы познакомились с тре:мя основными понятиями ООП: -+ инкапсуляция  с окрытие данных внутри класса; -+ наследование  возможность создания ПрОН'ЗБОДНЫХ классов на основе 6азовоrо клас са. При ЭТОМ прОН'ЗБОДНЫЙ класс автоматически получает возможности базовоrо клас са и может добавить новую функциональность или переопределитъ некоторые методы; -+ полимор физм  смысл действия, которое выполняет одноименный метод, зависит от объекта, над которым это деЙС1Бие выполняется. Что же должно быть пред ставлено в виде классов, а что в виде методов или атрибутов? Если слово является существительным (автомобипь, телевизор, кнопка и т. д.), то оно может быть описано как класс. Метод описывает изменение объекта, например, автомобиль начал движение, непрерывно движется, остановился. Атрибут предназначен для сохранения текущеrо состояния объекта и ero характеристик, например, размер кнопки и ее цвет, признак нажата или нет. В заключение этоrо кpaTKoro обзора следует заметить, что именно поддержка ООП отличает язык С++ от языка С, который поддерживает только процедурный стиль проrpаммирования. В отличии от языков с# и Java, ООПстипь проrpаммирования в языке С++ не является обязатель ным стилем. В своих проrpаммах вы можете использовать только процедурный стиль. И в процедурном и в ООПстиле есть свои преимущества и недостатки. Какой стиль использовать зависит от конкретной ситуации. Но чем больше будет ваша проrpамма, тем более очевидными будут достоинства ООПстиля.   Ооъявленпе класса Класс объявляется с помощью ключевоrо слова class по слеДJ'lOщей схеме: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  5  1712.10 class [<Название класса>] <Объявления закрытых членов класса>; р uk1ic : <Объявления открытых членов класса>; pr ivate: <Объявления закрытых членов класса>; protected: <Объявления защищенных членов класса>; [<Объявления переменных через запятую>]; После ключевоrо слова с lass задается название класса, которое становится новым типом данных. Название класса ДОЛЖНО быть допустимым идентификатором, к которому предъявля::ются такие же требования как и к названиям переменных. Допустимо не задавать название клас са, если после закрывающей фиrурной скобки указано объявление переменной. Точка с запятой в конце объявления класса является 06яз ательной. Внутри фиrурных скобок располarаются объявления членов класса  атрибутов и методов. Перед объявлениями можно указ ать название спецификатора доступа: -+ public  открытый. Пдентификатор доступен для внешнеrо использования; -+ pr ivat е  закрытый. Пдентификатор доступен только внутри данноrо класса; -+ pr ot ее te d  защищенный. Пдентификатор недоступен для внешнеrо использования, НО доступен для данноrо кл асса и ДЛЯ пото:мков этоrо клас са. Обратите внимание Если специф ика то р ДО ступа не указан, то ид енти Ф ика т ар явля ет ся закрыrым. Спецификаторы доступа предназначены для контроля значения атрибутов класса, а также для запрещения использования методов, которые предназначены только для внутренней реализации класса. Например, если в атрибуте предполarается хранение определенных значений, то перед присвоением значения мы мож ем проверить соответствие зн ачения некоторому условию. Если же любой пользователь буд ет иметь возможность BBecТ1l что утодно, минуя нашу проверку, то ни о каком контроле не может быть и речи. Такая концепция сокрытия данных называется инкапсуляцией. Объявление класса только описывает новый тип данных, а не определяет переменнJ'lO, поэтому па:мять под нее не выделяется. Чтобы объявить переменнJ'lO, ее название указыв ается после заКРЫВaIOщей фиrурной скобки при объявлении класса или отдельно, используя название кл асса в каче стве типа данных: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  б  1712.10 <Название класса> <Название переменной>; Пример одновременноrо объявления класса с открытыми атрибутами и переменной: class Point р uk1ic : int Х; int У; point 1; Пример отдельноrо объявления переменной: Point point 2; Обратите внимание на наличие специ фикатора рм 1ic. Если этот спецификатор не указ ан, то получить до ступ к атрибутам х и у буд ет нельзя, так как по умолчанию члены кл асса являются закрытыми и доступны ТОЛЬКО внутри клас са. Действие спецификатора длится до следующеrо спецификатора или до закрывающей фиrурной скобки. В объявлении кл асса мож ет быть несколько одинаковых специ фикаторов. Пример : class Point р uk1ic : int Х; р uk1ic : int У; } point 1; Определения классов можно вкл адывать внутрь функции или друrоrо класс а при условии, что все методы имеют реализацию внутри класса. В этом случае класс виден только внутри функции. Пример: void func (1 class Point р uk1ic : int Х; int У; point; point.x = 10; point.y = 40; std::cout «point.x «std::endl; 11 10 std::cout «point.y «std::end1; //40 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  7  1712.10 Внутри одноrо класс а допускается использование объектов дрyrоrо класса. В качестве примера объявим класс Ро int (точка), а затем используем ero ДЛЯ описания координат п рямоуrольника внутри класса Rect (прямоyrольник) (листинr 9.1). I .1IИСТIПП 9.1. ПрИI>reр не IЮЛЪ ЗОВnНИЯ юте еов #include <iostream> class Point р uk1ic : int Х; int У; {; class Rect р uk1ic : Point top left; Point bottomright; {; int ,"ain (1 Rect rect; rect.top left.x = о; rect.top left.y = о; rect.bottomright.x = 100; rect.bottomright.y = 100; std::cout «rect.top left.x « rr rr «rect.top left.y «std::endl « rect.bottomright.x « rr rr «rect.bottomright.y «std::endl; std: : cin. get (1 ; return о;    Ооъявленпе атрпоутов Объявление атрибута внутри класса производится аналоrично объявлению обычной переменной, только перед типом данных нельзя указыв ль спецификатор хранения, а Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  8  1712.10 также производить инициализацию атрибута. Присвоить или получить значение атрибута через экземпляр класса можно с помощью точечной нотации: <Переменная>.<Название атрибута> = <Значение>; <Значение> = <Переменная>.<Название атрибута>; Пример: pointl. х 10; point1. У 40; std::cout «point1.x «std::end1; // 10 std::cout «point1.y «std::end1; //40 В языке С++ структуры имеют функционал, аналоrичный классам. Единственное отличие состоит в ТОМ, что доступ к членам структуры является открытым, а доступ к членам кл асса по умолчанию является закрЫТЫМ. И в ТОМ и друrом случае поведение по умолчанию можно изменить. Объявление структуры Point выrлядит так: struct Point { 11 Объявление структуры и переменной int Х; int У; point; Также как и в структур ах внутри класса допускается использование битовых полей. Битовые поля предоставляют доступ к отдельным битам, позволяя тем самым хр анить в ОДНОЙ переменной несколько значений, занимaIOЩИХ указанное количество бит. Объявление битовоrо поля имеет следующий фор мат <Тип данных> [<Название поля>]:<Длина в битах>; В одном кл ассе можно использовать одновременно битовые поля и обычные атрибуты. Обратите внимание на то, что название битовоrо поля можно не указывать, кроме Toro, если длина поля составляет один бит, то перед названием поля следует указать ключевое слово unsigne d. Пример объявления класса с битовыми полями: class Status { р uk1ic : unsigned :3; unsigned а: 1; unsigned Ь: 1; unsigned с: 1; status; Доступ к битовому полю осуществляется также как и к атрибуту кл асса: status. а = 1; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  9  1712.10 status.b = о; status . с = 1;   Ооъявленпе п определенпе I\Iетодов Объявление методов внутри класс а осуществляется также как и объявление обычной функции. Определение метода обычно размещают вне класса, указывая название класса перед названием метода. Между двумя названиями вставляется оператор При обращении к методам клас са используется следующий формат: <Экземпляр класса>.<Имя метода>([<Параметры>]) Определение метода можно разместить внутри объявления клас са. В этом случае содержимое метода вставляется в место вызова метода. Таки е методы Н3ЗЫВaIOТСЯ встраиваемыми. В страиваемыми имеет смысл делать все не60льшие методы. Пример о бъявления и определения методов приведен в листинrе 9.2. I .1IИСТIПП 9.2. ОбъявJPние И определеиrn reтOДOB #include <iostream> c1ass С { int х ; р uk1ic : void set х (int уl {х int get х (1 ; obj; 11 Закрытый атрибут = У;} 11 Определение Бстраиваемоrо метода 11 Объявление обычноrо метода int ,"ain (1 11 ИЗменение значения закрытоrо атрибута ok] . set х (101 ; 11 ПОлучение значения std: : cout « оЬ]. get х 11 « std:: end1; / / 10 std: : cin. get (1 ; return о; { lnt с:: get х 11 return х ; 11 Определение обычноrо метода Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  10  1712.10 в этом примере атрибут х является закрытым. Получить доступ к тако му атрибуту можно только внутри методов класс а. Обратиться к атрибуту напрямую через экз емпляр класса нельзя. Чтобы обозначить, что атрибут закрытый, последним символом названия является символ подчеркивания. Некоторые проrpаммисты в ЭТОМ случае указ ывают символ подчеркивания в самом начале названия атрибута. Для изменения и получения значения атрибута предназначены методы se t х (1 и get х (1 соответственно. Внутри метод а set  х () можно контролировать значение, присваиваемое закрытому атрибуту. Таким образом соблюдается принцип сокрытия данных, называемый инкапсуляцией. Метод set х (1 определен внутри класс а В этом случ ае метод является встраиваемым и ero содержимое вставляется в место вызова Объявление метода ge t х () нахОДИТСЯ внутри объявления класс а, а определение  вне объявления класса. В этом случае метод будет вызываться, а не встраиваться. Перед названием метода в определении указыв ается название кл асса и оператор : : (с: : get х (1) Методы se t х (1 и get х (1 содержат только одну инструкцию, поэтому на практике оба метода имеет смысл сд ел ать в стр аив ае мы ми. Как видно из примера, внутри методов обращение к атрибутам (даже к закрытым) происходит как к обычным локальным переменным. Обратиться к атрибутам явным образом можно через указатель this, который неявно передается в кажд ый метод. Доступ к атрибуту через указатель this осуществляется с помощью оператора >. Пример: void setx (int уl {this>x = у; { Определение метода можно записать подруrому: void setx (int у) { (*this).x = У; } В этом случае вместо оператора > используется точечная нотация. Крyrлые скобки являются обязательными, так как приоритеты операторов  > и точка одинаковые, но выполняются они справа налево, а не наоборот. Если ско бки убр ать, то вначале будет сделана попытка выполнить оператор точка, что приведет к ошибке. Некоторые методы MOryт получать в качестве параметра объекты дрyrоrо класса. Если ИСПОЛЬЗJ'lOтся только два клас са, то объявление одноrо класса до статочно вставить перед объявлением друrоrо класса. Однако при увеличении количества классов возникает ситуация, в результате которой приходится решать вопрос что было раньше курица или яйцо. Чтобы избежать такой ситуации в языке С++ предусмотрено непОЛiюе объявление l<Ласса, имеющее следующий формат с las s <Наз В9.ние класс а > ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 11  1712.10 Пример использования неполноrо объявления класса приведен в листинrе 9.3. I .1IИСТIПП 9.3. Неrю mюе объявление ютс сп # include <iostream > class А; 11 Неполное объявление. Если убрать, то будет ошибка c1ass В { Р uk1ic : int func(A &obj); 11 Объявление метода {; class А р uk1ic : int Х; А (int аl { х = а; / / Конструктор {; int B::func(A &objl return obj. Х; 11 Определение метода int ,"ain(1 { А a(201; В Ь; std::cout «b.func(al «std::end1; //20 std: : cin. get (1 ; return о; Конструкторы 11 деструктор Чтобы при создании экземпляра кл асса присвоить начальные значения какимли60 атрибутам, нео6ходи МО создать метод, имеющий такое же название как и название кл асса. Тип Бозвращаемоrо значения не указывается. Такой метод называется конструктором. Конструктор всеrда автоматически вызывается при создании объекта. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  12  1712.10 Конструктор может иметь переrруженные версии, ОТЛИЧaIOщиеся типом параметров или их количеством. Если внутри клас са нет конструктора, то автоматически создается конструктор без параметров. В этом случае объект объявляется так: <Название класса> <Название переменной>; или так: <Название класса> <Название переменной> = <Название класса>(); Если внутри клас са объявлен пользовательский конструктор, то кон структор по умолчанию не СО:ЗД ается. Это означает, что если вы создали конструктор с ОДНИМ параметром, то при создании объекта обязательно нужно будет указывать параметр. Чтобы иметь возможность созд ания объекта без указ ания параметров следует дополнительно создать кон структор без параметров. Объявление объекта с указанием параметров выrлядит следующим образом: <Название класса> <Название переменной> «Параметрl>[, ..., <ПараметрМ>]); Суще с твует такж е аль тер н атив ны й в ар и аит о бъявл е н ия о бъ екта: <Название класса> <Название переменной> = <Название класса> «Параметр 1> [, ..., <Параметр М>] ) ; Создание класса с несколькими конструктор ами и различные способы создания экземпляра класса показаны в листинrе 9.4. .1IИСТIПП 9.4. Сrюсобы СОЗДШlИя объектов и переrр),кn коистр)"кторов #include <iostream> c1ass С { int х , y; р uk1ic : С (1 { х с (int х 1 C(int х, { х int уl Х; у { х о; { = Х; y / / Конструктор 1 // Конструктор 2 / / Конструктор 3 о; у о; { у; { int get х (1 { return х . , {; int main () с obj 1; с obj 2 = С (1 ; с obj 3 (101 ; 11 Вызывае rк: я ко не трукто р 1 11 Вызывается конструктор 1 11 Вызывае rк: я ко НС трукто Р 2 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. с obj 4 = 20; С obj 5 = С (301 ; с obj 6(40, 301; с obj 7 = С (50, 51; //с okj8 (1; // СШибка std::cout «ob]l.get х(1 «std::end1; //0 std::cout «ob]2.get х(1 «std::end1; //0 std::cout «ob]3.get х(1 «std::end1; // 10 std::cout «ob]4.get х(1 «std::end1; //20 std::cout «ob]5.get х(1 «std::end1; //30 std::cout «ob]6.get х(1 «std::end1; //40 std::cout «ob]7.get х(1 «std::end1; //50 std: : cin. get (1 ; return о;  13  1712.10 // Вызывае rк: я ко не трукто р 2 // Вызывается :конструктор 2 // Вызывае rк: я ко не трукто р 3 // Вызывается :конструктор 3 Как видно из примера (см. создание объекта obj4), если конструктор принимает только один параметр, ТО становится возможным следующий способ создания экземпляр а кл асса: <Название класса> <Название переменной> = <Значение>; В этом случ ае производится неявное преобразование значения в объект класса. Чтобы предотвратить такое преобразование перед ко н структр ом, ПрИНИМaIOщим один п араметр, следует указать ключевое слово exp1icit (листинr 9.5). I .1IИСТIПП 9.5. Ключевое слово e"l'licit #include <iostream> c1ass С { int х , y; р uk1ic : exp1icit С (int хl {х = х; y = о; { int get х () { return х {; int ,"ain(1 { Cobj1(101; / / но рмаль но Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  14  1712.10 // с obj2 = 20; std::cout «obJ1.get х(1 std: : cin. get (1 ; return о; / / СШибка «std::end1; // 10 Суще с твует аль тер н ативн ы й с п о с о б пр исв аиван ия н ач аль н ых з н ач е н ий атр иб утам кл асса, который заключается в указании списка инициализации после двоеточия между списком парамеТРОБ и телом конструктора. Внутри списка инициализации указывается название атрибута после KOToporo внутри крyrл ых скобок задается значение. Пример и спользования списка ИНИЦaJIи:зации приведен в листинrе 9.6. l-тшстIПП' 9.6. ИспользовnIOre СПИСК;[I IППЩИ;[IJПfЗ;[Щ= # include <iostream > class С Р uk1ic : int а, Ь; с (int х, int yl: a(xl, ь (уl {{ / / Конструктор {; int ,"ain(1 { С obj (50, 201; std::cout «obj.a «std::endl; std: : cout « obj.b « std:: endl; std: : cin. get (1 ; return о; // 50 / / 20 Если конструктор вызывается при создании объекта, то перед уничтожением объ екта автоматически вызывается метод, называемый деструктором Внутри деструктора можно закр ыть ранее открытый файл, освободить динамически выделенную память и др. Название деструктора совпадает с названием клас са и конструктора, но перед названием добавляется знак тильда (). Тип возвращаемоrо значения не указывается. В кач естве при мера продемонстрируем последовательность вызова кон СТРУКТОРОБ И деструкторов при создании и удалении нескольких объектов (листинr 9.7). Чтобы увидеть результат выполнения проrp аммы следует нажать ко мбинацию кл авиш <Ctrl>+<FS> или запустить проrpамму из командной строки. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  15  1712.10 .1IИСТIПП 9.7. Порядок BЪnOBn констр)"кторов н дестр)",торов #include <iostream> c1ass С { int х ; р uk1ic : С (int хl // Конструктор х = Х; std::cout « rrC(int х) rr «х «std::endl; { c 11 std: : cout « rrC () / / Деструктор rr «х «std:: endl; { obj 1 (1), obj 2 (2); 11 Создание I"лобальных объектов int ,"ain(1 { Cobj3(31; std: : cout « 11 Со зд ание ло каль НОТ' о rrmain () rr « std:: endl; объекта return о; Резуль тат в ып ол н ен ия: С (int хl 1 с (int хl 2 с (int хl 3 ,"ain(1 c 11 3 c 11 2 c (1 1 Как видно из результата конструкторы rлобальных объектов (расположены после объявления класса) выполняется до передачи управления в функцию ,"ain (1 . Конструкторы локальных объектов вызываются в порядке объявления объ ектов внутри функции. Вызов деструкторов про изводится в обратном порядке. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  16  1712.10 Конструктор коппрованпя в случ ае присваивания одноrо объекта друrому при объявлении, а также при передаче объекта в качестве параметра в функцию и возврате объекта из функции вызывается особый конструктор  конструктор копирования. Если конструктор копирования не определен, то используется конструктор копирования по умолчанию. В этом случае создается побитовая копия объекта. Если внутри класса ПРОИЗВОДИТСЯ динамическое выделение памяш, то обязательно следует опред елить конструктор копирования явным образом, так как создание побитовой копии в этом случае недопустимо. Конструктор копирования имеет следующий фор мат <Название класса>(соnst <Название класса> &<Название объекта»; Назв анне конструктора копирования совпадает с названием класса. В качестве параметра метод принимает ссылку на копируемый объект. Тип возвращаемоrо значения не указывается. Проде монстрируем использование конструктора копирования н а при мере (листинr 9.8). I .1IИСТIПП 9Я. Коне тр)"ктор копнровn ння # include <iostream > c1ass С { int х , y; р uk1ic : С (int х, int У 1 { х С (const С & с 1 { = Х; у  = У; } 11 Сбычный :конструктор 11 Конструктор копирования х = с.х ; y = c.y int get х () return х ; {; void func 1 (С obj 1 { { / / neредача объекта через дараметр С func2 (int хl С obj (х, 401; return obj; 11 Возврат объекта из функции int ,"ain(1 { С obj1 (40, 301; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  17  1712.10 11 Вызывается :конструктор копирования 11 Вызывае rк: я ко не трукто р ко пир о вания 11 Вызывае rк: я ко не трукто р ко пир о вания 11 ко не трукто ры не :ЕЫзываюrк: я! ! ! 11 Требуется переrрузка оператора = 11 По умолчанию побитовая копия std: : cout « ok] 1. get х (1 « std:: end1; / / 60 std::cout «ob]2.get х(1 «std::end1; // 60 std: : cin. get (1 ; с obj 2 = okj 1; func1 (obj 11; okj 1 = func 2 (601 ; okj 2 = obj 1; return о; Обратите внимание на то, что при просто м присванвании объектов (вне объявления) конструктор копирования не вызывается. В этом случае нужн о переrpуж ать оператор присваивания. По умолчанию создается побитовая копия обь екта. Статпческпе атрпбуты п I\Iетоды Внутри кл асса можно создать атрибут или метод, которые будут доступны без создания экз емпляра клас са. Для этоrо перед объявлением атрибута или метода следует указать ключевое слово s tat ic. Статические члены класса существJ'lOТ в единственном экз емпляре, независимо ОТ количества созданных объектов. Создание статическоrо атрибута выполняется в несколько этапов. Вначале атрибут объявляется внутри кл асса, дале е в rло6альном пространстве ПРОИЗВОДИТСЯ определение, а затем в локальной области присваивается значение. Статический атрибут по умолчанию инициализируется нулевым значением. Обращение к статическо му атрибуту внутри класс а осуществляется такж е как к обычной переменной. Чтобы обратиться к статическому атрибуту вне класс а следует перед ero названием указ ать название класса и оператор ::. В качестве примера использования статичесЮIХ атрибутов про изведем подсчет количества созданных экземпляров класса (листинr 9.9). .тШСТIПП' 9.9. Подсчет количеСТВ;[I созД;[lIПlЬ1\': '}кзеllrlIlЛЯJlОВ КЛ;[lСС;[I #include <iostream> c1ass С { Р uk1ic : static int count; 11 Объявление статическоrо атрибута Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  18  1712.10 ++count; // Конструктор 11 Об р аще ние к а тр ибу'Т'У внутр и класс а с (1 { c 11 { count; / / Деструктор {; int C::count; 11 Опреление статическоrо атрибута void func (1 с obj 1; std::cout «C::count «std::endl; 113 int main () с: : count = о; 11 сб Р аще ние к атр ибу'Т'У вне клас с а с okj 1; std::cout «C::count «std::endl; 11 1 С obj2; std::cout «C::count «std::endl; 112 func (1; std::cout «C::count «std::endl; 112 std: : cin. get (1 ; return о; Обраще ни е к статическому методу внутри класса осуще ствляется также как к обычной функции. Чтобы обратиться к статическому методу вне класса следует перед ero названием указать название кл асса и оператор ... Кроме Toro, обратиться к статическо му методу можно через экземпляр класса. Обратите внимание на то, что статические методы не имеют доступа к нестатическим членам клас са, так как в них не передается указатель t his. Пример использования статических методов приведен в листинrе 9.10. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  19  1712.10 -ТШСТIПП' 9.10. ИспользовnIOre СТ;[IТических I'rIeТOДOB #include <iostream> class С Р uk1ic : static int suml(int х, int у) { 11 Статический метод return х + У; int sunQ(int х, int у) { 11 Обычный метод return suml(x, у); 11 Вызов статическоrо метода внутри класса {; int ,"ain (1 с obj; 11 Вызов статическоrо метода вне класса std: : cout « с:: suml (10, 20) « std:: endl; 11 Вызов обычноrо метода std::cout «obj.sum2(20, 51 «std::end1; //25 11 Вызов статическоrо метода через экземпляр класса std: : cout « okj. sum1 (зо, 101 « std:: end1; / / 40 std: : cin. get (1 ; / / 30 return о; Созданпе констант внутрп класса Создать константу внутри класса можно несколькими способами: -+ объявив СThшчес:кyIO КОН станту. Статическая КОН стаит существует в единственном эк:зе мпляре, поэтому ЭТО лучший спое 06. константе внутри класса допускается только char. Статические константы остальных определять вне класса; Присваивание значения статической для Т1Iпов int, 10 ng, shor t, Ьо 01 и Т1Iпов необходимо дополнительно Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  20  1712.10 -+ объявив обычную константу. Присвоить значение обычной константе допускается только в списке инициализации конструктор а. Список указывается после двоеточия между списком параметров и телом конструктор а. Пример : const int F; const double G; C(I: F(501, G(15.31 / / Конструктор Значение обычной константы может отличаться у разных эк:зе МПЛЯРОБ класса, если при инициализации указана переменная, которая передается в параметре конструктор а. Пример : const int F; const double G; 11 Может иметь разные значения C(int il: F (il, G(15.31 {{ // Конструктор Если значение константы ДОЛЖНО быть одинаковым ДЛЯ всех экземпляров класса, то вместо обычных констант следует использовать статические константы. Это позволит более экономично использовать па:мять и компилятор сможет произвести ОПТ1lмизацию проrpаммы; -+ объявив константу внутри анонимноrо перечисления. Таким способом можно создать только целочисленнJ'lO константу. Различные варианты СО:ЗД ания константы и способы доступа к ним вне класса показаны в листинrе 9.11. I .1IИСТIПП 9.11. Создnние KOHCTn нr ВН)'Р н ют ccn #include <iostream> class С Р uk1ic : 11 Только целочисленные значения внутри перечисления enum { А = 10 {; 11 Инициализировать внутри класса можно только статические 11 константы типа int, long, short, bool и char. static const int В = 2 о; static const int D; static const double Е; 11 Опр ед е ле ние вне клас с а 11 Определение вне класса Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  21  1712.10 11 Присваивание значения :константе в :конструкторе const int F; const double G; С (int il: F (il, G (15.31 {{ / / Конструктор {; const int C::D = 30; const double С::Е = 40.3; int ,"ain(1 { С obj (501 ; 11 Обратиться можно и без создания std: : cout « С::А « std:: endl; std::cout «obj.A «std::endl; std: : cout « С::В « std:: endl; std::cout «obj.B «std::endl; std: : cout « C::D « std:: endl; std::cout «obj.D «std::endl; std: : cout « С::Е « std:: endl; std::cout «obj.E «std::endl; 11 Обращение только через экземпляр std: : cout « obj. F « std:: endl; std::cout «obj.G «std::endl; С obj2 (701 ; std::cout «obj2.F «std::endl; std: : cin. get (1 ; return о; экземпляра класса // 10 // 10 // 20 // 20 // 30 // 30 // 40.3 // 40.3 // 50 // 15.3 // 70 Константные I\Iетоды Если внутри метода не ПРОИЗВОДИТСЯ изменение значений атрибутов, то ero можно объявить константным. Для этоrо после списка параметров указыв ается ключевое слово со ns t. Внутри KOHCTaHTHoro метода любая попытка изменить значение атрибута приведет к выводу сообщения об ошибке. Если при объявлении атрибута указано ключевое слово mutable, то внутри кон CTaиrHoro метода допускается изменение этоrо Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  22  1712.10 атрибута. Пример использования KOHCTaHTHoro метода и применение ключевоrо слова ," utable приведен в листинrе 9.12. I .1IИСТIПП 9.12. ко HCTnнr ные "TOДЫ # include <iostream > class С Р uk1ic : int а, Ь; mutable int т; C(int х, int у, int z) а = Х; Ь = У; m = z; / / ,"utak1e / / Конструктор void func 11 const { // а = 100; Ь = 100; m = 100; std: : cout «а «rr rr « Ь « rr rr « m « std:: endl; 11 Константный метод / / СШибка // Нормально {; int ,"ain(1 { С obj (50, 20, 81; obj.func (1; std: : cin. get (1 ; return о; // 50 20 100 Если атрибут может изменять СБое значение извне, то после списка парамеТРОБ указыв ается ключевое слово vo la tile. Это ключевое слово предоmращает проведение опти:мизации проrpаммы, при котором предполarается, что значение изменяется только в проrpамме. Ключевое слово vo la tile может быть указ ано как отд ельно, так и совместно с ключевым словом со ns t. Пример указ ания: void func () volatile; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  23  1712.10 Дружественные фУНКЦIIII 11 классы Можно создать функцию, которая не является членом класса, но внутри которой будет доступ ко всем членам клас са, в том числе к закрытым и защищенным. Такая функция называется дру:жествеююй. Чтобы объявить функцию дружественной следует разместить прототип функции, перед которым указано ключевое слово f r iend, внутри объявления класса. Одним из параметров дружественной функции должен быть экз емпляр класс а или ссылка на Hero, чтобы иметь возможность изменять значения атрибутов в переданном объ екте. Пример создания дружественной функции показан в листинrе 9.13. I .1IИСТIПП 9.13. Др)'Жественные ф)...к.ЦlШ #include <iostream> c1ass С { int х ; 11 Закрытый атрибут р uk1ic : exp1icit С (int хl {х = х; int get х () { return х 11 Объявление дружественной функции friend int func(C &obj, int х); {; 11 Дружественная функция int func (С &obj, int х) { оь J . Х += Х; 11 МОЖНО изме нить з наче ние закрыто I" о атрибута return оь]. х ; int ,"ain(1 { С obj (101 ; std::cout «fuпc(obj, 10) «std::endl; std::cout «obJ.get х() «std::endl; std: : cin. get (1 ; return о; / / 20 / / 20 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  24  1712.10 Сделать дрyrо м можно не только отдельную функц ию, но И метод какоrолибо класса. Если в одном клас се дружественных методов несколько, то вместо объявления отдельных методов допускается объявить сразу весь класс дружественным В этом случае все методы класса СЧИТaIOТСЯ друже ственными. Чтобы объявить класс дружественными следует разместить неполное объявление класса, перед которым у казано ключевое слово friend, внутри объявления дрyrоrо класса (листинr 9.14). I .1IИСТIПП 9.14. Др)'Жественные юmссы # include <iostream > c1ass А { pr ivate: int х , y; 11 з a:кpы'Iыe а трибу'Iы р uk1ic : А (int х, int уl {х = х; y = у; { friend class В; 11 Объявление дружественноrо класса {; c1ass В { Р uk1ic : int getx(A &objl int gety(A &objl return оЬ]. х ; return obj.y; {; int ,"ain(1 { А а(20, 501; В Ь; std::cout «b.get х(аl «std::end1; //20 std::cout «b.get у(аl «std::end1; //50 std: : cin. get (1 ; return о; l\IаССIIВЫ объектов Объявление массива объектов ничем не отличается от объявления массива зн ачений, имеющих элементарный тип. Отличие заключается в способе передачи парамеТРОБ и Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  25  1712.10 вызове конструктора. Если существует конструктор, который не принимает параметров, ТО массив объектов можно объявить так: <Название класса> <Название переменной>[<Количество объектов>]; Однако при отсутствии кон структора без параметров это объявление приведет к ошибке. В этом случае необходимо явно передать значения конструктору при объявлении массива объектов. Если конструктор принимает только один параметр, то при создании массива объектов можно передать список значений через запятJ'lO внутри объявлением конструктора стоит ключевое слово использовать уже нельзя. Пример создания массива и нициализации показан в листинrе 9.15. I .1IИСТIПП 9.15. ИющиюпI'З nцня mссивn объектов фиryp ных скобок Если перед ехр lici t, ТО этот способ объектов и указания списка #include <iostream> c1ass С { int х ; р uk1ic : С (int хl {х = х; { int get х () return х ; {; int ,"ain(1 { С obj[2] = 10, 20 {; std::cout «obJ[O].get х(1 «std::end1; // 10 std::cout «obJ[l].get х(1 «std::end1; //20 std: : cin. get (1 ; return о; Если конструктор принимает несколько параметров или перед конструктора, ПрИНИМaIOщеrо один параметр, указ ано ключевое слово необходимо применятъ полную форму инициализации (листинr 9.1б). объявлением explicit, ТО Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  26  1712.10 .1IИСТIПП 9.16. по ЛlffiЯ фор m ШllЩШIлmnЦlШ mссивn о бъеКТОБ #include <iostream> c1ass С { int х , y; р uk1ic : С (int х, int уl {х = Х; y = у; { int get х () { return х {; int ,"ain(1 { С obj[2] = { С(lО, 201, С(30, 401 {; std::cout «obJ[O].get х(1 «std::end1; // 10 std::cout «obJ[l].get х(1 «std::end1; //30 std: : cin. get (1 ; return о; Дпнаl\lIIческое созданпе объектов Для динамическоrо создания объектов в языке С++ предназначен оператор new. Оператор new выделяет объем памяти, необходимый для хранения объ екта, и возвращает ero адрес. Работать в дальнейшем с объектом можно с помощью указателя. Существуют три способа динамическоrо создания объекта: <Указатель> = new <Название класса>; <Указатель> = new <Название класса>«Значения для конструктора»; <Указатель> = new <Название класса> [<Количество объектов>]; в первом способе вызывается конструктор без параметров. Во втором способе внутри крyrл ых скобок можно передать значения кон структору класс а. Тр етий способ позволяет создать массив объектов. Обратите внимание на то, что в ЭТОМ случ ае нельзя передать значения конструктору, поэтому необходимо предусмотреть конструктор без параметров. Примеры: А *рА = new А; В *рВ = new B(201; С * рС = new С [2]; / / Способ 1 // Способ 2 / / Способ 3 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  27  1712.10 Чтобы обратиться к членам класс а с помощью указ ателя при использовании способов 1 и 2 следует вместо точечной нотации применятъ оператор  >. В третье способе необходимо внутри maдpaTHblX СКО бок указать индекс элемента, а затем с помощью точечной нотации обратиться к члену класс а. Примеры: pA>x = 100; // Для способов 1 и 2 рА[О].х = 100; // Для способа 3 Управление динамической па:мятью полностью лежит на плечах проrpаммиста, поэтому после завершения работы с па:мятью необходимо самим возвратить па:мять операционной системе с помощью оператора de let е. При уничтожении объекта вызывается деструктор кл асса. Если па:мять выделялась для массива объектов, то после оператора de 1e te следует указать кв адратные скобки. В этом случ ае вызываются деструкторы всех объектов. Примеры: delete <Указатель>; 11 Для способов 1 и 2 delete [] <Указатель>; 11 Для способа 3 Если па:мять не возвратить операционной системе, то УЧ асток памmи станет недоступным для дальнейшеrо использования. Подобные ситуации приводят к утечке па:мяти. Сделать эти уч асти опять доступными МОЖНО только после перезаrpузки КО мпьютера. После использования оператора delet е указатель попрежнему будет содержать прежний адре с. Поэтому указ атель принято обнулять. При выделении па:мяти может возникнуть ситуация нехватки па:мяти. В ранних версиях С++ в этом случае возвращался нулевой указатель. Соrласно новой версии стандарта в случае ошибки оператор new долж ен возбуждать исключение bad a110c (о бъект исключения определ ен в файле new). Обработать это исключение можно с помощью конструкции tr у. . . са t ch. Пример выделения памяти с обраб откой исключения: # inc 1 ude <new> 11 ... Фраrмент опущен ... А * рА = о; 11 Создаем указатель try { рА = new А; 11 выд е ляем пaм.qть catch (std:: bad  a110c енl 11 Обработка исключения Выдел ение памяти производится внутри блока try. Если при этом возникнет исключение Ь ad  a11oc, то управление будет передано в блок cat ch. После Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  28  1712.10 выполнения инструкций в блоке са tc h управление передается инструкции, расположенной сразу после блока. Иными словами, компилятор считает, что вы обработали исключение и можно продолжить выполнение проrpаммы. Следует уч итывать, что пользоваться указ ателем после обработки нельзя, поэтому внутри блока са tc h обычно ВЫВОДЯТ сообщение 06 оши 6ке и завершaIOТ выполнение проrpаммы. Если исключение не обработать, то проrpамма аварийно завершится. Если исключение не возникло, ТО инструкции внутри блока са tc h не выполняются. Обратите внимание на то, что объявление указателя про изводится вне блока try. Если объявление раз местить внутри блока, то область видимости переменной будет оrpаничена этим блоком. После выхода из блока переменная автоматически уничтожается, а выделенная память операционной системе не Бозращается. Поэтому, объявление указателя ДОЛЖНО нахОДИТЬСЯ перед блоком, а не внутри Hero. Различные способы выделения динамической па:мяти ПОД объект, варианты 06р ащения к членам кл асса, а также ПОРЯДОК вызова конструкторов и де структоров показаны в листинrе 9.17. I .1IИСТIПП 9.17. Дшmшческое со здшше объектов #include <iostream> # inc 1 ude <new> / / Для bad a110c class А Р uk1ic : int Х; А () { Х = о; std:: cout « rrA::A () rr « std:: endl; A 11 { std:: cout « "А:: A (1" « std:: end1; { {; class В р uk1ic : int У; в (int а) { у = а; std:: cout « rrB:: В () rr « std:: endl; B 11 { std: :cout « "В: :B (1" « std: :end1; { {; int ,"ain (1 А *рА = о; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  29  1712.10 в *рВ = о; try { рА = new А; { // Способ 1 catch (std:: bad  a110c енl std::cout « rrError rr «std::endl; return 1; pA>x = 100; std::cout «pA>x «std::end1; // 100 delete рА; рА = о; try { рВ = new B(201; { // Способ 2 catch (std:: bad  a110c енl std::cout « rrError rr «std::endl; return 1; std::cout «pB>y« std::end1; //20 delete рЕ; рВ = о; try { рА = new А [2]; { // Способ 3 catch (std:: bad  a110c енl std::cout « rrError rr «std::endl; return 1; { рА[О] . х = 100; рА[l] . х = 200; std::cout «рА[О].х «std::end1; // 100 std::cout «рА[l].х «std::end1; //200 delete [] рА; рА = о; return о; ,Т  . ЮlЗателп на ооъекты п члены класса Адр ес объекта можно сохранить в указател е. Объявление указателя на объект производится также как и на любой дрyrо й тип данных. Для получения адр еса объекта используется оператор &, а для доступа к членам вместо точки применяется оператор >. Пример использования указателя на объект приведен в листинrе 9.18. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  30  1712.10 -ТШСТIПП' 9.18. ИспользовnIOre :'r"К;[IЗnТeJIЯIffi объект #include <iostream> class Point р uk1ic : int х, У; void print (1 ; {; void Point:: print () { std:: cout « х « rr rr « у « std:: endl; int main () Point point; 11 Объявление объекта Point *р = &point; 11 Объявление указателя на объект int *рУ = &point.y; 11 Объявление указателя на атрибут p>x = 10; 11 дРступ к атрибуту через указатель на объект *рУ = 20; 11 Доступ к атрибуту через указатель на атрибут p>pr int О ; 11 Вызов метода через указатель на объект std: : cin. get (1 ; return о; Как видно из примера, сохранить в указател е можно не только адрес объ екта, но и адрес oткpblToro атрибута. Помимо указателей на объекты и открытые атрибуты язык С++ позволяет создавать указатели на Ч,лены класса. Указатель на член класс а хранит не адрес члена внутри объекта, а ero смещение внутри класса. Объявление указателя на член клас са выrлядит так: < Тип > < Название клас с а >: : * < Наз В9.ние указа те ля > ; После объявления необходимо присвоитъ указ ателю смещение определенноrо атрибута. Выполняется это следующим образом: <Название указателя> = &<Название класса>::<Название атрибута>; Объявление указ ателя на метод кл асса выrлядит так: <ТJoШ> ( <Наз вание клас с а>: : * <Наз вание указ а те ля» ([ <Тип 1 > [ , ... , <ТипЫ>]] 1; Присвоить указателю смещение метода внутри кл асса можно так: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  31  1712.10 <Название указателя> = &<Название класса>::<Название метода>; Для доступа к члену через объект используется оператор .*, а для доступа через указ атель применяется оператор  >*. Пример использования указ ателей на члены класса приведен в листинrе 9.19. l-тшстIПП' 9.19. Укnзnте.тш Iffi члены КЖlСС;[I #include <iostream> class Point р uk1ic : int х, У; void print (1 ; {; void Point:: print () { std:: cout « х « rr rr « у « std:: endl; int ,"ain (1 Point point; Point *р = &point; 11 Объявление объекта 11 Объявление указателя на объект int Point:: * рХ; рХ = &Point:: Х; point. *рХ = 10; 11 Объявление указателя на член 11 Получаем смещение атрибута х 11 Доступ к атрибуту через объект int Point:: *рУ; рУ = &Point:: У; p>*pY = 20; 11 Объявление указателя на член 11 Получаем смещение атрибута у 11 Доступ к атрибуту через указатель void (Point:: *funcl (1 ; func = &Point::print; (point. *funcl (1 ; (p>*funcl (1 ; 11 Об ъявле ние указ а те ля на функцИlO член 11 По лучаем смеще ние ме rroд а р r in t ( ) 11 Вызов метода через объект 11 Вызов метода через указатель std: : cin. get (1 ; return о; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  32  1712.10 Обратите внимание на круrлые скобки внутри которых раз мещается название объекта (или название указателя на объект) и указатель на метод. Эти скобки являются обяз ательными. Вторые крyrлы е ско бки используются для вызова метода. (point. * func) () ; 11 Эквивалентно point. pr int () ; (p>* func 1 (1 ; / / Эквивалентно р >pr int (1 ; Передача объектов в функцпю п возврат объектов Существует три способа передачи объекта в функцию: -+ передача копии. При этом способе изменение объекта внутри функции не затрarивает ИСХОДНЫЙ объект. Обратите внимание на то, что в этом случае вызывается кон структор копирования, а не обычный конструктор. Это важно учитывать, коrда внутри класса используется динамическое выделение па:мяти. Если конструктор копирования не определен, то выполняется побитовая копия обь екта. Следует учитывать, что передача копии объекта в 60ЛЬШИНС1Бе случаев является плохим решением, особенно если объект содержит MHoro данных; -+ передача указателя на объект. Для этоrо при вызове функц ии перед названием переменной указывается оператор & (взятие адре са), а в прототипе функции о бъявляетс я указ ател ь. В это м случ ае в функ Ц ию пер ед ается н е з н ач е н и е переменной, а ее адре с, поэтому внутри функции можно изменить исходный объект. Для доступа к членам объекта используется оператор >; -+ использ ование механизма ссылок Этот способ используется наиболее часто, так как внутри функции переменная является псевдонимом исходноrо объекта. Любые изменения псевдонима отражаются на исходном объекте. Если внутри функции объект не должен изменяться, то ero следует объявить константным. При использовании механизма ссылок перед названием переменной в объявлении и определении функции указывается оператор &, а при вызове  только название объекта. Для доступа к членам объекта используется оператор точка. В каче стве значения функц ия может возвращать объект. В этом случае созд ается временный объект, а коrда результат присваивается экземпляру класса выполняется копирование, при этом вызывается конструктор копирования, а не обычный конструктор. Это важно учитывать, коrда внутри класса используется динамическое выделение памяти. Пример передачи объектов в функцию и возврат объектов приведен в листинrе 9.20. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  33  1712.10 .1IИСТIПП 9.20. ПереД<l'ffi объектов в ф)"нкцию и возврnт объектов #include <iostream> class Point р uk1ic : int х, У; void pr int (1 Point (int а, { std:: cout int ы х = а; у = Ь; Point (Point &obj 1 х = obj. Х; у = obj. У; « х « rr rr « у « std:: endl; 11 Обычный конструктор 11 Конструктор копирования {; void funcl(Point obj) 11 Передача копии std::cout «obj.x « rr rr «obj.y «std::endl; void func2(Point *рl p>x = 4; p>y = 12; Point func3(POint &рl Point obj(p.x + 10, р.у + return obj; int main () Point point (10, 201; func 1 (point 1 ; func2 (&point 1; point. pr int () ; point = func3(pointl; 11 Передача указателя 11 Механизм ссылок 201 ; 11 Возврат объекта. Вызывается 11 конструктор копирования!!! 11 Объявление объекта 11 пе р ед ача ко пии. Вызывае rк: я 11 конструктор копирования!!! 11 Передача указателя. МоЖНО изменить 11 значение исходноrо объекта // 4 12 11 Механизм ССЫЛОК. МоЖНО изменить Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  34  1712.10 point. pr int () ; std: : cin. get (1 ; return о; 11 значение исходноrо объекта / / 14 32 Нас ледова ине Наследование  ЭТО возможность создания ПРОИЗВОДНЫХ кл ассов на основе 6азовоrо кл асса. При ЭТОМ ПРОИЗВОДНЫЙ класс автоматически получ ает возможности 6азовоrо кл асса и может добавить новую функциональность или переопред елить некоторые м етоды. Пример создания иерархии классов приведен в листинrе 9.21. I .1IИСТIПП 9.21. Наследование #include <iostream> class А 11 Базовый класс р uk1ic : void funcl () std: : cout « rrA:: funcl () rr « std:: endl; {; class В: public А { 11 Класс В наследует класс А р uk1ic : void func2 () std: : cout « rrB:: func2 () rr « std:: endl; {; class с: public В { 11 Класс С наследует классы А и В Р uk1ic : void func3 () { std:: cout « rrc:: func3 () rr « std:: endl; {; int main () с с; c.func1 (1; c.func2 (1; c.func3 (1; std: : cin. get (1 ; return о; 11 Со зд аем Э:К3 емпляр клас с а С / / А:: func 1 (1 / / В:: func2 (1 / / с:: func3 (1 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  35  1712.10 в этом примере вначале клас с В наследует все члены клас са А. Затем объявляется класс С, который наследует все члены и кл асса В и класса А. Каждый кл асс добавляет один новый метод. Таки м 06р азом экземпляр класса С имеет доступ ко всем методам клас сов А и в. Класс А называется базовым классом или суперклассом, а клас с В  ПРОИЗВОДНЫМ классом или подклас СОМ. В то же вре:мя класс В является базовым ДЛЯ кл асса с. При наследовании используется следующий формат объявления класса: class <производный класс>: [<Спецификатор доступа>] <Базовый класс> { <Объявления членов класса>; } [<Объявления переменных через запятую>]; В параметре <Спецификатор доступа> МОЖНО указать слеДJ'lOщие спецификаторы: -+ public  открытое клас са становятся ПрОИЗБодноrо класса; -+ pr ivat е  закрытое наследование. Все открытые и защищенные члены 6азовоrо клас са становятся закрытыми членами производноrо класса; наследование. Все открытые и с о отв етств ен н о откр ыты ми защищенные члены и защищенными базовоrо членами -+ pr ot ес te d  защищенное наследование. В се открытые и защище нные члены базовоrо класса становятся защище нными членами производноrо клас са. Обратите внимание 3акрыты е члены баз ов ос о клас са не наследую тс я. Если специ фикат ар до ступа н е указан, то использует ся закрьrr о е насле довзние. При использовании закрытоrо наследования можно изменить уровень доступа некоторых открытых и защищенных членов базовоrо класса. Сделать это можно дву:мя способами: <Б аз о ВЫЙ клас с >: : <Чле н клас с а> ; using <Базовый класс>::<Член класса>; Вариант с ключевым словом using является более предпочтительным. Эти объявления следует добавить в соответствующий раздел в объявлении производноrо класса. Пример изменения уровня доступа отдельных членов класса при закрытом наследовании показан в листинrе 9.22. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  36  1712.10 -Тшст IПП 9.22. ИЗl'rreнеmre :'r'JIОВНЯ ДОСТ:'r"ШI :при ЗnJql ЬПОl'rllffiСле ДОВtllПШ # include <iostream > class А Р uk1ic : void func 1 (1 void func2 (1 void func3 (1 std: : cout « rrA:: funcl () rr « std: : endl; std: : cout « rrA:: func2 () rr « std: : endl; std: : cout « rrA:: func3 () rr « std: : endl; {; class В: pr ivate А { Р uk1ic : А: : func 2; using А:: func3; void func4 (1 { func1 (1 ; 11 Закрытое наследование / / Orкрываем до с туп к f unc 2 11 11 Открываем доступ к func3() { {; int ,"ain (1 в obj; 11 obj.funcl(); 11 Ошибка. МеТОД funcl()  закрытый член класса! okj . func2 (1 ; / / А:: func2 (1 obj. func3 (1 ; / / А:: func3 (1 obj. func4 (1; / / А: :func1 (1. Вызов метода func 1 (1 из В:: func 4 (1 std: : cin. get (1 ; return о; При СО:ЗД ании экземпляра производноrо класса в случае иерархическоrо наследования вначале вызывается конструктор caMoro первоrо 6азовоrо клас са в цепочке наследования. Далее ВЫЗЫВaIOТСЯ последовательно конструкторы всех остальных базовых класс ОБ и ЛИШЬ затем вызывается конструктор производноrо класс а. Деструктор ы вызываются в обратном порядке. Для передачи параметров кон структорам базовых классов используется следующий синтакс ис: < Наз вание ко нс трукто р а пр о из вод но I" О клас с а > ( < Па раме тры » <Название конструктора базовоI"О класса> «Значения» 11 тело конструктора Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  37  1712.10 Значения конструктору базовоrо кл асса передаются через список инициализации, который ДОЛЖ ен располarаться после двоеточия между списком парамеТРОБ и телом конструктора. Внутри списка инициализации указывается название баз oBoro класс а после KOToporo внутри крyrлых скобок передаются значения. В качестве примера продемонстрируем порядок вызова конструкторов и деструкторов, а также передачу значений конструкторам базовых классов (листинr 9.23). .1IИСТIПП 9.23. Порядок BЪnOBn ко петр )",ТОРО в п деетр)"ктор ОВ #include <iostream> class А Р uk1ic : int Х; A(int аl // Конструктор х = а; std:: cout « rrA::A () rr « std:: endl; { A 11 { std:: cout « "А:: A (1" « std:: end1; { {; c1ass В: puk1ic А { Р uk1ic : int У; В (int а, int ы : А (ы У = а; std: :cout « rrB::B () rr « / / Конструктор std: : endl; { B 11 { std: :cout « "В: :B (1" « std: :end1; { {; c1ass с: puk1ic В { Р uk1ic : int z; С (int а, int Ь, int сl : В (Ь, сl { / / Конструктор z = а; std::cout « rrC::C()rr «std::endl; { c 11 { std: :cout « "с: :c (1" « std: :end1; { {; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  38  1712.10 int ,"ain(1 { С obj (10, 20, 301; std: :cout « rrA::x = rr « obj.x « rr В::у = rr « obj.y « rr C::z = rr «obj.z «std::endl; return о; Результат выполнения проrpаммы: А: :А(I В::В (1 с::с (1 А::х = 30 В::у с: :c (1 В: :B (1 А: :A (1 20 с:: z 10 l\Iножественное наследованпе ЯзЫК С++ поддерживает также множественное наследование. В этом случае используется следующий формат объявления производноrо клас са: class <производный класс>: [<Спецификатор доступа>] <Базовый классl>, [<Спецификатор доступа>] <Базовый класс2>, ..., [<Спецификатор доступа>] <Базовый классМ> <Объявления членов класса>; [<Объявления переменных через запятую>]; При :множественном наследовании вначале вызывается конструктор 6аЗОБоrо класса, название KOToporo расположено в списке слева. После этоrо вызывается КОН структор 6азовоrо кл асса, название KOToporo расположено в списке наследования правее и т.д. Список наследования просматривается слева направо. Лишь затем вызывается конструктор производноrо клас са. Деструкторы вызываются в обратном порядке. Для передачи параметров конструктор ам базовых классов используется следующий синтаксис: <Название конструктора производноrо класса> «Параметры» <Название конструктора базовоrо классаl>«Значения», Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  39  1712.10 <Название :конструктора баЗОБоrо класса2>«Значения», ..., <Название :конструктора баЗОБоrо классаМ> «Значения» 11 Тело :конструктора Значения конструкторам базовых классов передaIOТСЯ через список инициализации, внутри KOToporo указывaIOТСЯ названия баз овых клас СОВ через запятyIO после которых внутри круrлых скобок передаются значения. В качестве примера продемонстрируем ПОРЯДОК вызова кон СТРУКТОРОБ И деструкторов при множественном наследовании, а т акже передачу значений конструкторам базовых классов (листинr 9.24). I .1IИСТIПП 9.24. I\IlЮжествеНlЮе lffiСледовnние #include <iostream> class А Р uk1ic : int Х; A(int аl // Конструктор х = а; std:: cout « rrA::A () rr « std:: endl; { A О { std:: cout « rrA:: A () rr « std:: endl; void funcl () { std:: cout « rrA:: funcl () rr « std:: endl; {; class В р uk1ic : int У; в (int аl у = а; std::cout « / / Конструктор rrB::B()rr «std::endl; { B 11 void { std::cout « rrB::B()rr «std::endl; func2 () std: : cout « rrB:: func2 () rr « std:: endl; {; class с: public А, public В { 11 Класс С наследует классы А и В Р uk1ic : Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  40  1712.10 int z; С (int а, int Ь, int с 1 : А (bl, В (сl { / / neредаем значения z = а; std::cout « rrC::C()rr «std::endl; { c 11 { std: :cout « "с: :c (1" « std: :end1; { {; int ,"ain(1 { С obj (10, 20, 301; obj.func1 (1; obj.func2 (1; std: :cout « rrA::x = rr « obj.x « rr В::у = rr « obj.y « rr C::z = rr «obj.z «std::endl; return о; Результат выполнения проrpаммы: А: :А(I В::В (1 с::с (1 А: :func1 (1 В: :func2 (1 А::х = 20 В::у = 30 с:: z = 10 с: :c (1 В: :B (1 А: :A (1 Если прОН'ЗБОДНЫЙ класс наследует несколько классов, которые в свою очередь наследJ'lOТ ОДИН и тот же базовый класс, то возникает неодно'Значность, так как один и тот же член 6азовоrо кл асса 6уд ет присутствовать в нескольких классах. Рассмотрим эту ситуацию на примере (листинr 9.25). -Тшст IПП' 9.25. Нео ,1J;НOЗIffi ЧНОСТЬ :при I'rnю:лсествеШЮI'rI нnслеДОВtllПШ # include <iostream > class А Р uk1ic : Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 41  1712.10 void funcl () { std:: cout « rrA:: funcl () rr « std:: endl; } {; c1ass В : puk1ic А { Р uk1ic : void func2 () { std:: cout « rrB:: func2 () rr « std:: endl; } {; c1ass С : puk1ic А { Р uk1ic : void func3 () { std:: cout « rrc:: func3 () rr « std:: endl; {; class D : public В, public С { 11 Класс D наследует классы В и С р uk1ic : {; int ,"ain (1 D obj; / / okj . func 1 (1 ; okj . В : : func 111 ; okj . С : : func 111 ; okj . func 2 (1 ; okj . func 3 (1 ; std: : cin. get (1 ; return о; // Неоднозначность. из в или из С? // Берем из класса В // Берем из класса С // Qц но з начно // Qц но з начно { в этом примере клас сы В и С являются наследниками кл асса А, в котором объявлен метод func 1 (1. Класс D наследует клас сы В и С. Таки м образом метод f unc 1 (1 суще ству ет в двух экз е мпляр ах. Е ел и СО:ЗД ать экз е мпляр кл ас с а D и поп ытать ся обратиться к методу, то компилятор выведет сообщение об оши бке. Од им из способов разрешения неоднозначности является явное указ анне клас са и оператора :: перед названием метода при вызове: obj . В : : func 1 () ; 11 Берем из класса В obj . С : : func 1 () ; 11 Берем из класса С Нужны ли два одинаковых метода? Скорее Bcero нет. Чтобы метод был только в единственном эк:зе мпляре следует объявить клас сы В и С вuртуалЫiЫМU. Для этоrо в списке наследования перед спецификатором до ступа необходимо указать ключевое слово virtual. Пример : Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  42  1712.10 class В : virtual public А { Р uk1ic : void func2 (1 std: : cout « rrB:: func2 () rr « std:: endl; } {; class С : virtual public А { Р uk1ic : void func3 (1 std: : cout « rrc:: func3 () rr « std:: endl; } {; в этом случае никакой неоднозначности не будет, поэтому можно вызвать метод без явноrо указ ания 6азовоrо класса: D obj; obj.func1 (1; 1>Т каз ;пеЛII на объекты "РОIIЗВОДНЫХ классов Указатель, имеющий тип баз OBoro класса, может ссылаться на объект лю60rо производноrо кл асса. Следует помнить, что такой указатель имеет доступ только к наследуе мым членам базовоrо класса и виртуальным методам. Чтобы получить доступ к членам производноrо класса нужно выполнить приведение типов (листинr 9.2б). Кроме Toro, при использовании адресной арифметики необходимо учитывать, что указ атель буд ет перемещен на размер базовоrо кл асса, а не производноrо. Это может привести к ошибке. -ТШСТIПП' 9.26. Укnзnте.тш Iffi объекты :проIfзвод:ны:{ КЛ;[IССОВ #include <iostream> class А Р uk1ic : void А: :func1 (1 ; {; c1ass В : puk1ic А { Р uk1ic : void В: :func2 (1 ; {; void А: :funcl () { std:: cout « rrA:: funcl () rr « std:: endl; } Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  43  1712.10 void В: :func2 () { std:: cout « rrB:: func2 () rr « std:: endl; } int ,"ain (1 А *рА; В Ь; РА = &Ь; pA>func1 (1 ; / / pAAunc2 (1 ; ((В *1 рА! >func2 (1 ; std: : cin. get (1 ; return о; 11 .Адрес производноrо класса / / А:: func 1 (1 11 Ошибка. нужно ВЫПОЛНИТЬ приведение типов / / В:: func2 (1 Впртуальные I\Iетоды Если и:мя метод а в ПРОИЗВОДНОМ кл ассе совпадает с метод о м из 6азовоrо класса, то будет использоваться метод из производноrо класса. В этом случ ае Т1IП и количество параметров у методов должны совпадать, в противном случае производится переrpузка метода, а не переопределение. Чтобы вызвать метод 6азовоrо класса из метод а производноrо класса, следует указать перед метод ом название 6азовоrо класс а и о ператор: :. Рассмотрим переопределение методов на примере (листинr 9.27). I .1IИСТIПП 9.27. Переопр еделенrn reтOДOB #include <iostream> class А Р uk1ic : void func (1 ; {; c1ass В : puk1ic А { Р uk1ic : void func (1 ; {; void А: :func () std: : cout « rrA:: func () rr « std:: endl; } void В: :func (1 std::cout « rrB::func()rr «std::endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 44  1712.10 11 A::func(); 11 Вызов MeTqдa из баЗОБоrо класса int ,"ain (1 в obj; obj.func (1; std: : cin. get (1 ; return о; / / В: :func (1 { в этом примере в классах А и В объявлен метод f unc ( 1. Класс В наследует класс А. Следовательно метод из класса В переопределяет одноименный метод из класса А. Поэтому при создании объекта класса в будет вызван метод именно из производноrо кл ас с а. Таки м о бр аз о м Д о стиrа ется с тати, ес кuй полимор физм. Язык С++ поддерживает также динaмu,ескuй полиморфизм, при котором выбор вызываемоrо метода зависит от объекта, на который ссылается указ атель, имеющий Т1IП 6азовоrо класса. В этом случае используется позднее связывание, которое означает, что выбор метода осуще ствляется в процес се выполнения проrpаммы, а не на этапе ко мпиляции. Чтобы при использовании указателя (имеющеrо тип базовоrо класса) ССЫЛaIOщеrося на объект производноrо класса был вызван одноименный метод из производноrо клас са, необходимо объявить метод в базовом кл ассе виртуальным. Для этоrо перед объявлением метода следует добавить ключевое слово virt ual. При наследовании дублировать ключевое слово virt ual в ПРОИЗВОДНЫХ кл ассах не нужно, так как виртуальные свойства метода автоматически передaIOТСЯ всем производным классам. Виртуальный метод не обязательно замещать в производном кл ассе. Если виртуальный метод не замещен, то используется метод базовоrо кл асса. Нельзя объявлять виртуальными статические методы, дружественные функции, а также конструкторы. Деструктор класса можно сделать виртуальным. Таким образом, любой метод, который может быть замещен в производном классе, следует объявить виртуальным, хотя увлекаться этим не стоит, так как при использовании виртуальных методов уменьшается эффективность работы проrpаммы. Переделаем код из листинrа 9.27 и сделаем метод func (1 в базовом классе виртуальным (листинr 9.28). Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  45  1712.10 I .1IИСТIПП 9.28. ВИРТ)"ЮIЫIЫe reтoды #include <iostream> c1ass А { Р uk1ic : virtual void func(); 11 Виртуальный метод {; c1ass В : puk1ic А { Р uk1ic : void func (1 ; {; void А: :func (1 void В: :func (1 std: : cout « rrA:: func () rr « std:: endl; std::cout « rrB::func()rr «std::endl; void test (А &obj 1 { obj. func (1; { int ,"ain (1 А *рА, а; В Ь; РА = &а; pA>func (1 ; рА = &Ь; pA>func (1 ; test (аl ; test (ы ; std: : cin. get (1 ; return о; 11 Адрес баЗОБоrо класса / / А:: func (1 11 Адрес производноrо класса // В: :func (1 / / А: :func (1 / / В: :func (1 { В этом примере дополнительно определена функция te st (1, которая в кач естве параметра принимает ссылку на объект базовоrо класса. Передать в функцию можно объект базовоrо класса, а также объект любоrо производноrо класса. Выбор вызываемоrо внутри функции метода зависит от типа переданноrо объекта. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  46  1712.10 Дпнаl\lIIческое определенпе ТIша объекта Для динамическоrо определения типа объекта, на который ссылается указатель, предназначен оператор typeid. Результат выполнения для полиморфных и неполиморф ных объектов отличается. Прежде чем использовать оператор, необходимо подключить файл typeinfo. Оператор имеет следующий фор мат <3 I'G емпляр клас с а typ е ln fo > = t ур eld (<об ъе к т или ТJoШ»; в кач естве значения оператор type ld возвращает экземпляр класс а t уре in fo. Этот экз емпляр можно сравнить с дрyrим экземпляром Toro же клас са, используя операторы == (равно) и ,= (не равно). Получить название типа объекта позволяет метод na,"e (1 . П ример использования оператора typeid приведен в листинrе 9.29. I .1IИСТIПП 9.29. Дшmшческое определение тШffi объектn #include <iostream> #include <typeinfo> c1ass А { Р uk1ic : virtual void func(); 11 Виртуальный метод {; c1ass В : puk1ic А { Р uk1ic : void func (1 ; {; void А: :func (1 void В: :func (1 std: : cout « rrA:: func () rr « std:: endl; std::cout « rrB::func()rr «std::endl; int ,"ain (1 А *рА, а; В Ь; рА = &а; std: : cout рА = &Ь; std: : cout « typeid(*pAI.name(1 « std: : endl; // class А « typeid(*pAI.name(1 « std: : endl; // class В Листинrи на странице http://unicross.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 47  1712.10 if (typeid(*pAI == typeid(BII std: : cout « rrclass B rr « std:: endl; / / c1ass В std: : cin. get (1 ; return о; Оператор (1)1Н1Шic cast Оператор dynamlc с as t выполняет приведение типов указател ей или ссылок Применяется для приведения полимор фных типов. Если приведение указателя окончилось неуд ачей, оператор возвращает нулевой указ атель, а если проблема со ссылкой, то rенерируется исключение bad с as t (объект исключения объявлен в файле (ур einf о). Фор мат о пер атор а: dynamlc cast< <Тип результата> > «Выражение» Как вы уже :знаете, указ атель, имеющий тип 6азовоrо клас са, может ссылаться на объект лю60rо производноrо класс а. Однако, если указ атель имеет тип производноrо кл асса, то с охранить в нем адрес, объекта 6азовоrо типа, нельзя. Различные способы п риведения и пример проверки корректности приведения показаны в листинrе 9.30. I .1IИСТIПП 9.30. Опер nTop (1)"IШlflic  СП" t #include <iostream> c1ass А { Р uk1ic : virtual void func(); 11 Виртуальный метод {; c1ass В : puk1ic А { Р uk1ic : void func (1 ; {; void А: :func (1 void В: :func (1 std: : cout « rrA:: func () rr « std:: endl; std::cout « rrB::func()rr «std::endl; int ,"ain (1 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  48  1712.10 А *рА, а' , В *рВ, Ь' , рА = dynamlc cast<A *> (&al; // ОК рА = dynamlc cast<A *> (&bl; // ОК рВ = dynamlc cast<B *> (&al; // Error рВ = dynamlc cast<B *> (&bl; // ОК рА = &а; // ОК рВ = dynamlc cast<B *> (pAI; // Error рА = &Ь; // ОК рВ = dynamlc cast<B *> (pAI; // ОК // рВ = &а; // Error рВ = &Ь; // ОК рА = dynamlc cast<A *> (pBI; // ОК if (рАI // Пример проверки std: : cout « rrOK rr « std: : endl; pAAunc (1 ; // В: :func (1 else std::cout « rrError rr «std::endl; std: : cin. get (1 ; return о; Абстрактные I\Iетоды 11 классы А6страктные методы содерж ат только объявление метода без реализации. Предп олarается, что ПРОИЗВОДНЫЙ класс должен переопред елить метод и реализовать ero функциональность. В языке С++ абстрактные методы реализуются с помощью ,исто виртуальных методов. Синтаксис объявления абстрактноrо метода: virtual <Тип результата> <Название метода>([<Тип> <Название параметраl> [, ..., <Тип> <Название параметраМ>]]) = о; Если внутри класса существует хотя бы один а6стр актный метод, то весь класс является абстрактным. Создать экзе мпляр абстрактноrо класса нельзя. Пример объявления и замещения абстрактноrо метода приведен в листинrе 9.31. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  49  1712.10 I .1IИСТIПП 9.31. Абе тpn ктные reтоды и ютее ы #include <iostream> c1ass А { Р uk1ic : virtual void func() = о; 11 Абстрактный метод {; c1ass В : puk1ic А { Р uk1ic : void func (1 ; 11 Замещаем метод {; void В: :func () { std:: cout « rrB:: func () rr « std:: endl; } int main () // А а; 11 Создать объект абстрактноrо класса нельзя! в Ь; b.func(l; // B::func(1 std: : cin. get (1 ; return о; Шаблонные (обобщенные) классы в языке С++ помимо шаблонных функций можно применятъ шаблонные классы, реализующие одинаковый алrоритм работы, но использующие разные типы данных, которые указывaIOТСЯ при создании объекта. Компилятор на основе ша6л OHHoro класс а автоматически создаст переrруженные версии в зависимости ОТ имеющихся способов создания обь ектов в проrpамме. Описывается шаблонный клас с по слеДJ'lOщей схе ме: te:mplate<class Тип 1 [, ..., class ТипN] > class Название класса 11 Тело класса {; После ключевоrо слова templat е внутри уrловых скобок через запятyIO указЫВaIOТСЯ обобщенные названия ТИПОВ. ЭТИ названия используются ДЛЯ описания типов, которые Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  50  1712.10 Moryт использоваться внутри клас са. При компиляции обобщенные типы будут заменены реальными типами данных. Перед названием обобще HHoro типа Moryт быть указ аны ключевые слова class или type пате, которые 060значaIOТ ОДНО и то же. Внутри объявления ша6лонноrо класс а не нужно использовать ключевое слово temp la te для объявления ша6лонноrо метода, так как методы ша6лонноrо класса автоматически становятся шаблонными. Однако перед определением ша6л OHHoro метода вне класса необходимо указать ключевое слово t emplat е с такими же типами, что и в объявлении ша6лонноrо класса. Схема определения ша6лонноrо метода вне объявления класса выrлядит так: te:mplate<class Тип 1 [, ..., class ТипN] > Типрезультата Название класса<Типl[, ..., ТипN]>::Названиеметода( [Тип Название параметраl[, ..., Тип Название параметраN]]) 11 Тело меrroда Для создания экземпляра ша6лонноrо клас са используется следJ'lOЩИЙ синтаксис: Название переменной; Название переменной(Значениеl [, """, Значение М] ) ; Обратите внимание на то, что при создании объекта внутри уrловых ско бок указыв аются реальные типы данных, а не обобщенны е. В качестве примера создадим шаблонный клас с и объявим несколько объектов с разными типами данных Названиекласса<Типl[, Название класса<Типl[, """, ТИпN] > ТИпN] > """, (листинr 9.32). I .1IИСТIПП 9.32. шnблоIolые юmссы #include <iostream> template<class Туреl, class Туре2> c1ass С { Туре 1 х Туре2 y; р uk1ic : С (Туре1 х, Туре2 yl; void print (1 ; Туре1 sum( 1 ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  51  1712.10 {; int ,"ain (1 C<int, int> а (10, 20); a.print (); std: : cout « rrsurn = rr « а. S1..Шl () «std:: endl; C<douk1e, int> Ь (54.6, 631; b.print (1; std: : cout « rrsurn = rr « Ь. S1..Шl () «std:: endl; C<douk1e, douk1e> с (14.8, 47.81; c.print (); std: : cout « rrsurn = rr « с. S1..Шl () «std:: endl; std: : cin. get (1 ; return о; template<class Туреl, class Туре2> С<Туре1, Туре2>:: С (Туре1 х, Туре2 уl Х = Х; y = У; template<class Туреl, class Туре2> void С<Туре 1, Туре2 >: : pr int (1 { std: : cout «rr x = rr «х «rr y = rr « y « std:: endl; template<class Туреl, class Туре2> Туре1 С<Туре1, Type2>::sum(1 return х + y; Шаблонные классы MOryт иметь переrруженные версии, в которых тип данных указыв ается явным образом. Объявление явной специализации выrлядит так: te:mplate -о- class Названиекласса<Типl[, ..., ТипN]> { 11 Тело класса {; Например, в предыдуще м примере, если объект создать следующим образом: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  52  1712.10 C<int, douk1e> а (10, 12.51; то буд ет выведено предупреждающее сообщение об усечении значения, так как внутри метода su," (1 результат сложения будет иметь тип double, а возвращаемый результат должен иметь Т1IП in t. Чтобы этоrо избежать можно реализовать ЯВНJ'lO специализацию д ля этой последовательности типов (листинr 9.33). I .1IИСТIПП 9.33. ЯвlffiЯ СIreЦИЮПrзnцня КJmccn # include <iostream > template<class Туреl, class Туре2> c1ass С { Туре1 Х ; Туре2 y; р uk1ic : С (Туре1 Х, Туре2 уl {Х = Х; y = у; { Туре1 sum( 1 { return Х + y; { {; te:mplate<> class c<int, doUble> { int х ; double y; р uk1ic : С (int х, douk1e уl {х = Х; y = у; { double S1..Шl () { return х + y; {; int ,"ain (1 c<int, douk1e> а (10, 12.51; std: : cout « rrsurn = rr « а. S1..Шl () «std:: endl; C<douk1e, int> Ь (12.5, 101; std: : cout « rrsurn = rr « Ь. S1..Шl () «std:: endl; std: : cin. get (1 ; return о; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  53  1712.10 Обобщенные и реальные типы можно смешивать в объявлении ша6лонноrо класса (листинr 9.34). Если в объявлении шаблонноrо класса указан реальный тип и название переменной, ТО эта переменная внутри класса является константой. При объявлении объекта этой константе необходимо передать конкретное значение. Реальный тип может быть целочисленным (int, long, short, Ьооl и char). Использовать веще ственные типы данных нельзя. I .1IИСТIПП 9.34. СrellIИВnние обобщенных иреnлъных ТШIов #include <iostream> template<class Туре, int у> class С Туре Х ; Р uk1ic : exp1icit С (Туре хl {х = х; void pr int (1 std::cout «rr x = rr «х «rr у = rr «у« std::endl; {; int ,"ain (1 C<int, 20> а (101 ; a.print (); C<douk1e, 50> Ь (54.61 ; b.print (1; std: : cin. get (1 ; return о; в объявлении ша6лонноrо класса допускается указывать значения по умолчанию после оператора  для конкретизации типа или значения константы. Если при создании объекта тип или значение не указ аны, то будут использоваться значения по умолчанию (листинr 9.35). Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  54  1712.10 -Тшст IПП' 9.35. ЗнnчеlШЯ по :'r'1'rIO..l'PffiIШЮ В объяв.J'l?!mш lШI блоlПЮ ro КЖI ccn #include <iostream> template<class Type=int, int у=100> class С Туре Х ; Р uk1ic : exp1icit С (Туре хl {х = х; void pr int (1 std::cout «rr x = rr «х «rr у = rr «у« std::endl; {; int ,"ain(1 { С<> a(lOl; 11 Эквивалентно C<int, 100> а(10); a.print (); C<douk1e> Ь(12.51; // Эквивалентно C<douk1e, 100> Ь(12.51; ь .print (1; C<doUble, 5> с(2.4); 11 Конкретные значения c.print(); std: : cin. get (1 ; return о; Шаблонные классы можно наследовать, как и обычные клас сы. При использовании указ ателей важно ПОМНИТЬ, что указатель на объект ОДНОЙ специализации нельзя присвоить указ ателю у KOToporo специализация отличается. Иными словами, указателю на объект типа в <int > нельзя присвоитъ адр ес объекта типа B<double >. Пример наследования шаблонных классов показан в листинrе 9.36. I .1IИСТIПП 9.36. На следов ание шаблонных класс ов # include <iostream > template<class Туре> class А { Р uk1ic : Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  55  1712.10 Туре Х ; А (Туре аl { х = а; { virtual void func(); {; 11 Клас с В нас ледуе т класс А temp1ate<c1ass Туре> c1ass В puk1ic А<Туре> { р uk1ic : Туре у; В (Туре а, Туре ы А<Туре> (ы { У = а; { void func (1 ; {; template<class Туре> void А<Туре>:: func (1 template<class Туре> void В<Туре>:: func (1 std: : cout « rrA:: func () rr « std: : endl; std: : cout « rrB: :func () rr « std: : endl; int ,"ain (1 A<int> *рА, а (30) ; B<int> Ь(lО, 201; B<douk1e> с (10.5, 20.31; рА = &а; pAAunc (1 ; рА = &Ь; pAAunc (1 ; std::cout «typeid(*pAI .name(1 «std::end1; std::cout «typeid(cl .name(1 «std::end1; std: : cin. get (1 ; return о; // А: :func (1 // В: :func (1 // B<int> // B<douk1e> Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  2  1712.10 После создания класса ero название становится новым типом данных. Тем самым пользовательски е классы расширяют возможности языка С++. С помощью переrpузки операторов можно еще больше расширить возможности объектов, так как переrpузка операторов позволяет экз емплярам кл ассов участвовать в обычных выражениях. Например, переrpузив оператор + можно сложить объект с дрyrи м объектом или JПOбым элементарным типом данных. Способы переrружп операторов Переrpузка операторов производится с помощью методов, имеющих специальные названия. Определив в классе Ilоператорныйll метод можно изменить поведение оператора по своему вкусу. Например, переrpузив оператор + можно вместо сложения ПрОН:ЗБОДИТЬ вычитание. Однако польз ователи класса врядли положительно оценят TaкJ'lO инициаТ1lВУ. Тем не менее в некоторых случаях изменение смы ела оператора ДОВОЛЬНО полезно. Например, класс cout переrpужает оператор по6итовоrо сдвиrа « ДЛЯ вывода данных в ОКНО консоли. 11 О пер атор н ый 11 мето Д и ме ет ел едJ'!O щи й Ф ор ма т: <Тип результата> ореrаtоr<Название оператора> ( [<Тип> <Название параметраl>[, """, <Тип> <Название параметраМ>]]) 11 Тело меrroда Название Ilоператорноrоll метода состоит из слова Iloperator", после KOToporo указыв ается переrружаемый оператор, например, оре ra to r+, оре ra to r= и т. д. Внутри круr-л ых скобок указ ывается тип, объект KOToporo может быть расположен в выражении справа от переrpужаемоrо оператора. Следовательно для кажд oro типа, с которым может взаимодействовать экземпляр класс а внутри выражения, необходимо создать отдельный Ilоператорныйll метод. Например, чтобы сложить объект с целым числом следует создать метод о ре ra to r + (in t х), а для сложения с вещественным числом  метод ор er at or + (double х 1. Внутри метода доступен указ атель t his на объект, который расположен слева от оператора. Таким образом, внутри метода можно напрямую обращаться к атрибутам и методам класса. Пример переrpузки оператора + для сложения объ екта с целым числом и возвратом HOBoro объекта: с с:: operator + (int х) 11 Объект класса С + целое число С nev.:ob j ; 11 Со зд аем вр еме нный об ъе к т Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  3  1712.10 пewobJ.x = Х + Х; re t ur n nev.:ob j ; 11 х  закрытый член класса С 11 Возвращаем временный объект Метод будет вызван в следующей ситуации: obj2 = obj1 + 20; / / с obj1, obj2; Однако, если будет следующая ситуация, то метод вызван не будет, так как объект должен быть расположен слева от оператора, а не справа: obj 2 = 20 + obj 1; 11 Меrroд с:: operator + (int х) не вызывается! Переrpузить оператор + в этом случае позволяют дружественные функции. Параметры дружественной функции передаются явным образом. Объект, расположенный слева от оператора, доступ ен через первый параметр, а объект, расположенный справа от оператора, доступен через второй параметр. Объявление дружественной функции внутри объявления класс а выrлядит так: friend С operator+(int х, С &obj); При мер определения дружественной функции вне класса: с operator + (int х, С &obj) С newobj; newobJ . х = оЬ]. х + Х; re t ur n nev.:ob j ; 11 Целое число + обкт класса С 11 Сбращение к х через параметр с помощью друже ственной функции можно также заме нить Ilоператорныйll метод. Тем не менее, стоит отдать предпочтение Ilоператорным" методам, а друже ственные функции применятъ в случаях, коrда обойтись методом нельзя. В каче стве примера переrpузим оператор + ДЛЯ сложения объекта с целым числом: С operator + (С & obj, int х) 11 Обкт класса С + целое число С newobj; newobJ.x = obJ.x + Х; return newobj; При переrpузке операторов следует учитывать, что: -+ с помощью друже ственных функций нельзя переrpузить операторы =, (1,  > и []. Д 11 11 ля переrpузки этих операторов нужно использовать операторные методы; -+ вообще нельзя переrpузить операторы . (точка), ::,?: и . *; -+ н ельзя из мен ить пр и ор итет о п ер атор ов; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  4  1712.10 -+ нельзя изменить количеС1БО парамеТРОБ в IlonepaTopHOMl1 методе или дружественной Ilоператорнойll функции; -+ нельзя использовать значения по умолч анию в параметрах. Исключ ением является переrpузка оператора (1 ; -+ нельзя добавить новые операторы. Переrружа БШlарных операторов При использовании бинарных операторов в выраж ении участвуют два операнда. Примеры бинарных операторов: + (плюс),  (минус), * (умножение), / (деление), % (остаток от деления), & (двоичное И), 1 (двоичное ИШI), л (двоичное исключающее ИЛП), « (сдвиr влево), » (сдвиr вправо) и оператор "запятая". К бинарным операторам такж е относятся операторы сравнения: == (равно), , = (неравно), < (меньше), > (больше), <= (меньше или равно), >= (больше или равно), && (лоrическое и) и 11 (лоrиче ское ИШI). При переrpузке бинарных операторов через единственный параметр в операторном методе доступен операнд, расположенный от оператора справа, а указ атель на сам объект, расположенный от оператора слева, передается неявным образом. Таким образом внутри метода ко всем членам класса можно обращаться напря:мyIO или через указ атель this. Дружественной функции передаются два параметра. Через первый параметр доступен операнд, располож енный от оператора слева, а через второй параметр доступен операнд, расположенный от оператора справа. Тип возвращаемоrо значения, а также внутренняя реализация зависит от предпочтений проrpаммиста. Обратите внимание на то, что в обычных выражениях при использовании бинарных операторов возвращается новое значение, а значения операндов внутри выражения не изменяются. Хотя это не правило, а лишь реко мендация. В кач естве при мера п ереrpузим операторы + и == (листинr 10.1). I .1IИСТIПП 10.1. Переrp),кn бшmрных оперnторов # inelude <iostream > c1ass С { int х ; р uk1ic : С (1 {х = о; 11 ко не ТРУКТО Р по умо лчанию Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  5  1712.10 exp1icit С (int хl {х = х; { с (const С & с) {х = с. х ; l1lt get х (1 { return x; { с operator+(const С &obj); 11 с operator+(int х); 11 fr iend С operator+ (int х, const С &obj); 11 bool operator==(const С &obj); 11 bool operator== (int х); 11 friend bool operator==(int х, const С &obj); 11 // // Обычный конструктор Конструктор копирования {; int ,"ain(1 { С obj1 (101, obj2 (201, obj3; obj3 = obj1 + obj2; std::cout «ob]3.get х(1 «std::end1; obj3 = obj3 + 50; std::cout «ob]3.get х(1 «std::end1; obj2 = 20 + obj3; std::cout «ob]2.get х(1 «std::end1; std::cout « (obj1 == obj21 «std::end1; std::cout « (obj1 == 101 «std::end1; std::cout « (100 == obj21 «std::end1; std: : cin. get (1 ; return о; obj 1 + obj2 obj + целое число целое число + obj obj 1 == obj2 obj == целое число целое число == obj / / 30 / / 80 // 100 // о // 1 // 1 // obj1 + obj2 с C::operator+(const С &obj) С nev.:ob j ; newobJ.x = х + obJ.x ; r е tur n nev.:ob j ; 11 obj + целое число с C::operator+(int х) С nev.:ob j ; newobJ.x = Х + Х; r е tur n nev.:ob j ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  б  1712.10 с operator+(int х, const С &obj) С nev.:ob j ; newobJ.x = obJ.x + Х; r е tur n nev.:ob j ; 11 целое число + obj bool C::operator==(const С &obj) return (х == obJ.x ); // obj1 obj2 bool C::operator==(int х) return (х == х); // obj це ло е число bool operator==(int х, const С &obj) return (х == obJ.x ); 11 целое число obj Переrружа унарных операторов При использовании унарных операторов в выражении уч аствует только один операнд  сам объект. Примеры унарных операторов: + (унарный плюс),  (унарный минус), * (разыменование), & (взятие адреса),  (двоичная инверсия) и ' (лоrическое отрицание). При переrpузке унарных операторов Ilоператорныйll метод не принимает парамеТРОБ. Внутри метода ко всем членам объекта можно обращаться напрямую или через указ атель t his. Дружественной функции передается один параметр  объект класса. В качестве примера переrpузим унарный минус с помощью IlonepaTopHorol1 метода, а о ператор , с помощью друж ественной функции (листинr 10.2). I .1IИСТIПП 10.2. Переrp ),Kn )'ШIp ных оперnт орОБ # include <iostream > c1ass С { int х ; р uk1ic : С (1 {х = о; { exp1icit С (int хl {х = х; { с (const С & с 1 {х = с. Х ; { 11 ко не трукто р по ума лчанию 11 Обычный :конструктор 11 Конструктор копирования Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  7  1712.10 l1lt get х (1 { return x; { с operator(); friend bool operator! (const С &obj); // obj // 'obj {; int ,"ain(1 { С obj1 (101, obj2; obj2 = obj 1; std::cout «obJ2.get х(1 «std::end1; // 10 std: : cout « (' okj 11 «std:: end1; / / о std: : cin. get (1 ; return о; с с:: operator (1 с nev.:ob j ; nev.:obJ.x = x ; r е tur n nev.:ob j ; // obj bool operator! (const С &obj) return I (оь]. х ); // 'obj Переrружа операторов IIHKpel\IeHTa 11 декремента Операторы инкремента (++) и декремента () такж е являются унарными операторами, но они изменяют сам объект. Кроме Toro, операторы MOryт использоваться в постфиксной или префиксной формах. При постфиксной форме (х++) возвращается значение переменной перед операцией, а при префиксной форме (++х)  вначале производится операция и только потом возвращается значение. Прототипы IlonepaTopHblX" методов: <Название класса> &operator++(); <Название класса> &operator(); <Название класса> operator++ (int) ; <Название класса > operator  (int) ; Прототипы дружественных функций: // ++obj // obj // okj++ / / okj Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  8  1712.10 friend <Название класса> &ореrаtоr++«Название класса> &); 11 ++Obj friend <Название класса> &ореrаtоr«Название класса> &); 11 Obj friend <Название класса> ореrаtоr++«Название класса> &, int); 11 obj++ fr iend <Название класса> operator  «Название класса> &, int); 11 obj  Целочи сленный параметр, используемый в прототипах при постфиксной форме, можно проиrнорировать. По умолчанию этот параметр имеет зн ачение о. Пример переrpузки оператора инкремента приведен в листинrе 10.3. .1IИСТIПП 10.3. Переrp ),Kn оперnт opn ШlКреrelПn # include <iostream > c1ass С { int х ; р uk1ic : С 11 {х = о; { exp1icit С (int хl {х = х; { с (const С & с) {х = с. х ; l1lt get х (1 { return x; С &operator++(); С operator++(int х); 11 Конструктор по умолчанию 11 Обычный :конструктор 11 Конструктор копирования / / ++okj // obj++ {; int ,"ain(1 { С obj1(101, obj2; obj2 = ++okj 1; std: : cout « obJ1.get х (1 « std: : endl; // 11 std: : cout « obJ2.get х (1 « std: : endl; // 11 obj2 = objl++; std: : cout « obJ1.get х (1 « std: : endl; // 12 std: : cout « obJ2.get х (1 « std: : endl; // 11 ++okj2 ; std: : cout « obJ1.get х (1 « std: : endl; // 12 std: : cout « obJ2.get х (1 « std: : endl; // 12 std: : cin. get (1 ; return о; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  9  1712.10 с &C::operator++() ++X; return *this; / / ++okj с C::operator++(int х) С tmp = *this; ++*this; return tmp; // obj++ Переrружа операторов прпсвапванпя Переrpузка оператора = и сокращенных операторов присваивания (например, += = *=, /= и др.) осуществляется также как и переrpузка бинарных операторов. lлавное отличие заключается в ТОМ, что операторы присваивания изменяют сам объект, а не БОЗВращmoт новый. При использовании IlonepaTopHblxl1 методов ссылка на объект, расположенный слева от оператора присваивания, передается неявным образом, а объект, расположенный справа от оператора, доступен через параметр. Друж ественной функции передаются два параметра. Через первый параметр доступен объект, расположенный от оператора слева, а через второй параметр доступен объект, расположенный от оператора справа. В качестве результата обычно возвращается указ атель на ИСХОДНЫЙ объект. При переrpузке оператора = следует учитывать: -+ е ел и о п ер атор н е пер erp уж е н, то авто матич е ски с О:ЗД ается о п ер атор пр ив аив ания по умолчанию, который создает по6итовJ'lO копию объекта. Это важно учитывать, если внутри класса производится динамическо е выделение па:мяти; -+ при использовании оператора присваивания при инициализации объекта вызывается конструктор копирования, а не переrpуженная версия оператора =; -+ переrpузить оператор = с помощью дружественной функции нельзя. Пример переrpузки операторов присваивания приведен в листинrе 10.4. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  10  1712.10 .1IИСТIПП 10.4. Переrp),кn оперnТорОВ присвnивnния #include <iostream> c1ass С { int х ; р uk1ic : С (1 { х  = о; { exp1icit С (int хl {х = х; { С (const С &с) {х = с. X; l1lt get х () { return х ; С &operator=(C &obj); с &operator=(int х); С &operator+=(int х); 11 ко не трукто р по ума лчанИIO 11 Обычный :конструктор 11 Конструктор копирования // obj2 = obj1 / / obj = целое число 11 obj += целое число {; int ,"ain (1 с objl, obj2; okj1 = 10; okj2 = okj 1; obj1 = obj1; okj2 -1'= 20; std: : cout « ok] 1. get х (1 « std:: end1; std::cout «ob]2.get х(1 «std::end1; 11 Множественное присваивание obj2 = obj1 = 5; std: : cout « ok] 1. get х (1 « std:: end1; / / 5 std::cout «ob]2.get х(1 «std::end1; //5 11 Вызывается конструктор копирования, 11 а не меrroд С &operator= (С &obj) ! ! ! С okj3 = okj 1; std::cout «ob]3.get х(1 «std::end1; //5 std: : cin. get (1 ; return о; // okj = целое // okj2 = okj 1 // obj = obj // okj -1'= целое // 10 // 30 число число Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 11  1712.10 С &C::operator=(C &objl if (this == &obj) return *this; х = оЬ]. х ; return *this; с &C::operator=(int х) х = Х; return *this; с &C::operator+=(int х) х += Х; return *this; Переrружа оператора () // obj2 = obj1 // Случай obj = obj / / obj = целое число 11 obj += целое число Переrpузка оператора (1 позволяет обработать вызов экз емпляра класса как вызов Ф К 11 11 УНКЦИИ. оличеС1БО парамеТРОБ и тип Бозвращаемоrо значения в операторном методе MOryт быть произвольны:ми. Внутри метода ко всем членам объекта можно обращать ся напрямую или через указатель this. Обратите внимание на то, что переrpузить оператор (1 с помощью дружественной функц ии нельзя. Пример п ереrpузки оператора (1 приведен в листинrе 10. s. I .1IИСТIПП 10.5. Переrp ),Kn оперnт opn О # include <iostream > c1ass С { int х ; р uk1ic : С (1 {х = о; { exp1icit С (int хl {х = х; { l1lt get х (1 { return х ; { void operator (1 (int хl {х = х; int operator() () { return х {; 11 ко не трукто р по ума лчанию 11 Обычный :конструктор Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  12  1712.10 int ,"ain (1 с obj; obj (101 ; std::cout «obj(1 «std::end1; std::cout « (20 + obj(11 «std::end1; std: : cin. get (1 ; return о; // 10 / / 30 Переrружа оператора [ ] Переrpузка оператора [] позволяет обработать доступ к элементу по индексу, причем индекс может быть не только целочисленным. При переrpузке оператора [] через единственный параметр в IlonepaTopHOM" методе доступен индекс, расположенный внутри кв адратных скобок Внутри метода ко всем членам кл асса можно обращать ся напрямую ипи через указатель this. Чтобы можно быпо присвоить значение элементу, расположенному по указанному индексу, необходимо внутри метод а возвратить ссылку на элемент. Обратите внимание на то, что переrpуз ить оператор [] с помощью дружественной функции нельзя. Пример переrpузки оператора [] приведен в листинrе 10. б. I .1IИСТIПП 10.6. Переrp ),Kn оперnт opn [] #include <iostream> #inc1ude <cstd1ik> c1ass С { static const int size = 2; int arr[size ]; р uk1ic : С (1 { ап[О] = о; ап[1] = о; { С (int х, int уl { ап[О] = х; ап [1] = у; { int &operator [] (int i); {; int &с:: operator [] (int il { if (i < О 11 i :::= size ) { 11 Проверка :ЕЫхода за rраницы массива Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  13  1712.10 std: : cout « rrError rr « std:: endl; std: : exit (11 ; return arr  [i] ; int ,"ain(1 { С objl, obj2 (30, 401 ; obj1[0] = 10; obj1[1] = 20; std: : cout « obj1 [О] « std:: end1; / / 10 std: : cout « (obj 1 [1] + obj2 [О] 1 «std:: end1; / / 50 std: : cin. get (1 ; return о; Переrружа оператора доступа к члену класса Переrpузка оператора  > существляется также как и переrpузка унарных операторов. В качестве значения Ilоператорныйll метод должен возвращать указатель this. Обратите внимание на то, что переrрузить оператор > с помощью дружественной функции н ельзя. Пример переrpузки оператора > приведен в листинrе 10.7. I .1IИСТIПП 10.7. Переrp ),Kn оперnт opn  > # include <iostream > c1ass С { int х ; р uk1ic : int У; с (int а, int Ь) {х = а; у = Ь; С * operator > () { return this; } {; int ,"ain(1 { С obj (30, 401; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  14  1712.10 11 obJ>x 10; 11 Ошибка. х  закрытый член класса Obj>y = 20; 11 ОК. у  открытый член класса std::cout «obj>y« std::end1; //20 std: : cin. get (1 ; return о; Переrружа операторов не,,, 11 (Ielete Операторы new И delet е, предназначенные для дина:мическоrо управления памятью, также можно переrpузить. Допускается переrpужать все форматы операторов. Наиболее часто переrpужаются следующие форматы операторов: <Указатель> = new <Название класса>«Начальное значение»; delete <Указатель>; <Указатель> = new <Название класса>[<Количество элементов>]; delete [] <Указатель>; Чтобы переrрузить эти форматы операторов необходимо создать "опер аторные " методы, имеющие следующие прототипы: void *operator new(slze t count); void operator delete(void *object); void *operator new[] (slze t count); void operator delete[] (void *object); Внутри методов new И new [] для выделения памяти обычно используется функция ,"a11oc (1 , а внутри методов de 1e te и de1et е [] для освобождения памяти  функция fr ее () Количество байтов, необходимых ДЛЯ хранения одноrо или нескольких объектов, доступно через параметр со un t. При неудачном выделении памяти функция ,"a11oc (1 вернет нулевой указ атель. В этом случае внутри методов new И new [] следует сrенерировать исключение, являющее объектом класса bad a110 с (опред ел ен в файле new). lенерация исключения выrлядит так: std: : bad alloc err; 11 Создаем объект искточения throw err; 11 rенерируем исключение При использовании следующих фор матов операторов необходимо не rенерировать исключение, а возвращать нул евой указатель: <Указатель> <Указатель> new (std::nothrow) <Название класса>«Начальное значение»; new (std: :nothrow) <Название класса>[<Количество элементов>]; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  15  1712.10 Чтобы переrрузить эти форматы операторов необходимо создать "опер аторные " методы, имеющие следующие прототипы: void *operator new(slze t count, const std::nothrowt &); void operator delete(void *object, const std::nothrowt &); void *operator new[] (slze t count, const std::nothrowt &); void operator delete[] (void *object, const std::nothrowt &); Обратите внимание на то, что в этом случае при переrpузке операторов de1et е и de le te [] необходимо указ ать во втором параметре const st d: : not hrow t &. Параметр по throw t внутри методов можно проиrнорировать Дополнительно следует переrpузить обычные операторы de1et е и de 1e te [] с одним параметром. Пример переrpузки операторов new [] И de 1et е [] С обр аботкой ошибок, а также последовательность вызова IlonepaTopHblxl1 методов, конструкторов и деструкторов кл асса показ аны в листинrе 10.8. .1IИСТIПП 10Я. Переrp ),Kn оперnт орОБ """'[] и ,lele ос. [] #include <iostream> #inc1ude <cstd1ik> # inc 1 ude <new> c1ass С { int х ; р uk1ic : С () {х = о; std:: cout « rrc О rr « std:: endl; c О { std:: cout « rrc () rr « std:: endl; void setx (int х) {х = Х; int getx () { return х ; } void *operator new[] (slze t count); void operator delete[] (void *р); {; void * С: : operator new[] (slze t count) std: : cout « rr new [] rr « std:: endl; void *р = std::malloc(count); 11 Выделяем память if (!р) 11 Проверяем на корректность std: : bad alloc err; 11 Создаем обкт исключения Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  16  1712.10 throw err; 11 re не р ируем ис к.тпоче ние return р; 11 Возвращаем указатель void C::operator delete[] (void *рl std::cout « rrde!ete[]rr «std::endl; std::free(p); 11 Освобождаем память int ,"ain (1 с *obj = о; try { okj = new С[2]; 11 Обрабатываем исключение 11 Выделяем память дЛЯ ДВУХ объектов catch (std:: bad  a110c енl std::cout « rrError rr «std::endl; std:: exit (11; 11 ВЫХОДИМ при ошибке { okJ[O].set x(101; // Пользуемся памятью okJ[l].set x(201; std::cout «obJ[O].get х(1 «std::end1; std::cout «obJ[l].get х(1 «std::end1; delete [] obj; 11 Освобождаем пaм.qть Obj = о; 11 Обнуляем указатель std: : cin. get (1 ; return о; Резуль тат в ып ол н ен ия: new[] С (1 С (1 10 20 C (1 C (1 delete [] Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  17  1712.10 Как видно из результата, при успешн ОМ выделении па:мяти автомашчески ВЫЗЫВaIOТСЯ конструкторы. При вызове оператора de 1et е [] вначале вызываются деструкторы всех объектов, а затем управление передается переrpуженному методу о per at о r de 1et е [] (1 . Не забывайте о том, что если для выделения памяти используется оператор new [] , то при освобождении памяти следует вызывать оператор de1et е [ ] , а не de1et е. И, наоборот, если ДЛЯ выделения па:мяти используется оператор new, ТО при освобождении памяти следует вызывать оператор de1e t е, а не de 1e te [] . Вме СТО std:: по t hr ow внутри круr-л ых скобок при вызове операторов new И new [] можно указать несколько значений через запятyIO: <Указатель> new «Значения» <Название класса>«Начальное значение»; <Указатель> new «Значения» <Название класса>[<Количество элементов>]; Чтобы переrрузить эти форматы операторов необходимо создать "опер аторные " методы, имеющие следующие прототипы: void *operator new(slze t count, <Тип> <Параметрl> [, ..., <Тип> <Параметр N>] ) ; void operator delete(void *object, <Тип> <Параметрl> [, ..., <Тип> <Параметр N>] ) ; void *operator new[] (slze t count, <Тип> <Параметрl> [, ..., <Тип> <Параметр N>] ) ; void operator delete[] (void *object, <Тип> <Параметрl> [, ..., <Тип> <Параметр N>] ) ; Тип и количество дополнительных параметров может быть произвольным. Обратите внимание на то, что операторы выделения па:мяти и операторы освобождения памяш ОТЛИЧaIOтся только первым параметром. Помимо этих методов дополнительно следует создать переrpуж енные версии методов для обычных операторов de 1e te и de 1et е [] С одним параметром. Например, если определены следующие методы: void *operator new(slze t count, int х, doUble у); void operator delete(void *object); void operator delete(void *object, int х, doUble у); то выделить и освободить па:мять можно так: С *obj = new (10, 25.81 с; / / Выделяем память / / ... delete obj; 11 Освобождаем память Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  18  1712.10 Значения 1 О и 25.8 , указанные внутри крyrлых скобок при выделении памяти, будут доступны в метод е о per at or new ( ) через параметры int х и doub le у соответственно. Если внутри класса переrpужены операторы new И delet е, ТО при выделении и освобождении па:мяти ПОД объекты этоrо класса будут вызываться Ilоператорныеll методы этоrо кл асса. При выделении па:мяти ПОД дрyrи е объекты ВЫЗЫВaIOТСЯ их переrpуженные операторы или rлобальные операторы при отсутствии переrpуженных версий. Чтобы отказ аться от переrpуженных операторов и обратиться к rлобальному оператору следует написать так: С * obj = :: new с; 11 Сбращение к I"лобальному оператору new / / ... : : delete obj; 11 Сбращение к I"лобальному оператору delete В этом примере перед ключ евыми словами new И dele te расположен оператор разрешения области видимости ::, поэтому вместо переrpуж енных версий будут вызваны rло6альные операторы new И dele te. Переrpужать операторы new И de le te допускается не только для отдельноrо класса, НО и rло6аль но ДЛЯ всех объектов, включая встроенные типы данных. Для этоrо следует создать rло6альные "операторные" функции без привязки к конкретному классу. В этом случае стандартные операторы иrнорируются и вызываются переrруженные версии. Если в какомлибо кл ассе операторы new И dele t е переrpужены, то ВЫЗЫВaIOТся именно переrpуженные версии, а не rлоб альные. Переrрузка операторов' 11' в языке С++ операторы « и » переrpужены для вывода и ввода данных соответственно. Что бы объекты пользовательскоrо класса имели возможность взамодействовать с потоками ввода!вывода следует переrpузить эш операторы с помощью дружественных функций. Использовать в этом случае Ilоператорныеll методы нельзя. Переrрузка оператора « осуществляется следующим образом: std::ostream &operator«(std::ostream &stream, <Класс> &obj) 11 ВЫВОДИМ данные в поток используя переменную stream return stream; 11 Возвращаем ССЫЛКУ на поток Переrpузка оператора » выrлядит так: std::istream &operator»(std::istream &stream, <Класс> &obj) Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  19  1712.10 11 ВВОдИМ данные из потока используя переменнyIO stream return stream; 11 Возвращаем ссылку на ПОТОК { в качестве параметров функции принимают ссылку на соответствующий поток и ссылку на объект. Внутри функции необходимо вернуть ссылку на поток, чтобы иметь возможность составлять цепочки из вызовов операторов. Пример переrpузки операторов « и» показан в листинrе 10.9. I .1IИСТIПП 10.9. Переrp),кn оперnТорОВ .. <: и>... #include <iostream> c1ass С { int х ; р uk1ic : int У; С (int а, int Ь 1 {х = а; у = Ь; { friend std::ostream &operator«(std::ostream &stream, С &obj); friend std::istream &operator»(std::istream &stream, С &obj); {; std: : ostream stream « &operator«(std::ostream &stream, rrClass С {х rr « оЬ]. х «rr, у С &obj 1 " « obj. У « rr } rr; return stream; 11 Во з вращаем ссылку на по ТО к std::istream &operator»(std::istream &stream, С &obj) std: : cout « rry = rr; stream » obj. У; return stream; 11 Во з вращаем ссылку на по ТО к int ,"ain(1 { С obj(10, 201; std:: cin » obj; std: : cout « obj « std:: endl; // // // Например, ввели число 500 Результат: C1ass С {х = 10, У 500 { Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  20  1712.10 std: :cin.ignore (255, I\n l ) .get (); return о; Преобразованпе объекта в друrОII тпп данных Помимо операторов, язык С++ позволяет переrpуж ать операцию приведения типов. Для этоrо используется следующий формат 11 onepaTopHoro 11 метода: operator <Тип данных> () return <Значение, точно соответствующее типу>; Назв анне типа данных, в который ПРОИЗВОДИТСЯ приведение типа, задается после ключевоrо слова ар er at or. Внутри метода необходимо вернуть значение, точно соотвеТСТВYIOщее этому Т1Iпу. Метод не имеет типа Бозвращаемоrо значения и параметров. Если внутри класс а определен один операторный ll метод переrpузки приведения, ТО при указ ании объекта внутри выражения ПРОИЗВОДИТСЯ автоматическое прео6разование объекта в дрyrой тип, используя этот метод. Например, если существует переrpузка операции приведения к типу in t, то объект можно преобразовать и в тип do uk 1e. Однако, если существJ'lOТ несколько методов, то компилятор уже не может выбрать метод. Поэтому перед объ ектом следует указ ать в какой тип данных необходимо ero преобразовать с помощью операторов приведения типов. В кач естве примера определим внутри класса три метода, ПОЗВОЛЯЮЩИХ преобразовать объект в ТИПЫ in t, d o uk 1e и char * (листинr 10.1 О). I .1IИСТIПП 10.10. Переrр),кn оперnЦlШ приведения rшюв #include <iostream> #include <stdio.h> c1ass С { int х ; р uk1ic : char buf[ 15]; С (int хl {х = х; { operator int() { return х ; } operator double () { return static cast<double> (х ); } Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  21  1712.10 operator char* () sprlntf s (buf, 15, rr %d rr , х ); return buf; {; int ,"ain(1 { С obj (101 ; int х = static cast<lnt>(obJ) + 47; std::cout «х «std::endl; х = (intlobj + 12; std::cout «х «std::endl; douk1e у = statlc cast<douk1e>(obJI + 22.5; std::cout «у« std::endl; std::cout «static cast<char *>(obj) « std:: endl; std: : cin. get (1 ; return о; // 57 // 22 // 32.5 // 10 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  2  1712.10 Если вы коrдани6удь учились ВОДИТЬ автомобиль, то наверняка вспо:мните, что при первой посадке на водительское сиденье все внимание было приковано к трем деталям: рулю, педалям и рычarу переключения передач. Происходящее вне автомобипя уходило на второй план, так как вначале нужно было стронуться с места. По мере пракТ1lКИ навыки вождения улучшал ись и эти три детали постепенно УХОД или на задний план. Как ни странно, но руль и рычar переключения передач всеrда оказывались там, куд а вы не смотря протяrивали руки, а ноrи сами находили педали. Теперь все внимание стало занимать происходяще е на дороrе. Иными словами, вы стали профе сеноналом. В проrpаммировании все абсолютно также. Начинающие проrpаммисты больше обращают внимание на первые попавшиеся на rлаз а операторы, функции и дрyrие элементы языка, а сам алrоритм уходит на задний план. Если проrpамма СКО мпилировалась без ошиб ОК, то ЭТО уже большое счастье, хотя это еще не означает, что проrpамма работает правильно. По мере практики мышление проrpаммиста меняется, ОН начинает обращать внимание на мелочи, на фор матирование проrpаммы, использует бол ее эф фективные алrоритмы и в результате Bcero этоrо допускает меньше ошибок Подводя ИТОПl, можно сказать, что начинaIOЩИЙ проrpаммист просто пишет проrpамму, а опытный проrpаммист пытается найти оптимальный алrоритм и предус мотреть поведение проrpаммы в различных ситациях. Однако, от ошибок никто не застрахован, поэтому очень важно знать как быстро найти ошибку. Тппы ошпбок Существуют три типа ошибок в проrpамме: -+ СИiiтакси,ескuе  это ошибки в имени оператора или функции, отсутствие закрЫВaIOщей или ОТКРЫВaIOщей кавычек и т. Д., то есть оши бки в синтаксисе языка. Как правило, компилятор предупредит о наличии ошибки, а проrpамма не будет выполняться совсем. При мер синтаксиче ской ошибки: std: : cout « rrИет завершающей кавычки!; std:: cin.get (1; При компиляции будут выведены следующие сообщения об ошибках: main. с рр (6) е rro r С2 00 1: newline в ко нс танте main. срр (7) error С2143: синтаксическая ошибка: отсутствие перед rrstd:: cin rr rr.rr , Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  3  1712.10 Цифр а внутри крyrлых скобок, расположенных после названия компилируемоrо файл а, обозначает номер строки, в которой обнаружена ошибка. Если после попытки скомпилировать проrpамму в окне ВЫВОД (открыть окно можно из меню Вид, выбрав пункт Вывод) выполнить двойной щелчок мышью на строке с описанием ошибки, то слева от строки с ошибкой внутри проrpаммы появится маркер и строка станет активной. Кроме Toro, обратите внимание на то, что строка с синтаксической ошибкой подсвечивается редактором красн ой волнистой линией еще ДО компиляции проrpаммы. После слова err or указ ывается номер оши 6ки. Чтобы получить дополнительную инфор мацию об ошибке с таким кодом следует запустить локальную документацию (в меню Справка выбираем пункт Просмотр справки) и в строку поиска ввести номер оши 6ки. Если локальная документация не установлена, то ее можно установить выбрав в меню Сщ):;)вка пункт "}:Щ):;)ВЛI?'IПII?' па})аМl?'траl'o-ПI (Щ):;)В:КП или воспользоваться документацией в Интернете на сайте ilttp: ........шs ,h'.шiпо soft.cOln....; -+ ло8ltЧ,ескuе  ЭТО ошибки в лоrике работы проrpаммы, которые можно выявить только по результатам работы проrpаммы. Как правило, компилятор не предупреждает о наличии ошибки, а проrpамма будет выполняться, так как не содержит синтаксических ошиб ок. Такие ошибки достаточно трУДНО выявить. Основные оши 6ки В языке С++ связаны с указателями и массивами, так как компилятор не производит никакой проверки корректности указателя и не контролирует выход за rpаницы массива Весь контроль полностью лежит на плечах проrpаммиста; -+ оuш61CU времени выполнения  это ошибки, которые возникают во время работы проrpаммы. В одних случаях ошибки времени выполнения являются следствием лоrических ошибок, а в друrих случаях причиной являются внешние события, например, нехватка оперативной памяти, отсутствие прав для записи в файл и др. Операторы tlJ....catcll- 11 аи'О}1! Некоторые операторы стандарной библиотеки в случае ошибки rенерируют uсклl-atенuя. Например, исключение может rенерироваться оператором new, при невозможносТ1l выделении динамической па:мяти. Если в исходном коде не предус мотрена обработка исключения, то проrp амма аварийно прерывается. Обработать исключение в проrpамме позволяет оператор tr у. . . са t ch. Формат о п ер атор а: try <Блок, в котором перехватывается исключение> Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  4  1712.10 catch «Тип исключенияl> <Переменная» <Блок, выполняемый при возникновении исключения> catch «Тип исключенияМ> <Переменная» <Блок, выполняемый при возникновении исключения> catch (... 1 <Блок, :который выполняется, если прыдущие блоки catch не соответствуют типу исключения> Инструкции, в которых перехв атывaIOТСЯ исключения, ДОЛЖНЫ быть располож ены внутри блока try. Если при выполнении этих инструкций возникнет исключение, то управление будет передано в блок с atc h, который соответствует типу исключения. Типом исключения может выступать встроенный тип или пользовательский класс. Обратите внимание на то, что если исключение не возникло, ТО инструкции внутри блока са tc h не выполняются. В качестве примера сrенерируем исключение Т1Iпа int и обработаем ero: try { throw 10; std: : cout 11 rенерируем исключение типа int < < rrэ та ине ТРУ:КЦИ:Я не буд е т :ЕЫПО лне на! I I rr ; catch (int х) { 11 Обработка исключения типа int std: : cout « rr x = rr « х « std:: endl; 11 х = 10 { в этом примере исключение искусственно rенерируется с помощью оператора thr ow. После оператора указывается обь ект исключения. Тип этоrо обь екта становится типом исключения, а само значение доступно через переменнJ'lO, заданнJ'lO в операторе са tch. При возникновении исключения внутри блока tr у управление сразу передается в соответствующий блок с atc h. Таки м образ ом, код, расположенный после инструкции, CreH ерировавшей исключ ение, выполнен не будет. После выполнения инструкций в блоке cat ch управление передается инструкции, расположенной сразу после оператора tr у. . . са t ch. Иными словами, считается, что исключение обработано и можно продолжить выполнение проrpаммы. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  5  1712.10 в некоторых случаях необходимо не продолжить выполнение проrpаммы, а прервать ее выполнение. Например, при нехватке памяти не имеет смысла продолжать работу. В этом случ ае можно внутри блока са tc h произвести завершающие действия (закрыть файл, освободить динамическую память и т. д.), а затем прервать работу проrpаммы с помощью функции exit (1 или akort (1 . Однако, в больших проrpаммах внутри блока са tc h не всеrд а имеется доступ ко всем указателям, хранящим адреса динамически выделенной па:мяти, так как область ВИДИМОСТ1l переменных оrpаничена блоком. Если прервать выполнение проrpаммы, ТО эта динамическая па:мять освобождена не будет. Чтобы сообщить остальным частям проrpаммы об исключении, следует повторно creH ерировать исключение внутри блока с atc h, указав оператор t hrow без параметр а. Пример: try { try throw 10; 11 rенерируем исключение типа int catch (int х 1 std: : cout t hrow ; { 11 Обработка исключения типа int « rr x = rr « х « std:: endl; 11 х = 10 11 ПОвторно rенерируем исключение std: : cout « rrЭта ИНСТРУКЦИЯ не будет :ЕЫполнена! ! ! rr; catch (int х 1 std::cout « rr x = rr «х «std::endl; 11 х = 10 { Как видно из примера, один обработчик исключения можно вложить в дрyrой. При rенерации исключения внутри вложенноrо блока try вначале управление передается во вложенный блок с atc h. Внутри этоrо блока ВЫВОДИТСЯ сообщение, а затем исключение rенерируется повторно с тем же самым типом и значением. В этом случае исключение " в сплывает 11 к обработчику более BblcoKoro уровня и управление передается внешнему блоку с atc h, минуя остальную часть проrpаммы. Если в коде нет дрyrих обработчиков, то проrpамма аварийно прерывается. Внутри оператора t ry. . . с at ch можно указывать несколько блоков cat ch с разными типа:ми исключений. При возникновении исключения производится проверка Т1Iпа в первом блоке са tch. Если Т1Iп исключения соответствует, то управление передается в этот блок, а остальные блоки с atc h иrнорирJ'lOТСЯ. Если тип не соотвеТСТБует, то производится проверка типа в следующе м блоке с at ch и т. д. Если ни один блок са tch Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  б  1712.10 не соответствует исключению, то исключение " ЕС плывает 11 к обработчику более BblcoKoro уровня. При отсутствии обработчика проrpамма аварийно завершается. Пример использования нескольких блоков са tc h: try { throw 10.5; 11 rенерируем исключение типа doUble catch (int х 1 11 Этот блок пропус:кается std: : cout « rrint х = rr « х « std:: endl; catch (douk1e х 1 11 Управление передается этому блоку std: : cout « rrdouble х = rr « х « std:: endl; 11 double х 10.5 catch (char chl 11 Этот блок иrнорируется std: : cout « rrchar ch = rr « ch « std:: endl; Если в блоке с at ch внутри крyrлых скобок указ аны три точки вместо типа, то такой блок перехватывает все исключения. Обычно блок по умолчанию размещaIOТ после всех остальных блоков с atc h. Пример: try { throw I А 1; 11 re не р ируем ис к.тпоче ние типа с har catch (int х 1 11 Этот блок пропус:кается std: : cout « rrint х = rr « х « std:: endl; catch (... 1 11 Управление передается этому блоку std: : cout « rrcatch (...) rr « std:: endl; 11 catch (...) catch (douk1e х 1 11 Этот блок НИКОI"да не будет :ЕЫполнен! ! ! Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  7  1712.10 Прu.мечанuе Не в с е ошибки можно пер ехва тить с помощью опер ат ора t r у. . . с а t с h. Наприм ер, пер ехватить ОIШI бку дел ения на ноль нел:ьзя. KlIacc ехсерНон в зarоловочном файле exception объявлен класс ехс ер tion, который наследJ'lOТ некоторые стандартные классы исключений, например, bad е хс е pt lOn, bad allo с и др. Класс имеет четыре конструктора: exception () ; explicit exception(const char * const &); exception(const char * const &, int); exception(const exception&); Если параметр в конструктор е не зад ан, то текст сообщения выrлядит так: "UnknoWll exception " . С помощью BToporo и тpenero конструктора можно изменить текст сообщения. Получить со обще ние об ошибке позволяет метод what (1 . Прототип метода: virtual const char *what () const; В кач естве при мера сrенерируем исключение класс а ехс ер tion и обработаем ero с п омощью оператора try. .. catch (листинr 11.1). I .1IИСТIПП 11.1. кrm се ехсер Uoll #include <iostream> #include <exception> int ,"ain (1 try { std: : exception err (rrmy  error rr) ; throw err; 11 Создаем обкт 11 rенерируем исключение catch (std::exception &err) std::cout «err.what() «std::endl; 11 myerror std::exception errl; std::cout «errl.what() «std::endl; std: : exception err2 (rrmy  error rr) ; 11 Unknown exception Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  8  1712.10 std::cout «err2.what() «std::endl; std: : cin. get (1 ; return о; 11 myerror Пользовательскпе классы псключеНПII Как вы уж е :знаете, типом исключения может выступать встроенный тип или пользовательский класс. Основное преимущество использования классов ДЛЯ обработки исключений заключается в возможности указания 6азовоrо класса ДЛЯ перехвата всех исключений соответствYIOЩИХ классовпото:мков. Например, если пользовательский кл асс наследует стандартный класс ехс ер tion, то, указав в блоке cat ch объект класс а ех се pt io n, можно перехваТ1lТЬ исключение пользовательскоrо клас са. Обратите внимание на то, что блок с atc h, в котором указан объект производноrо класса, должен быть расположен перед блоком cat ch, в котором указан объект базовоrо кл асса. При разработке библиотек обычно создается базовый класс, ЯВЛЯlOЩИ йся наследником кл асса ех се pt io n, а все остальные клас сы исключений внутри библиотеки наследут этот базовый класс (листинr 11.2). Таким образом, разр аботчик библиотеки получает возможность создания новых кл ассов исключений, созд авая иерархию кл ассов. Пользователю в этом случ ае достаточно указать объект баз oBoro класс а в блоке cat ch, чтобы перехватить все исключения, rенерируемые внутри библиотеки. -ТШСТIПП' 11.2. СОЗДnIOre rnрtlp::r{IШ пользовnтельскl'[\': КЖlССОВ исключеlШЙ #include <iostream> #include <exception> 11 Б азо ВЫЙ клас с class MyExceptionBase : public std::exception р uk1ic : MyExceptionBase () : exception (rrError rr) { } MyExceptionBase (const char *message) exception (message) { { virtua1 MyExceptionBase (1 { { {; 11 Производные классы от MyExceptionBase class MyExceptionl : public MyExceptionBase Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  9  1712.10 р uk1ic : MyExceptonl() : MyExceptonBase(rrErrorrr) { } MyExceptionl (const char *message) : MyExceptionBase (message) { { virtual MyExceptionl () {; class MyException2 : public MyExceptionBase р uk1ic : MyException2() : MyExceptionBase(rrError rr ) MyException2 (const char *message) : MyExceptionBase (message) { { virtua1 MyException2 (1 { { {; int ,"ain (1 try { MyException2 err (rrmy  error rr) ; throw err; 11 Создаем обкт 11 rенерируем исключение catch (MyExceptionl &err) 11 Про из водный класс исключения должен обрабатываться 11 раньше, чем базовый класс!!! std: : cout « rrмyException2: rr « err. what () « std:: endl; catch (MyExceptionBase &err) std: : cout « rrMyExceptionBase: rr « err. what () «std:: endl; } 11 Результат: MyExceptionBase: myerror std: : cin. get (1 ; return о; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  10  1712.10 Оrранпченпе ТIша псключеНПII, rенерпруеl\IЫХ внутрп функцпп в объявлении функции после параметров можно указать специ фикацию, оrpаничивaIOI.ЦYlO типы исключ ений, которые допускается reH ерировать внутри функции. Спецификация имеет следующий синтаксис: <Тип> <Название ФУнкции>([<Параметры>]) thrоw([<Типы исключений>]) / / Те JЮ функции Внутри инструкции t hrow (1 Moryт быть указаны допустимые типы исключений через запятую. Если типы исключ ений не заданы, то функция не должна rенерировать исключения вообще. Если вме сто типов указан ы три точки, то функция может creH ерировать любое исключ ение. Пример : void func() throw(); 11 Функция не должна rенерировать исключение void func() throw(...); 11 Функция может rенерировать любое исключение void func () throw (int, double); 11 Допустимы только ТИПЫ int и double Обратите внимание на то, что в VC++ спецификации исключений являются допусти мыми, но не реализованы. Попытка указ ать внутри круrлых скобок конкр етные типы приводит к выводу предупреЖДaIOщеrо сообщения с номером С4290. Чтобы предотвратить вывод предупреЖДaIOщеrо сообщения следует вначале проrpаммы вставить следующую инструкцию: #pragma warning( disak1e: 4290 1 Н   азначенпе оораоотчпков BepXHerO уровня Если не существует ни одноrо блока са tc h, соотвеТСТВYIOщеrо типу исключения, то вызывается функция te r,"inat е ( 1 . Прототип функции te r,"inat е ( 1 : #inc1ude <eh. h> void ter.minate(void); По умолчанию эта функция завершает выполнение проrpаммы, вызывая функцию ak or t ( 1 . С помощью функц ии s et t er'"lnat е (1 можно назначить функцию, которая будет вызываться вместо t er,"ina te (1 . Прототип функц ии: #inc1ude <eh. h> ter.minate function setterminate(terminate function NewPtFunc); typedef void (* terminate function) () ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 11  1712.10 Через параметр функция принимает указатель на функцию, которая будет вызвана при наступлении исключения BepXHero уровня. Внутри этой функции можно произвести заверШaIOщие действия, а затем обязательно необходимо прервать выполнение проrpаммы. Функция не должна возвращать управление обратно в проrpамму. В кач естве значения функц ИЯ set t ermlnat е () возвращает указатель на прежний о бработчик Пример использования функции приведен в листинrе 11.3. I .1IИСТIПП 11.3. Ф)",кцня "е t  teпniIш te О #include <iostream> #inc1ude <cstd1ik> #inc1ude <eh. h> void func (1 std: : cout « rrfunc () rr « std:: endl; std::abort (); 11 Прерываем выполнение проrраммы int ,"ain (1 setterminate(func); 11 Назначаем обработчик try { throw 10; catch (double err) { 11 Тип не соответствует! std: : cout « rrdouble err rr « err « std:: endl; std: : cin. get (1 ; return о; Помимо функции t er,"inat е (1 существует еще функция unexp е ct ed ( 1, которая вызывается, коrда внутри функции rенерируется исключение не указ анное внутри инструкции throw (1 в объявлении функции. Обратите внимание на то, что в VC++ 2010 функция в этом случае не вызывается. Прототип функции une хр ее te d (1 : #inc1ude <eh. h> void unexpected(void); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  12  1712.10 Внутри функции unex ре ct ed (1 прозводится вызов функции te r,"inat е ( 1 . Назначить свой обраб отчик можно с помощью функции set une хр е ct е d (1 Прототип функции #inc1ude <eh. h> unexpectedfunction setunexpected(unexpectedfunction NewPtFunc); typedef void (* unexpected  function) () ; Через параметр функция принимает указатель на функцию, которая будет вызвана при наступлении исключения. Внутри этой функции можно произвести завершающие действия, а затем обязательно необходимо прервать выполнение проrpаммы. Функция не должна возвращать управление обратно в проrpамму. В качестве значения функция se t unex р ее t ed (1 возвращает указ атель на прежний обработчик Функцпя stl'епOl'О Некоторые функции из стандартной библиотеки не rенерируют исключение, а БОЗВращmoт некоторое значение и присваивaIOТ переменной err по номер ошибки. Чтобы сбро сить флar ошибки следует присвоить значение О этой переменной. Например, функция str to 1 ( 1 , предназначенная для преобразования Сстроки в число типа long, в случае ошибки присваивает переменной е rrno значение макроса ERANGE. Макрос ERANGE и остальные макросы с номерами ошибок определены в заrоловочном файле errno.h. Получить текстовое описание оши бки по ее коду позволяет функция st re rr or ( 1 . Прототип функции: #include <cstring> char *strerror(int n); Пример вывода сообщения: std::cout «std::strerror(ERANGE) «std::endl; 11 Result too large std::cout «std::strerror(22) «std::endl; 11 Invalid argwment В VC++ при использовании функции str er ro r ( 1 выводится предупреждающее сообщение "warning С499б: 'strerror': This function or variable тау Ье unеаЕе". Чтобы избежать этоrо сообщения следует вместо функции str er ro r (1 использовать функцию st re rr or s (1 Прототип функции #include <cstring> errno t strerror s(char *Buf, Slze t SlzelnBytes, lnt ErrNum); В первом параметре функц ия принимает указатель на строку, а во втором параметр е максимальный размер этой строки. Номер ошибки задается в третье м параметре. Пример использования функции st rer r or s (1 приведен в листинrе 11 4 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  13  1712.10 I Лиепаи 11.4. ИСIЮЛЪЗОВnние ф)...к.ЦlШ SQ"lТOl'SO #include <iostream> #include <cstring> #include <errno.h> int ,"ain (1 char ен[ 100] = {О{; strerror s (еп, 100, 421; std::cout «err «std::endl; 11 !llegal byte sequence strerrors(err, 100, ERANGE); std::cout «err «std::endl; 11 Result too large std: : cin. get (1 ; return о; Отключенпе вывода предупреждающпх сообщеНПII При использовании некоторых стандартных функций в VC++ выводятся предупре ждающие сообщения, которые информируют, что функции MOryт стать причиной различных (иноrда очень опасных) ошибок Например, функция st rcp у (1 не ПРОИЗВОДИТ никакой проверки при копировании символов, поэтому возможна ситуация переполнения буф ер а. Для кажд ой такой функции в VC++ суще ствует безопасная замена. Название безопасной функции отличается наличием фраrмента Sll в конце н азв ания. Использ ование без опасных функций решает проблему с переполнением буфер а, но делает проrpамму несовместимой с дрyrи ми компиляторами. Одним из способов решения проблемы несовместимости является переrpузка стандартных функций в б ез о п ас н ы е. В это м случ ае в нутр и про rp аммы ук аз ыв аются станд артн ы е фу нкц ии, а в самом начале проrp аммы добавляются инструкции: #define CRT SECURE срр OVERLOAD STANDARD NAМES 1 #define CRT SECURE срр OVERLOAD STANDARD NAМES COUNT 1 Если вы уверены в своих действиях, то можно отключить вывод предупреждающих сообщений. Сделать это можно двумя способами: -+ определить макрос с названием С RT  S ЕС URE ЫО  WARN INGS в самом начале проrpаммы, перед подключением зarол овочных файл ов. При мер: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  14  1712.10 #define CRT SECURE ЫО WARNINGS #incl ude <io st re am> #incl ude <cs tr ing> -+ вставить прarму war ning. Внутри Ф иryрных скобок указыв ается ключевое слово disab le, после KOToporo задается номер отключаемоrо сообщения. Пример : #prag,"a warning( disak1e : 4996 1 Обратите внимание По еле дир ектив # de f i nе и # р r а gm а Т очка с запя:rо й не указыва етс я. Способы ПОПСЮl ошпбок В проrраl\II\Iе в предыдущих разделах мы научились обрабатывать ошибки времени выполнения. Однако, наи60льше е количе С1БО времени проrpаммист затрачивает на друrой тип ошибок  лоrические ошибки. В этом случае проrpамма компилируется без ошибок, но результат выполнения проrраммы не соответствует ожидаемому результату. Ситуация еще более осложняется, коrда неверный результат проявляется лишь периодически, а не постоянно. Инсценировать TaкyIO же ситуацию, чтобы получить этот же неверный результат, бывает крайне сложно и занимает очень MHoro времени. В этом разделе мы рассмотрим ЛИШЬ "дедовские" (но по прежнему актуальные) способы поиска ошибок, а современные способы отладки приложений, доступные в Мicros oft Visual С++ 2010 Expre ", изучим в следующе м разделе. Первое, на что следует обратить внимание,  это форматирование кода. Начинающие проrpаммисты обычно не 06ращmoт на это никакоrо внимания, считая этот процесс лишним. А на самом деле зря l Компипятору абсолютно все равно, разместите вы все инструкции на одной строке ипи выполните форматирование кода. Однако, при поиске ошибок фор матирование кода позволит найти ошибку rораздо быстрее. Перед всеми инструкциями внутри блока должно быть расположено одинаковое количе ство пробелов. Обычно используется три или четыре пробела. От применения символов табуляции лучше отказаться. Если все же используете, то не следует в одном файле совмещать и пробелы и табуляцшо. Для вложенных блоков количество пробелов УМНОЖaIOТ на уровень вложенности. Если для блока первоrо уровня вложенности использовалось три пробела, то ДЛЯ блока BToporo уровня вложенности ДОЛЖНО использоваться шесть пробелов, для тpenero ур овня  девять пробелов и т. д. Пример форматирования вложенных блоков приведен в листинrе 11. s. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  15  1712.10 .1IИСТIПП 11.5. ПрИI>'ер фор mтиров nния вложенных блоков const short ARRROWS = 2, ARR COLS = 4; int arr[][ARRCOLS] = { {1, 2, 3, 4}, {5, 6, 7, 8 { {; int i, j; for (i=O; i<ARRROWS; ++i) for (j=O; j<ARRCOLS; ++jl std::cout.width(31; std::cout «arr[i][j]; std::cout «std::endl; Открывающая фиrурная скобка может быть расположена как на одной строке с оператором, так и на слеДJ'lOщей строке. Какой способ использовать зависит от предпочтений проrpаммиста или от требований по офор мпению кода, принятых внутри фирмы. Пример размещения открывающей фиrурн ой скобки на отдельной строке: for (i=O; i<ARRROWS; ++i) for (j=O; j<ARRCOLS; ++jl { std::cout.width(31; std::cout «arr[i][j]; std::cout «std::endl; Длина одной строки не должна содерж ать более 80 символов. Если количество символов больше, то следует выполнить переход на новую строку. При этом продолжение смещается относительно основной инструкции на величину отступа или выравнивается по како мули60 элементу. Иначе ПРИХОДИТСЯ пользоваться rоризонтальной полосой прокрутки, а это очень неудобно при поиске ошибок Если проrpамма слишком большая, то следует задуматься о разделении проrpаммы на отдельные функции или класс Ы, которые выполняют лоrически законченные действия. П Ф 11 11 омните, что отлаживать отдельнYIO ункцию rора:здо леrче, чем спarетти KOД. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  16  1712.10 Причем прежде чем вставить функцию (или класс) в основную проrpамму ее следует протестировать в отдельном проекте, передавая функции различные значения и проверяя результат ее выполнения. Обратите внимание на то, что форматирование кода должно выполняться при написании кода, а не во вре:мя поиска ошибок. ЭтИМ вы сократите вре:мя поиска ошибки и скорее Bcero заметите ошибку еще на этапе написания. Если все же ошибка возникла, то вначале следует инсценировать ситуацию, при котор ой ошибка проявляется. После этоrо можно начать поиск ошибки. Причиной периодических ошибок чаще Bcero являются внешние данные. Например, если числа получmoтся ОТ пользователя, а затем ПРОИЗВОДИТСЯ деление чисел, то вполне возможна ситуация, при котор ой пользователь введет число о. Деление на ноль приведет к ошибке. Следовательно, все данные, которые ПОСТУПaIOТ ОТ пользователей, ДОЛЖНЫ проверяться на СОО1Бетствие допустимым значениям. Если данные не cooweTCТEJ'lOT, ТО нужно вывести сообщение 06 ошибке, а затем повторно запросить новое число или прервать выполнение всей проrраммы. Кроме Toro, нужно обработать возможность Toro, что польз ователь может ввести вовсе не число, а строку. Пример получения числа от пользователя с проверкой корректности данных показан в листинrе 11. б. .1IИСТIПП 11.6. ПРИI>.ер 1ЮЛ)"Ч"НИЯ ЧИСJm от IЮЛЪ зовnтеля с провер кой дюlНЫХ int х = 10, у; for ( ; ; ) std: : cout « 11 Бесконечный цикл 11 Вывод им под сказ ку std::cin » у; 11 Получаем значение if (!std::cin.good()) { 11 Проверка успешности операции std: : cout « std:: endl « rrError rr « std:: endl; std::cin.clear(); 11 Сбрасываем флar ошибки std: : cin. ignore (255, 1\ n I ); 11 Очидаем буф=р rry = rr; else if (у == О) 11 Про верка допустимости значения std: : cout « rrЗначение О недопустимо rr « std:: endl; else break; 11 Ес ли ошиб о к не т , 'КI :ЕЫХ ОД им из цикла std::cout « х 1 у « std::endl; 11 Выводим результат Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  17  1712.10 Объект с ои t удобно использовать ДЛЯ вывода промежуточных значений. В этом случае значения переменных вначале выводятся в самом начале проrраммы (внутри функции main () ) и про ИЗВОДИТСЯ проверка СОО1Бетствия значений. Если значения соответствуют, то инструкция с объектом с out перемещается на следующую строку проrpаммы и опять ПРОИЗВОДИТСЯ проверка и Т. д. Если значения не совпали, то ошибка возникает в инструкции, расположенной перед инструкцией с объектом с out. Если ЭТО пользовательская функция, то проверку значений производят внутри функции, каждый раз перемещая инструкц ию С ВЫВОДОМ значений. На одном из этих мноrочисленных этапов ошибка обычно обнаруживается. В больших проrpаммах можно лоrически доrадаться о примерном расположении инструкции с ошибкой и начать поиск оши 6ки оттуда, а не с caMoro начала проrpаммы. Инструкции для вывода промежуточных значений можно расставить уже при написании проrpаммы, не дожидаясь возникновения оши 6ки. В этом случае в начале проrpаммы объявляется макрос, а внутри проrpаммы производится проверка наличия макроса. Если макрос определен, то ВЫВОДЯТСЯ значения. В противном случае инструкция просто иrнорируется. Создать макрос позволяет директива # de f ine: #define МУ DEBUG 1 Проверить суще ствование макроса позволяет следующая конструкция: # ifdef МУ DEBUG 11 Макрос определен. Здесь размещаем ИНСТРУКЦИИ вывода значений # endif Проверить значение макроса можно так #if МУ DEBUG == 1 11 Макрос имеет значение 1 #еndН Вме сто определения co6cweHHoro макроса можно воспользоваться уже существJ'lOЩИМ макросом DEBUG. ЭТОТ макрос определен, если используется режим Debug. Если используется режим Re1e as е, то макрос определен не будет. В качестве примера с оздадим несколько макросов (листинr 11.7). I .1IИСТIПП 11.7. ИСIЮЛЪЗОВnние II<pOCOB # include <iostream > #ifdef DEBUG #define МУ DEBUG1 1 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  18  1712.10 #еndН #def ine МУ DEBUG2 1 int ,"ain (1 int х = 10; #ifdef МУ DEBUG 1 11 Эта ИНСТРУКЦИЯ будет выполнена только при отладке std: : cout « rr x = rr « х « std:: endl; #еndН #if МУ DEBUG2 == 1 11 Эта ИНСТРУКЦИЯ будет выполнена только если макрос // МYDEBUG2 равен 1 std::cout « rr x = rr «х «std::endl; #еndН std: : cin. get (1 ; return о; { В этом примере макрос МУ DEB UG 1 буд ет определен только в режиме D ebug Вместо Hero можно напрямую использовать макрос DE BUG, но определение нескольких собственных макро СОВ, существJ'lOЩИХ только в режиме Debug, ПОЗВОЛИТ ВЫВОДИТЬ те или иные значения, а не все сразу. Чтобы прекратить ВЫВОД промежуточных значений достаточно закоммеНТ1Iровать определение KOHкpeTHoro макр оса. Кроме Toro, в начале скрипта определ ен макрос МУ  DE BUG2. ЭТОТ макрос будет определен в любых режимах. Если макрос имеет значение 1, то будет производиться вывод промежуточных значений. Чтобы отключить ВЫВОД следует изменить значение макроса в начале проrpаммы. Для проверки условия можно также воспользовать ся макр офункцией as ser t (1 , которая имеет следующий прототип: #include <cassert> assert «Выражение»; Если выражение возвращает значение О, то выводится сообщение об ошибке с указ анием названия файла и номера строки, а затем выполнение проrpаммы прерывается с помощью функции ak or t ( 1 . В противном случае никаких действий не производится. В качестве выражения обычно используется лоrическое выражение. Макрофункция срабатывает только в режиме D еЬ ug, В режиме Re 1e as е она Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  19  1712.10 иrнорируется. Пример использования макро функции asse rt ( 1 листинrе 11.8. приведен в .1IИСТIПП 11.8. ИСIЮлъзовnние кроф)",кцин nssel't() # include <iostream > #include <cassert> int ,"ain (1 int х = 10; assert (х >= О); std: : cout « rr x assert (х < О); std: : cin. get (1 ; return о; 11 ОшиБОК не rенерируется = rr « х « std:: endl; 11 re не р ируе те я ошиб ка в режиме Deb ug Результат в режиме D ebug выrлядит так х = 10 Assertion failed: х < О, file c:\book\test\test\main.cpp, line 8 При поиске ошибок часто приходится переходить от кода внутри функции ,"ain (1 к определению какойлибо функции в том же самом файле. Постоянно пользоваться в этом случае вертикальн ой полосой прокрутки очень неуд обно. Одним из способов решения проблемы в VC++ является использ ование закладок Чтобы пометить строку следует сделать ее активной, а затем из ме:mo Прав};;:;) выбирать пункт Закла;!J;КП I Закла;!J;Ка или нажать соотвеТС1БJ'lOЩYIO кн опку на панели инструментов. Слева от строки появится специальный маркер. Чтобы удалить закладку следует повторно выбрать тот же пункт меню Перемещаться между закладками можно с помощью клавиши <F2> или с помощью соответствYIOЩИХ кнопок на панели инструментов. Еще одним способом решения проблемы является разделение окна на две части. Для этоrо в меню Окно следует выбрать пункт РnздеJШТЪ. Чтобы вернуть окно в первоначальное состояние следует в меню ОКНО выбрать пункт СНЯТЬ })аЗДI?'Ш"IПII?'. Отладка "роrраl\II\IЫ в l\Iiпоsоft Уisпаl С++ 2010 Expl'ess Сделать поиск ошибок боле е э фф ективным позволяет отладчик, встроенный в Мicros оа Visual С++ 2010 Express. С ero помощью можно выполнять проrpамму по шаrам, при Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  20  1712.10 ЭТОМ контролируя значения переменных на каждом шarу. Отладчик позволяет также проверить, соответствует ли порядок выполнения инструкций разработанному ранее алrоритму. Прежде чем начать отладку необходимо пометить строки внутри проrpаммы с ПОМОЩЬЮ тоЧ,ек остшюва. Для добавления точки останова делаем строку активной, а затем из KOHTeKCTHoro меню выбираем пункт Точка OfT:;)HOB;) I В("таВIПЬ точку OfT:;)HOB:;). Слева ОТ строки появится красный кружок, 060значaIOЩИЙ точку останова. Добавить точку останова можно еще быстрее. Для этоrо достаточно щелкнуть слева от строки левой кнопкой мыши. Повторный щелчок позволяет удалить точку останова. Кроме Toro, для добавления или удал ения точки отстанова можно воспользоваться клавишей <F9>. Чтобы изменить свойства точки, отключить или удалить ее следует щелкнуть на ней правой кнопкой мыши и в открывшемся контекстном меню выбрать соответствующий пункт. Коrда точки останова расставлены можно начать отладку. Для этоrо из ме:mo Отладка выбираем пункт Начать отла;!J;КУ или нажимаем клавишу <FS>. При достижении точки останова выполнение проrpаммы прерывается и отладчик ожидает дальнейших действий проrp аммиста. Инструкц ия, котор ая буд ет выполняться на следующем шаrе, помечается желтой стрелкой слева от строки. В режиме прерывания можно посмотреть значения различных переменных в окнах ВндПI"Ы и ЛокаJThНЫ. Если окна не отображаются, то отобразить их можно выбрав в меню Отла;!J;Ка пункт Окна, а затем соответствJ'lOЩИЙ пункт. По смотреть значение переменной можно также если навести указатель мыши на переменную. Значение переменной отобразится во ВСПЛЫВaIOщей под сказке . При отладке можно контролировать значения отдельных переменных, а не всех сразу. Для этоrо следует добавить название переменной в окне KOHTpOJn.Hbll?' знаЧl?'IПIЯ 1 в поле П"IЯ. Чтобы отобразить окно из меню Отладка выбираем пункт Окна I КoHTI'OJThHbl значmlЯ I KOHTI'OJThHbl значmlЯ 1. Можно также выделить название переменной и из KOHTeКYHoro меню выбрать пункт Добавить контр OJn.HOI?' знаЧI?'IПII?'. Для пошаrовоrо выполнения проrpаммы предназначены следующие пункты в меню Отла;!J;Ка или соотвеТС1БJ'lOщие кнопки на панели инструментов О тла;!J;К а: -+ Пl'одолжнтъ (клавиша <FS»  выполняет инструкции до следующей точки останова или до конца проrp аммы при отсутствии точек; -+ Шат с заходом (клавиша <Fll»  выполняет одну инструкцию. Если в этой инструкции производится вызов функц ии, то производится заход внутрь функции; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  21  1712.10 -+ Шаr с обходом (клавиша <Fl0»  выполняет одну инструкцию. Если в этой инструкции производится вызов функции, то функция выполняется и отладчик переходит в режим ожидания после выхода из функции; -+ Шаr с выходом (комбинация клавиш <Shift>+<Fll»  при заходе в функцию ЭТОТ пункт позволяет выполнить функцию и выйти из нее. Отладчик переходит в режим ожидания после выхода из функции; -+ ПI'заIl)'СТНТЪ (комбинация клавиш <Ctrl>+<Shift >+<FS»  начинает отладку заново; -+ Остановнтъ отладку (комбинация клавиш <Shift>+<FS»  останавливает отл адку. Кроме Toro, можно произвести выполнение проrpаммы до текущей позиции. Для этоrо в режиме отладки щелкае м правой кнопкой мыши на строке и из KoиreKCTHoro меню выбираем пункт ВьmОJППIТЬ до ТI?'К)""Щl?'ii ПОЗIп..:I;JДI или дел аем строку активной и нажимаем комбинацию кл авиш <Ctrl>+<F1 О>. Чтобы сделать все точки останова неактивными следует из меню Отла;!J;Ка выбрать пункт ВЫКJIЮЧПТЬ В(!?' ТОЧКИ OfT:;)HOB:;). В ЭТОМ случае точки временно ОТКЛЮЧaIOТСЯ, но не удаляются. В отключенном состоянии отображается лишь контур кружка без заливки. Чтобы опять сделать все точки активными следует из меню Отла;!J;Ка выбрать пункт ВКJIЮЧПТЬ В("!?' ТОЧКИ OfT:;)HOB:;). Для удал ения точек предназначен пункт "}:даJПIТЬ В("!?' точки OfT:;)HOB;) В меню о тла;!J;Ка. Управлять отдельными точками останова или всеми сразу можно в окне Точки о("танова. Чтобы отобразить окно следует из меню О тла;!J;К а выбрать пункт Окна I Точкн останова или нажать комбинацию клавиш <A1t>+<F9> В этом окне можно изменить свойства точки останова Например, чтобы указ ать, что точка должна срабатывать только на N ый раз следует щелкнуть на точке правой кнопкой мыши и из KOHTeКYHoro меню выбрать пункт l.bI(" ло попадаю.и":'"}. В открывшемся окне из списка выбираем нужный пункт, вводим число в текстовое поле, а затем нажимаем кнопку ОК. После этоrо в красном кружке, обознаЧaIOщем точку останова, появится белый плюс. В предыдуще м разделе мы рассматривали поиск ошибки с помощью вставки в код инструкций для вывода промежуточных значений. С помощью точек останова можно выполнить такое же действие, но без вставки инструкций в исходный код. Для этоrо делаем строку активной, щелкаем на ней правой кнопкой мыши и из KoиreKcTHoro меню выбираем пункт Точка о("танова I В("тавить точку ОТ("ЛAcr.mаЮIЯ. В открывшемся окне вводим текст сообщения, используя специальные символы, инфор мация о которых содержится в окне, а затем нажимаем кнопку ОК. После этоrо слева от строки с Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  22  1712.10 инструкцией отобразится кр асный ромб. Текст сообщения при отладке будет отображаться в окне Вывод. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  2  1712.10 Язык С++ поддерживает две системы ввода/вывода. Первая система позаимствована от языка с. Втор ая система является 06ъектноориентированной и доступна только в языке С++. В этой rлаве мы рассмотрим обе системы. Прu.мечанuе В iiЛ. 1 мы уж е и:J учалп вв О WB ыв О Д данных в окно конс оли. В этой r лав е описывают ся только ДОП ОJП:пrr ельны е в озмож НО ст применительно к файлов о й систем е, а таюк е форматированный выв о Д даННЫХ. Работа с фа(IЛШ\Ш в языке С Язык С++ поддерживает операции ввода/вывода из языка С, объявленные в файл е stdio. h. В языке С++ вместо этоrо файла можно подключать файл cstdio: #include <cstdio> Следует учитывать, что рассматриваемые далее функции применяются в языке С Хотя ИХ можно использовать и в языке С++, тем не менее для ввода!вывода данных стоит отдать предпочтение объектноориентированной системе ввода/вывода языка С++. Описание функций языка С приведено в этой книrе лишь для Toro, чтобы вы моrли разобраться в чужом коде. ОТКIIЬПИf И заКIIЬПИf файла Для открытия файл а предназначена функция f ор en (1 . Прототип функции: #include <cstdio> FILE *fopen(const char * Filename, const char *Mode); КоличеС1БО одновременно открытых файлов оrpаничено значением макроса FOPE N  МАХ. Определение макроса выrлядит так: #define FOPEN МАХ 20 В каче стве результата функция возвращает указатель на структуру F ILE. Этот указ атель следует передавать функциям, которые предназначены для работы с уже открытым файл о м. Есл и откр ыть файл н е уд ал ось, Ф ун кц ия В озвр ащае т нул ев о й указ атель и присваивает rлобальной переменной er rno значение макр оса Е INVAL. Структура F ILE определена следующим образом: struct iobuf { char * ptr; int cnt; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  3  1712.10 char * base; int flag; int file; int charbuf; int  bufsiz; char * tтp f пате; {; typedef struct iObuf FILE; В параметре F i1e na,"e указывается путь к Ф айлу. Длина пути оrpаничена значением макроса F ILE ЫАМЕ МАХ Определение макро са: # de f ine F ILE ЫАМЕ МАХ 2 60 Путь может быть абсолютным или относительным. При указании абсолютноrо пути следует учитывать, что слэш является специальным СИМВОЛОМ. ПО этой причине ero необходимо удваивать. Пример : std: : F ILE * fp; fp = std:: fopen (rrc: \ \ temp \ \ new\ \ f ile. txt rr, rrw rr ); Если вместо двух слэшей использовать только один, то в пути будут присутствовать сразу три специальных символа: \ t, \ n и \ f. Посл е преобразования специальных символов путь буд ет выrлядеть следующи м образо м: с : <Табуляция> етр <Пер е вод с тро ки> ew <Пе ре вод фа рма та> ile . t х t Вме сто абсолютноrо пути к файлу можно указать относительный путь. В этом случ ае путь определяется с учетом местополож ения текущеrо рабочerо каталоrа. Обратите внимание на то, что текущий рабочий каталоr не всеrда совпадает с каталоrом, в котором находится исполняемый файл. При запуске из редактора VC++ текущим рабочим KaTaJIorOM будет каталоr проекта, а не KaTaJIor, в котором нахОДИТСЯ исполняемый файл. Если файл запускается с помощью двойноrо щелчка на значке, то каталоrи будут совпадать. Если же файл запускается из командной строки, то текущим рабочим каталоrом будет каталоr, из KOToporo запускается файл. Получ ить строковое представление текущеrо рабочеrо каталоrа в VC++ позволяет функция get cwd (1 Прототип функции: #include <direct.h> char * getcwd(char *DstBuf, int SizelnBytes); В первом параметре функция принимает указатель на буфер, а во втором параметр е  максимальный размер буфер а. Пример: char buf[200] = {О{; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  4  1712.10 getcwd(buf, 2001; std::cout «buf «std::end1; // C:\book\test\test Если в кач естве парамеТРОБ указаны нулевые значения, то строка создается динамически с помощью функц ии ,"a11oc (1. В этом случае функция get cwd (1 возвращает указатель на эту строку или нулевой указ атель в случае ошибки. После окончания работы со строкой следует освободить память с помощью функции fr ее (1 . Пример: char *buf = о; buf = getcwd(O, 01; if (bufl { std::cout «buf «std::end1; // C:\book\test\test std: : free (buf 1 ; buf = о; Возможны следующие варианты указания отиосительноrо пути в Windows: -+ если открываемый файл находится в текуще м рабоч ем каталоrе, то можно указать только название файла или перед названием файла добавить одну точку и прямой или обратный слэш. Пример: fp 1 = std:: fopen (rrf ile. txt rr , rrw rr ); fp2 = std:: fopen (rr ./f ile. txt rr, rrw rr ); fp3 = std:: fopen (rr. \ \ f ile. txt rr , rrw rr ); -+ если открываемый файл расположен во вложенной папке, то перед названием файл а перечисля::ются названия вложенных папок через прямой или обратный слэш. Пример: fp 1 = std:: fopen (rrfolder 1 \ \ f ile. txt rr, rrw rr ); fp2 = std:: fopen (rrfolder l/f ile. txt rr , rrw rr ); fp3 = std:: fopen (rrfolder 1 \ \ folder2\ \ file. txt rr, rrw rr ); fp4 = std:: fopen (rrfolder 1/folder2/f ile. txt rr , rrw rr ); -+ если папка с файлом расположена ниже уровнем, то перед названием файла указываются две точки и прямой или обратный слэш Пример: fp 1 = std:: fo р еn (rr . . \ \ f ile. t xt rr , rrw rr) ; fp2 = std:: fopen (rr. ./f ile. txt rr , rrw rr ); fp3 = std:: fopen (rr.. \ \.. \ \file .txt rr , rrw rr ); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  5  1712.10 fp 4 = std:: fo р еn (rr . ./ . ./ f ile . t xt rr, rrw rr ); -+ если в начале пут расположен слэш, то путь отсчитывается ОТ корня диска. В этом случае местоположение текущеrо ра60Ч ero каталоrа не имеет значения. Пример : fp 1 = std:: fopen (rr\ \book\ \test\ \ f ile. txt rr , rrw rr ); fp2 = std:: fopen (rr /book/test/f ile. txt rr , rrw rr ); Параметр Мо de в функции fo реп (1 может принимать следующие значения внутри C строки: -+ r  только чтение. По сле открытия файла курсор устанавливается на начало файл а. Если файл не суще ствует, то функц ия fo ре n (1 возвращает нулевой указатель; -+ r+  чтение и запись. После ОТКРЫТ1lЯ файла кур сор устанавливается на начало файл а. Если файл не суще ствует, то функц ия fo ре n (1 возвращает нулевой указатель; -+ w  запись. Если файл не существует, то он будет создан. Если файл существует, то он будет перезаписан. Посл е открытия файла кур сор устанавливается на начало файл а; -+ w+  чтение и запись. Если файл не суще ствует, то он будет создан. Если файл существует, то он будет перезаписан. По сле открытия файла курс ор устанавливается на начало файла; -+ а  запись. Если файл не суще ствует, то он будет создан. Запись осуще ствляется в конец файл а. Содержимое файла не удаляется; -+ а+  чтение и запись. Если файл не существует, то он будет создан. Чтение производится с начала файла. Запись осуществляется в конец файла. Содержимое файл а н е уд ал яется. Прu.мечанuе В Мicrosoft Visual С++ имеются дополнительные р ежимы с, n, t, S, R, Т и D, а также парам етр с с s , ПОЗВ оляющий указать ко дир овку файпа. Эти р ежимы не ВХО дЯТ В стандарт я:JЬJКa С ++. За допо лнпт ельн ой инф о рмацией о бр ащ3Йте сь к документации. После режима может следовать моди фикатор: -+ ь  файл будет открыт в бинарном режиме; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  б  1712.10 -+ t  файл будет открыт в текстовом режиме (значение по умолчанию в Windows). В этом режиме при чтении символ \ r будет удал ен, а при записи наоборот добавлен. В каче стве примера откроем файл на запись в текстовом режиме и запишем в Hero две строки, разделенные символом \ n (листинr 12.1). Затем откроем тот же файл на чтение в бинарном режиме и считаем первую строку. Чтобы продемонстрировать факт добавления символа \ r при записи в текстовом режиме, выведем код ы символов, которые расположены в конце считанной строки. -ТШСТIПП 12.1. PtlБОТ;[I с фnйлt1r"IИ в TeKCTOBOl'r1 и б:mmрНОI'rI реЛCШrШХ #include <iostream> #include <cstdio> #inc1ude <cstd1ik> int ,"ain(1 { char buf[200] = {О{; std::FILE *fp = о; fp = std:: fopen (rrfile . txt rr, rrw rr ); if (' fpl std: : perror (rr Error rr) ; std: : cin. get (1 ; std: : exit (11 ; std: : fputs (rrStr ingl \ nStr ing2 rr, fp); std: : ff1ush (fpl ; std:: fc10se (fpl; fp = std:: fopen (rr file . txt rr, rrrb rr) ; if (' fpl std: : perror (rr Error rr) ; std: : cin. get (1 ; std: : exit (11 ; std: : fgets (buf, 30, fp 1 ; std: : cout « (int) buf [7] « rr rr « 11 Открываем файл на запись 11 в текстовом режиме 11 Проверяем успешность 11 ВЫВОДИМ сообщение 11 Выходим при ошибке 11 Записываем строку // Сбрасываем буфер 11 Закрываем файл 11 Открываем файл на чтение 11 в бинарном режиме 11 Проверяем успешность 11 Выводим сообщение 11 Выходим при ошибке 11 Читаем од ну с тро ку 11 Результат: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  7  1712.10 (intl buf [8] « std:: end1; std:: fc10se (fpl; std: : cin. get (1 ; return о; // 13 10 == \r \n 11 Закрываем файл Попробуйте во втором случае изменить режим с "rb " на Ilr". В результате ВЫВОД будет 1110 011, а не 1113 1011. Это доказывает, что при чтении в текстовом режиме символ \r уд аляет ся. В этом примере мы воспользовались несколькими новыми функциями. Функция ре rr or (1 выводит текст сообщения об ошибке. Перед этим сообще ни ем добавляется текст, переданный в параметре, и символ двоеточия. Например, если в первом случае файл доступ ен только для чтения, то получим следующее сообщение в окне консоли: "Error: Permission denied". Если во втором случае файл не существует, то сообщение будет дрyrим: "Error: Но such filе or directory". Прототип функции: #include <cstdio> void perror(const char *ErrMsg); Вме сто функции ре rr or (1 можно воспользоваться функцией s tre rr о r ( 1 , которой в параметре передается значение переменной er rno. Пример : std::cout «std::strerror(errno) «std::endl; Функция f ри ts (1 записывает CCтpOKY в файл. Для ускор ения работы производится буферизация записываемых данных. Ин формация из буф ера записывается в файл полностью только в момент закрытия файла. Сбросить буфер в файл явным образом можно с помощью функции ff 1 us h ( 1 . Прототип функции: #include <cstdio> int ff1ush(FILE *Filel; Прочитать одну строку из файла позволяет функция fget s ( 1. Считывание производится пока не будет достиrнут символ перевода строки или из файла не буд ет прочитано указанное количество символов минус ОДИН символ (используется ДЛЯ вставки нулевоrо символа). Закр ыть файл позволяет функция f c10 se (1 . Пр ототип функц ии: #include <cstdio> int fclose(FILE *File); В единственном параметре передается указатель на открытый ранее файл. В качестве з н ач е н ия фу нкц ия В озвр ащае т: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  8  1712.10 -+ О  если файл успешно закрыт; -+ EOF  если при закрытии файла произошла оши бка, например, дискета была вынута из дисковода или нет сво60дноrо места на диске. Макрос Е OF определен следующим образом: #define EOF (11 При использовании функции f оре n (1 в VC++ выводится предупреждающее сообщение "warning С499б: '[ореn': This function or variable тау Ье unеаЕе". Чтобы избежать вывода сообщения вместо функции fo ре n (1 можно использ овать функцию f оре n  s (1 . Прототип функции: #include <stdio.h> errno t fopens(FILE **File, const char * Filename, const char *Mode); В первом пара метре функция принимает адрес указателя на файловую структуру. Остальные параметры аналоrичны параметрам функции f оре n (1. В кач естве результата функция возвращает О при отсутствии ошибки ипи код ошибки. Пример использования функции fop en s (1 приведен в листинrе 12 2 -ТШСТIПП 12.2. PtlБОТ;[I с фnйлt1r"IИ в TeKCTOBOl'r1 и б:mmрНОI'rI реЛCШrШХ #include <iostream> #include <cstdio> #inc1ude <cstd1ik> int ,"ain (1 std::FILE *fp = о; errno t err; err = fopen  s (&fp, rrfile. txt rr , if (еп ,= 01 std::perror(rrError rr ); std: : cin. get (1 ; std: : exit (11 ; std::fputs(rrStringl\nString2 rr , std: : ff1ush (fpl ; std: : fc10se (fp 1 ; std: : cout « rrOK rr « std:: endl; rrw rr ) ; // Открываем файл на запись // Проверяем успешность // ВЫВОДИМ сообщение // ВЫХОД им пр и ошиб ке fpl; // Записываем с тро ку // Сбрасываем буф= р // Закрываем файл Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  9  1712.10 std: : cin. get (1 ; return о; '3аIШfЬ в файл и 'ПflШf из файла Для записи в файл предназначены следующие функции: -+ fp ut с (1 и р utc (1  записывают символ в файл. Функции возвращают код записанноrо символа или значение макроса EOF в случ ае ошибки. Прототипы функций: #nclude <cstdo> int fputc(int Ch, FILE *File); int putc(int Ch, FILE *File); Пример: std:: fputc ('Т 1, fp); std: : putc ( I S 1, fp); -+ fp ut s (1  записывает CCтpOKY в файл. Функция возвращает неотрицательное ЧИСЛО, если ошибок нет, и зн ачение макроса EOF при наличии оши 6ки. Прототип функции: #include <cstdio> int fputs(const char *Str, FILE *File); Пример: std: : fputs (rrStringl \nStr ing2 rr, fp); -+ fprintf (1  производит форматированный вывод в файл. При наличии ошибки функц ия возвращает значение макроса EOF . Прототип функции: #include <cstdio> int fprintf(FILE *File, const char *Format, ...); в параметре Fo r,"a t указ ывается строка специальноrо формата. Внутри этой строки можно указать обычные символы и спецификаторы формата, наЧИНaIOщиеся с символа %. Эти спецификаторы мы рассматривали при изучении функции pr int f (1 . Пример использования функции fpr in tf (1 : int а = 10, Ь = 20; std: : fpr intf (fp, rr%d %d rr , а, Ь); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  10  1712.10 -+ fwr i te (1  записывает объект в файл. Обратите внимание на то, что файл должен быть открыт в бинарном режиме. Функция возвращает количество записанных объектов. Прототип функции: #nclude <cstdo> size t fwrite (const void *Buf, size t Size, size t Count, FILE *F ile) ; В первом параметре функция принимает указ атель на объект. Во втором параметре указывается размер объекта в байтах, а в третьем параметре  количество записываемых объектов. Размер объ екта следует определять с помощью оператора si "ео f. В каче стве примера запишем структуру в файл, открытый на запись в бинарном режиме: struct Point int х, у; point; point. х = 10; point. у = 2 о; int х = std:: fwr ite (&point, sizeof (Point), 1, fp); std::cout « х « std::endl; 11 1 Перечислим функции, предназначенные для чтения файла: -+ fget с (1 и get с (1  считывают один символ из файла. В качестве значений функц ии возвращают код прочитанноrо символа. Если в файле нет больше символов или произоШТI а ошибка, то функции возвращают значение константы EOF. Прототипы функций: # inc lude <с stdio > int fgetc(FILE *Fi1el; int getc(FILE *File); Пример использования функций: char ch1 = std: :fgetc(fpl; std::cout « chl « std::endl; char ch2 = std: :getc(fpl; std: : cout « ch2 « std:: endl; -+ fget s (1  читает одну строку из файла. Прототип функции: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 11  1712.10 #nclude <cstdo> char *fgets(char *Buf, nt MaxCount, FILE *Fle); Считывание производится до первоrо символа перевода строки или до конца файла или пока не будет прочитано МахС ount  1 СИМВОЛОВ. Возвращаемая строка включает символ перевода строки. Исключением является последняя строка. Если она не завершается символом перевода строки, то символ доб авлен не будет. Если произошла ошибка или достиrнут конец файл а, то функция возвращает нулевой указатель. Пример считывания одной строки из файла: char buf [200] = {О {, * pch; pch = std:: fgets (buf, 200, fp 1 ; if (pchl std:: cout « buf « std:: end1; -+ fs canf ()  позволяет считать данные из файла и автоматически прео6разовать в конкр етный тип, например, в целое число. Прототип функции: #nclude <cstdo> int fscanf (FILE *F ile, const char *Format, ...); в параметре F or,"at указ ывается строка специальноrо формата, внутри которой задаются спецификаторы, аналоrичные применяемым в функции sc anf ( 1. В последующих параметрах передаются ссылки на переменные, в которых будет сохран ено зн ачение. В каче стве результата функция возвращает количество преобразованных данных. Пример считывания из файла целоrо числа: int х = О, count = о; count = std:: fscanf (fp, rr %d rr , &х); 11 СИМВОЛ & обязателен! ! ! std: : cout « count « std:: endl; std::cout « х « std::endl; В VC++ при использовании функции fscanf (1 выводится предупреждающее сообщение "warning С499б: 'fscanf: тш, function or variable тау Ье unsafe". Чтобы избежать этоrо сообщения следует применятъ функцию fsc an f s (1 Прототип функции: int fscanf s (F ILE * File, const char *Format, ...); в ЭТОМ случ ае при считывании строки вначале указывается адрес строки, а затем максимальное количество символов. Пример исчитыания строки: char str[100] = {О{; 11 СИМВО Л & для етро КИ не указываете я! ! ! Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  12  1712.10 fscanf s (fp, rr %srr, str, 100); std::cout « str « std::endl; -+ fr ead (1  считывает объект из файла. Обратите внимание на то, что файл должен быть открыт в бинарном режиме. Прототип функции: #nclude <cstdo> size t fread (void * DstBuf, size t ElementSize, size t Count, F ILE * F ile ) ; в первом параметре функция принимает указ атель на объект. Во втором параметре указывается размер объекта в байтах, а в третьем параметре  количество считываемых объектов. Размер объекта следует определять с помощью оператора si zeo f. Функция возвращает количе ство считанных объектов. Запишем структуру в файл, открытый на запись в бинарном режиме, а затем считаем с труктуру из файла и выведем значения (листинr 12.3). I .1IИСТIПП 12.3. Coxpnнe ине с тр)']( Т)l' ы в фnйл #include <iostream> #include <cstdio> #inc1ude <cstd1ik> struct Point { int х, У; } point 1, point2; int ,"ain (1 std::FILE *fp = о; int х = о; if (fopen  s (&fp, rrfile. txt rr , rr1Alb rr ) != О) { 11 Бинарный ре;:ю.rм! std::perror(rrError rr ); std: : cin. get (1 ; std: : exit (11 ; pointl. х = 10; point1. У = 20; х = std::fwrite(&pointl, sizeof(Point), 1, fp); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  13  1712.10 std::cout «х «std::endl; 11 1 std: : ff1ush (fpl ; std: : fc10se (fp 1 ; if (fopen  s (&fp, rrfile. txt rr , rrrb rr ) != О) { 11 Бинарный ре;:ю.rм! std::perror(rrError rr ); std: : cin. get (1 ; std: : exit (11 ; х = std::fread(&point2, sizeof(Point), 1, fp); std::cout «point2.x «std::end1; // 10 std::cout «point2.y «std::end1; //20 std: : cout « х « std:: endl; 11 1 std: : fc10se (fp 1 ; std: : cin. get (1 ; return о; { в качестве еще одноrо примера запишем строку в файл, а затем произведем п осимвольное считывание (листинr 12.4). I-тшст IПП 12.4. по СШrШ ольное считыв[IIore из ф;[lЙJI;[I #include <iostream> #include <cstdio> #inc1ude <cstd1ik> int ,"ain (1 std::FILE *fp = о; char ch = о; if (fopen  s (& fp, rrf ile. txt rr, rrw+rr) ! = О) { 11 Чтение и запись std::perror(rrError rr ); std: : cin. get (1 ; std: : exit (11 ; std: : fputs (rrStr ingl \ nStr ing2 rr, fp); 11 Записываем строку std: : ff1ush (fpl ; std::rewind(fp); 11 Перемещаем курсор в начало файла Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  14  1712.10 ch = std:: fgetc (fp 1 ; while (' std: : feof (fpll { if (std:: ferror (fp 11 11 Считываем один символ 11 Пр о ве р яем наличие ошиб о к std::perror(rrError rr ); std: : cin. get (1 ; std: : exit (11 ; std: : cout « ch « rr (rr « (int) ch « rr) rr « std:: endl; ch = std:: fgetc (fp) ; 11 Считываем один символ std: : fc10se (fp 1 ; std: : cin. get (1 ; return о; в этом примере были использованы три новые функции: -+ rewind (1  устанавливает курсор на начало файла. Пр ототип функц ии: #include <cstdio> void rewind(FILE *File); -+ fe of (1  возвращает ненулевое значение, если достиrнут конец файла. В противном случае возвращается значение О. Прототип функции: #include <cstdio> int feof(FILE *File); -+ fe rr or (1  возвращает ненулевое значение, если при работе с файл ом возникп а ошибка. В противном случае возвращается значение о. Функцию следует вызывать сразу после выполнения операции. Прототип функции: #include <cstdio> int ferror(FILE *File); Удалить все оши 6ки, связанные с потоко М, позволяет функц ия cle ar er r ( ) . Прототип функции: #include <cstdio> void clearerr(FILE *File); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  15  1712.10 в VC++ вместо функции с 1eare r r (1 можно использовать функцию с 1eare r r s (1 Если операция успешно произведена, то функция возвращает значение О. Прототип функции: #incl ude <st dio. h> errno t clearerr s(FILE *File); Файлы ЩIоизвольноrо доступа Файл можно читать не только с caMoro начала, НО и с произвольной позиции. Как правипо в этом случ ае файл открывают в бинарном режиме. Записывать в файл также можно с произвольной позиции. Для работы с файлами произвольноrо доступа предназначены следующи е функции: -+ fget ро s (1  записывает позицию курсора относительно начала файла в переменную, адрес которой передается во втором параметре. В качестве результата функц ия возвращает значение О, если ошибок не возникло, и ненулевое значение в противном случае. Прототип функции: #include <cstdio> int fgetpos (F ILE *File, fpos t *pos); Тип fpo s t объявлен как целочисленный тип Пример использования функции: std:: fpos t pos = о; fgetpos (fp, &posl; std::cout « pos « std::endl; -+ ft e11 (1  возвращает позицию кур сора относительно начала файла. При ошибке возвращается значение  1L. Прототип функции: #include <cstdio> 10ng fte11(FILE *Fi1el; Пример использования функции: long pos = о; pos = std::fte11(fpl; std::cout « pos « std::endl; В VC++ вместо функции ft e11 (1 можно воспользоваться функцией Не 11i 6 4 (1 . Прототип функции: #incl ude <st dio. h> Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  16  1712.10 int64 fte11i64(FILE *Fi1el; Пример: int 64 pos = о; pos = ftelll64(fpl; std::cout « pos « std::endl; -+ rewind (1  устанавливает курсор на начало файла. Пр ототип функц ии: #include <cstdio> void rewind(FILE *File); -+ fs et ро s (1  перемещает кур сор относительно начала файла. Адрес переменной, в которой содержится значение, передается во втором параметре. В каче стве результата функция возвращает значение О, если ошибок не возникло, иненулевое значение в протнвном случае. Прототип функции: #include <cstdio> int fsetpos (F ILE *File, const fpos t *pos); Пример: fpos t pos = 2 * siz eof (int) ; std: : fsetpos (fp, &Pos); -+ fs ее k (1  устанавливает курс ор в позицию, имеющую смещение Of fs et относительно позиции Or igin. В качестве результата функция возвращает значение О, если ошибок не возникло, и ненулевое значение в противном случае. Пр ототип функции: #include <cstdio> int fseek(FILE *File, long Offset, int Origin); В параметре Or igin MOryт быть указ аны следующие макросы: . SEEKSET  начало файла; SE ЕК  С UR  текущая позиция курс ора; SE ЕК  Е ND  конец файла. . . Определения макро сов выrлядят следующим образом: #define SEEK SET О #define SEEK CUR 1 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  17  1712.10 #def ine SE ЕК Е ND 2 В VC++ вместо функции fse ek можно воспользоваться функц ией fse eki 6 4 (1 . Прототип функции: # inc lude <5 tdio . h> int fseeki64(FILE *File, int 64 Offset, int Origin); в качестве примера использ ования файлов произвольноrо доступа запишем массив в файл, а затем считаем из файла значения первоrо и предпоследнеrо элементов массива (листинr 12.5). I .1IИСТIПП 12.5. Фnйлы пр ОIfЗВОЛЪЮ"О ДОСТ)'ШI # include <iostream > #include <cstdio> #inc1ude <cstd1ik> int ,"ain (1 std: : FILE *fp int ап[] = { long pos = о; if (fopens(&fp, rrfile.txt rr , std::perror(rrError rr ); = о; 1, 2, 3, 4, 5 }, х = О, size = о; rrw+b rr ) ,= 01 { // Бинарный режим'" std: : cin. get (1 ; std: : exit (11 ; size = sizeof(int); std: : fwr ite (arr, size, 5, fp); 11 Записываем массив std: : ff1ush (fpl ; std: : fseek (fp, OL, SEEK :ЗЕТ); 11 Перемещаем курсор в начало файла pos = std::fte11(fpl; std::cout «pos «std::endl; 11 О std: : fread (&х, size, 1, fp); std::cout «х «std::endl; 11 1 11 П=ремещаем курсор на предпоследний элемент std: :fseek(fp, 2L * size, SEEKEND); pos = std::fte11(fpl; std::cout «pos «std::end1; // 12 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  18  1712.10 std: : fread (&х, size, 1, fp); std::cout «х «std::endl; std: : fc10se (fp 1 ; std: : cin. get (1 ; return о; // 4 СоздаlШf Вllf!llfШIЫХ файлов Для создания BpeMeHHoro файла предназначена функция t,"p f i1e (1 . Временный файл создается в корневой папке. Функция возвращает файловый указатель на поток, открытый в режиме w+b, или нулевой указатель в случае ошибки. После закр ытия временный файл автоматически удаляется. Обратите внимание на то, что в некоторых операционных системах для создания вpeMeHHoro файла MOryт потребоваться права администратора. Прототип функции: # include <cstdio> FILE *tmpfi1e(voidl; В VC++ при использовании функции t'"pfi1e (1 выводится предупреждающее сообщение "warning С499б: 'tmpfi1e': тш, function or variable тау Ье unеаЕе". Чтобы избежать этоrо сообще ния следует применятъ функцию t'"pf lle s ( 1 Прототип функции: #include <stdio.h> errno t tmpflle s(FILE **File); При успешн ом выполнении операции функция возвращает значение О, а в противном случае код ошибки. Пример использования функции t,"p f lle s ( 1 приведен в листинrе 12. б. I .1IИСТIПП 12.6. Создnние вpe"IOIoro фn ЙJm #include <iostream> #include <cstdio> #inc1ude <cstd1ik> int ,"ain (1 std::FILE *fp = о; char buf[200] = {О{, *pch = о; if (t'"pfl1e s (& fp 11 11 Пр о ве р яем ус пешнос ть Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  19  1712.10 std: : perror (rr Error rr) ; std: : cin. get (1 ; std:: exit (11; std: : fputs (rrTest rr, fp); std: : ff1ush (fp 1 ; std: : rewind (fp 1 ; pch = std:: fgets (buf, 200, fp 1; if (pchl std::cout «buf «std::endl; std:: fc10se (fpl; std: : cin. get (1 ; return о; 11 ВЫВОДИМ сообщение 11 ВЫХОДИМ при ошибке // Записываем с тро ку // Сбрасываем буфер // Пер емещаем курсор в начало // СчИТЫВ9.ем строку / / Test 11 Закрываем файл. Файл будет 11 уд але н аВ'КIиа тиче с ки Вме СТО создания вpeMeHHoro файла можно сrенерировать уникальное название с помощью функции t'"pna," (1 , а затем создать файл обычным образом. Длина названия оrpаничена значением макроса L t,"p па," Прототип функции: #include <cstdio> char * t:mpnam (char * Buffer) ; Если произошла ошибка, то функция возвращает нулевой указатель. Сrенерированное название записывается в символьный массив Buf fe r. Если в параметре передан нулевой указ атель, ТО сrенерированное название размещается во внутреннем статическо м буфере, а ссылка на Hero возвращается в каче стве значения. Эш данные будут перез аписаны при следующе м вызове функции t'"pnam (1 . Пример использования функции: char buf[L t'"pnam] = {О{, *р = о; р = std::t'"pnam(bufl; if (рl std::cout «buf «std::end1; // Например, \s3g4. std::cout «L tmpnam «std::end1; // В vc++ 2010: 14 В VC++ при использ овании функции t'"pnam (1 выводится предупреждающее сообщение "warning С499б: 'tmpnam': тш, function or variable тау Ье unsafe". Чтобы избежать этоrо сообщения следует применятъ функцию t,"p па,"  s ( 1. Пр ототип функции: # include <stdio. h> Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  20  1712.10 errno t tmpnams(char *Buf, rsize t Size); При успешн ом выполнении операции функция возвращает значение О, а в противном случае код ошибки. Сrенерированное название сохраняется в символьном массиве Ви f, максимальный размер KOToporo указывается в параметре S ize. Длина названия оrpаничена значением макроса L tmp пат  s Пример: char buf[L t,"pnams] = {О{; if (tmpnams(buf, L tmpnamsl == 01 std::cout «buf «std::endl; // Например, \s3i4. std::cout «L tmpnams «std::endl; // в vc++ 2010: 18 Кроме перечисленных функций, в VC++ дЛЯ reHep ации названия BpeMeHHoro файла можно воспользовать ся функцией te,"p па," ( 1 . Прототип функции: #include <stdio.h> char * tempnam(const char *DirName, const char *FilePrefix); В первом параметре указ ывается путь к кат ал ory , который будет использоваться если переменная окруж ения ТМР не определ ена или содержит некорректный путь. Если переменная ТМР корректна, то будет использоваться ее значение. В о втором параметре указыв ается префикс. Функция динамически выделяет под название необходимый объем памяти с помощью функции ,"a11oc (1 и возвращает указатель на Hero. Обратите внимание на то, что ответственность за освобождение дина:мической па:мяти лежит на плечах проrpаммиста. Поэто му после использования па:мяти следует обязательно вызвать функцию fre е ( 1 и передать ей указатель. В случае ошибки функция возвращает нулевой указатель. Пример использования функции: char *р = tempnam (rrc: \ \bookrr, rrt:mp rr); if (рl std::cout «р «std::endl; // Например, C:\DOCUМEl\user\LOCALSl\Te,"p\t,"p 2 std::free(p); 11 Освобождаем память!!! ПfllfШ1ЩlаВЛflШf ввода/вьшода Потоки ввода/вывода на консоль аналоrичны потокам ввода/вывода в файл. При запуске проrpаммы автоматически открываются три потока: -+ st din  стандартный ввод; -+ stdout  стандарный вывод; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  21  1712.10 -+ stderr  стандартный вывод сообщений об ошибках. Ве е эш идентификаторы являются файловыми указ ателями, связанными по умолчанию с ОКНОМ консоли. Следовательно их можно указывать вместо обычных файловых указ ателей в функциях, предназначенных для работы с файлами. Например, вывести строку в ОКНО КОНСОЛИ можно так: std: : fputs (rrStr ingl \ nStr ing2 rr, stdout); std::ff1ush(stdoutl; Ввод символа выполняется следующим образом: char ch = std::fgetc(stdinl; Стандартные потоки можно перенаправить таким образом, чтобы данные записывались в файл или считывались из файла. Для этоrо существуют два способа: -+ перенаправить из командной строки. В этом случае ничеrо в проrpамме менять не нужно. Чтобы выполнить перенаправление вывода в файл следует в командной строке выполнить одну из команд: test. ехе > file. txt test.exe » file.txt Первая строка записывает результат выполнения проrpаммы te st . ех е В файл f i1e . tx t. Если файл не суще ствует, то он будет создан, а если существует, то он буд ет перезаписан. Вторая строка производит дозапись в конец файл а. Чтобы ввести в проrp амму данные из файла следует выполнить команду: test. ехе < file. txt -+ перенаправить с помощью функции f reo ре n ( 1 . Прототип функции: #include <cstdio> F ILE * f re ар еn (со ns t char * F ile пате, со ns t char *Mode, FILE * File) ; Первые два параметра аналоrичны параметрам функции fop en (1. Пример перенаправления стандартноrо вывода в файл: std:: FILE *fp = о; fp = std:: freopen (rrfile. txt rr, rrw rr , stdout); if (' fp 1 std:: ех it ( 11 ; std: : printf (rr %s\ n rr , rrПJШJем В файл! rr) ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  22  1712.10 в VC++ при использовании функции f reo ре n (1 выводится предупреждающее сообщение "warning С499б: 'freopen': тш, function or variable тау Ье unsafe". Чтобы избежать этоrо сообщения следует применятъ функцию f reo ре n s (1 Пр ототип функции: #incl ude <st dio. h> errno t freopens (F ILE **F ile, const char *Filename, const char *Mode, FILE *OldFile); Первые три параметра аналоrичны параметрам функц ии fo ре n  s (1. Пример использования функции f reo ре n s (1 std:: FILE *fp = о; if (freopen s (&fp, rrf ile. txt rr, rrw rr , stdout) != О) std: :exit(ll; std: : printf (rr %s\ n rr, rrПJШJем В файл! rr) ; ВВОД/ВЬШОД II;lПIШllfШIЫХ {'U]'IШОЛОВ И fЧ1ОК Функции для ввода/вывода расшир енных символов и строк являются аналоrами функций, предназначенных для ввода/вывода обычных символов и строк В названии таких функций добавляется буква "w", например, расширенная функция fputwc (1 является аналоrом функции fpu tc (1 . Кроме Toro, изменяется знач ение, возвращаемое при ошибке. В место значения макроса EOF возвращается значение макроса WEOF. Определение макро са выrлядит так: #def ine WEOF (wint t 1 (OxFFFF 1 Прежде чем использовать расширенные функции необходимо настроить локаль и подключить з arоловочные файлы cstdio и cwchar: #include <cstdio> # inc 1 ude < cwchar > Некоторые обычные функции Moryт работать как с потоками обычных символов, так и с потоками расширенных символов, например, функции fc 10 se (1, fwr it е (1 , fread (1 , ff1ush (1 , rewind (1 , feof (1 , ferror (1 , c1earerr (1 , а также функции для работы с файлами произвольноrо доступа. Назв ания обычных функций и прототипы соответствующих им расширенных функций приведены в табл. 12.1. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  23  1712.10 Таблица 12.1. Фующии для ееода/еыеода расшupеюiЫХ сuмеолое u строк ООЫЧlC)Я ф)"НКЦИЯ ПI'ОТ ОТИП l' сппq)IOIОЙ Ф )"НlЩIOl р" OOT С КО НСОЛЪЮ putcharQ wintt putwchar(wchart Ch); putsO int utws(const wchart *Str); рrinЩ) in t wprinЩ с оnе! wchar  t *F оrшa t, ...); getchar() win!  t getwchar( VO id); getS() wchar  t * getws( wchar  t *В uf); есanЮ in t wscanf\ соnе! wchar  t *F ormat, ...); есanС е() in t wscanC е( с оnе! wchar  t *F ormat, ...); OTKI'ЪТf и<' Ф йm fop en() F!LE * wfopen(const wchart *Filename, соnе! wchart *Мойе); fopens() erшо! wfopens(F!LE **Не, соnе! wchart *Filename, соnе! wchart *Мойе); jj-eo р en() F!LE *wfreopen(const wchart *Filenarne, const wchart *Мойе, F!LE *OIdFile); jj-eopens() erшо  t  wfreop en  s(F! LE * *Н е, соnе! wchar  t *F il enaте, соnе! wchart *Мойе, F!LE *O!dFile); '3 IШСЪ В фйп и ЧТ<'НИ<' из Ф йm fputc() wintt fputwc(wchart Ch, F!LE *File); putcO win!  t putwc( wchar  t Ch, F! LE *Н е); fput';) int fputw';const wchart *Str, F!LE *FiIe); fprinЩ) in t fwprinЩF !LE *F iIе, с onst wchar  t *F ormat, ...); fgetcO win!  t fgetwc(F !LE *Н е); getcO win!  t getwc(F !LE *Н е); fgetsO wchar  t * fgetws( wchar  t * D st, int Siz е!n W о rds, F !LE *F iIе); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  24  1712.10 fs сanЮ int fwscanf\FILE *File, соnе! wchart *Format, ...); fscanCsO int fwscanC>(FILE *FiIe, соnе! wchart *Format, ...); РЗlЮ р error() vo id  wp error( с оnе! wchar  t *ErrM s g); renarne() in t  wrenarne( с оnе! wchar  t * OIdF iIenarn е, соnе! wchart *NewFiIenarne); remove() in t  wremove( с оnе! wchar  t *F il enaте) ; tmpnam() wchart *wtmpnam(wchart *Buffer); tmpnarn  е() erшо! wtmpnarns(wchart *Buf, еше! Size); tempnam() wchar  t *  wtempnam( с оnе! wchar  t *D irectory, соnе! wchart *FilePrefix); в VC++ в функциях wf ор en (1 и wf ор en s (1 параметр Mode может содержать опцillO ccs, которая задает кодировку файла. Опция принимает значения UN ICOD Е, UTF  8 или UTF  16L Е. Если указ ан а опция UTF  8 или UTF  16LE, то файл создается в соответствующей кодировке и в начало файла вставляются служебные байты, сокращенно называемые ВОМ (Вyte Order Mark, метка порядка байтов). Если открываемый файл содержит ВОМ, то значение, указанное в опции ccs иrнорируется. При отсутствии опции с cs автоматическое определение кодировки файла по ВОМ не производится. В каче стве при мера созд адим файл в кодировке UТF  1 БLЕ, запишем строку, а затем выведем каждый символ и ero код (листинr 12.7). Обратите внимание на то, что первым символом является ВОМ. .1IИСТIПП 12.7. Создние и чтние фЙJШ в ко диI' OBK UТF  16 LE #include <iostream> #include <cstdio> #inc1ude <cstd1ik> #include <clocale> #include <cwchar> int ,"ain (1 std: : setlocale (LC  ALL, rrRussian  Russia. 1251 rr) ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 ii  25  171 2.10 std::FILE *fp = о; wchart wch = о; if (v.:rfopens (&fp, Lrrfile. txt rr , Lrrv.:t+, ccs=UTF 16LE rr ) != О) wperror (LrrОшибка rr ); std::getwchar(l; std: : exit (11 ; std::fputws(L rr Stringl\nCTpoKa2 rr , std: : ff1ush (fpl ; std:: rewind (fpl; wch = std:: fgetwc (fp 1 ; while (' std: : feof (fpll { if (std:: ferror (fp 11 fp); 11 Записываем строку // // Пе р емещаем кур со р в начало файла Считываем один символ 11 Пр о ве р яем наличие ошиб о к wperror (LrrОшибка rr ) ; std::getwchar(l; std: : exit (11 ; wprintf (Lrr%c (%Щ \nrr, wch, (int) wch) ; wch = std::fgetwc(fp); 11 Считываем ОдИН символ if (std::fc1ose(fpll wprintf (L rrОшибка при закрытии фаЙJ1а\ n rr ) ; std::getwchar(l; return о; Ввод/вывод данных в языке С++ Система ввода!вывода языка С++ является обь ектноориентированной и по умолчанию синхронизируется с потоками языка С. Поэтому в одной проrpамме можно одновременно использовать обе системы. Тем не менее стоит отдать предпочтение только системе ввода/вывода языка С++. Система ввода/вывода языка С++ состоит из иерархии шаблонных классов, которые позволяют работать как с обычными символами, так и с расширенными. Пер архия наследования для ввода данных выrлядит так: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  26  1712.10 ios base  basic ios  basic istream  basic ifstream Иерархия наследования для вывода данных: ios base  basic ios  basic ostream  basic ofstream Иерархия наследования для ввода и вывода данных: ios base  basicios  (basic istream, basic ostream)  basic iostream  basic fstream Классом BepXHero уровня является шаблонный класс io s base. Шаблонный класс baS1C 10 s наследует класс 105  Ь as е В СБОЮ очередь класс bas ic ios является базовым ДЛЯ шаблонных классов basic is t re ат И bas ic  о st r еат, которые предназначены ДЛЯ работы с консолью. Для использования ЭТ1lХ классов необходимо ПОДКЛЮЧИТЬ з arоловочный файл io stre ат: # include <iostream > Для удобства использования шаблонных кл ассов в зarоловочном файл е определяются более короткие имена с помощью оператора t ур edef: typedef basic istream< typedef basic ostream< typedef basic iostream< typedef basic istream< wchar t, char traits<wchar t> > wistream; typedef basic ostream< wchart, char traits<wchar t> > wostream; typedef basic iostream< wchar t, char traits<wchar t> > wiostream; Объект cin, предназначенный для ввода обычных символов с кл авиатуры, является экз емпляром класса is tr еат, а объекты сои t, се rr И с10 g, позволяющие вывести обычные символы в окно консоли, являются экземплярами кл асса os tr еат. Объект wc in, предназначенный для ввода расширенных символов, является экземпляром класса wist re ат, а объекты wco ut, wc err И wc 10g, позволяющие вывести расширенные символы, являются экземплярами класса wos tr еат. Объекты cin, сои t и се rr мы уже рассматривали в maee 1, а объекты wcin и wc out в maee б. В этой rлаве мы расс мотрим работу с файл ами, а такж е фор матированный вывод Д анных. Большинство операций с консолью в языке С++ выполняется аналоrичным образом. char, char traits<char> > istream; char, char traits<char> > ostream; char, char traits<char> > iostream; KТIaccы basic  ifsh'fШП, basic оfsh'fШП и bask fsh'fШП Классы bas ic ist r еат И basic os tr е am являются баз овыми для шаблонных классов basic if s tr е am И Ь as ic о fs t re am соотвеТС1Бенно. Класс basic if s tr еат   предназначен для чтения данных из файла, а класс bas ic  о fs t re ат  для записи данных в файл. Кроме Toro, существует шаблонный клас с Ь as lC f st r еат, который Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  27  1712.10 позволяет как читать из файла, так и записывать в файл. Прежде чем использовать кл ассы Ь as ic  i fst re ат, basic ofs tr еат и Ь as ic f str еат необходимо ПОДКЛЮЧИТЬ зarоловочный файл fstream: # include <fstream > Для удобства использования шаблонных кл ассов в зarоловочном файл е определяются более короткие имена с помощью оператора t ур edef: typedef basic ifstream< char, char traits<char> > ifstream; typedef basic ofstream< char, char traits<char> > ofstream; typedef basic fstream< char, char traits<char> > fstream; typedef basic ifstream< wchar t, char traits<wchar t> > wifstream; typedef basic ofstream< wchart, char traits<wchar t> > wofstream; typedef basic fstream< wchar t, char traits<wchar t> > wfstream; В последующих при мерах мы будем рассматривать только классы для работы с обычными строками. Работа с расширенными строками выполняется аналоrично. При создании экземпляра класс а чаще Bcero используются два формата: <Класс> <Переменная >; <Класс> <Переменная> « :путь к фsLйлу> [, <Режим >[, <Блокировка>]]); Назв ание клас са зависит от необходимой операции с файлом: -+ if st re am  только чтение; -+ of st re am  только запись; -+ fs tr еат  одновременно и чтение и запись. При использ овании первоrо формата вызывается конструктор по умолчанию. В этом случае создается объект потока не связанный ни с каки м файлом. Чтобы связать объект с конкретным файл ом следует вызвать метод о ре n ( 1 . Пример : std::ofstream file; 11 Объект для записи в файл Второй формат позволяет при создании экз емпляра класса сразу связать поток с конкретным файлом. В первом параметр е указ ыв ается путь к Ф айлу. Путь может быть абсолютным или относительным. При использовании абсолютноrо пути следует уч итывать, что слэш необходимо обязательно удваивать: std: : ofstream f ile ("С: \ \book \ \ f i1e. txt" 1 ; При указании относительноrо пути полный путь определяется с учето м местоположения текущеrо рабочеrо каталоrа. Обратите внимание на то, что текущий рабочий каталоr не всеrда совпадает с каталоrом, в котором находится исполняемый Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  28  1712.10 файл. При запуске из редактора VC++ текущи м рабочим каталоrом будет каталоr проекта, а не каталоr, в котором нахОДИТСЯ исполняемый файл. Если файл запускается с помощью двойноrо щелчка на значке, то каталоrи будут совпадать. Если же файл запускается из командной строки, то текущим рабочим каталоrом будет каталоr, из KOToporo запускается файл. Способы указания относительноrо пути мы рассматривали при изучении системы ввода/вывода в языке С Примеры : std: : ofstream f ile 1 (rrf ile. txt rr) ; std: : ofstream f ile2 (rr . . \ \ f ile. txt rr) ; std: : ofstream f ile3 (rrfolder 1 \ \ f ile. txt rr) ; Путь может быть Сстрокой, расширенной строкой ипи объектом классов string и ws tr ing. Пример: std: : ofstream f ile 1 (rrf ile. txt rr) ; 11 std: : ofstream f ile2 (L rrf ile. txt rr); 11 std::string path(rrfile.txt rr ); std::ofstream file3(pathl; std: : wstr ing wpath (L rrf ile. txt rr) ; std::ofstream file4(wpath); 11 Экземпляр класса wstring Параметр <Р ежим> зад ает режим открытия файла. Если параметр не указан, то ИСПОЛЬЗJ'lOТСЯ слеДJ'lOщие режимы по умолчанию: CCTpOKa Расширенная с тро ка 11 Экземпляр класса string -+ if st re am  ios : : in  файл открывается только на чтение в текстовом режиме. После открытия файла кур сор устанавливается на начало файла. Если файл существует, то содер жимое файла не уд аляется. Если файл не существует, то устан авливается фл ar io s: : f ailbi t; -+ of st re am  ios : : ои t  файл открывается только на запись в текстовом режиме. Если файл не существует, то он будет создан. Если файл существует, то он буд ет перезаписан. После открытия файла курсор устанавливается на начало файл а; -+ fs tr еат  ios: : in I ios:: ои t  файл открывается одновременно на чтение и запись в текстовом режиме. После открытия файла курс ор устанавливается на начало файла. Если файл не существует, то устанавливается фл ar ios: : f ai1bi t. Если файл суще ствует, то содержимое файла не удаляется. В параметре <Режии> можно указать следующие значения (обычно их ко мбинацию через оператор 1): -+ io s : : in  файл открывается для чтения. Если файл существует, то содержимое файл а н е уд ал яется; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  29  1712.10 -+ io s : : ои t  файл открывается для записи. Если файл суще ствует, то содержимое файл а стир ается; -+ io s : : tr ипс  если файл существует, то ero содержимое стирается. Режим используется по умолчанию, если установлен режим ios : : о ut, а режимы ios : : in, ios: : арр или ios: : ate не указаны; -+ io s : : ар р  запись производится в конец файла, даже если указ ана дрyrая позиция с помощью метода see kp (1 ; -+ io s : : at е  при открытии файл а кур сор устанавливается на конец файла. Запись производится в текущую позицшо курс ора, а не обязательно в конец файла как в режиме ios: : арр; -+ io s: : Ь inar у  файл открывается в бинарном режиме. используется текстовый режим. В текстовом режиме при чтении удален, а при записи наоборот добавлен. Рассмотрим несколько примеров. Вначале откроем существующи й файл для чтения в текстовом и бинарном режимах: По умолчанию символ \ r будет 11 Те:кс то ВЫЙ режим чте ния std:: ifstream file 1 (rrfile . txt rr, std:: ios: : in); 11 Бинарный режим чтения std: : ifstream file 2 (rr f ile . txt rr, std:: ios : : in I std:: ios : : binary) ; В этом случае если файл не существует, то устанавливается флаr ios:: f ai1bi t. Теперь открое м файл на запись с удал ением сод ержимоrо: 11 Текстовый режим записи std: : ofstream f ile 1 (rrf ile. txt rr, std:: ios: : out) ; 11 Бинарный режим записи std: : ofstream f ile2 (rrf ile. txt rr, std:: ios: : out std: : ios: : binary) ; В этом случ ае если файл не суще ствует, то он будет автоматически создан, а если суще ствует, то ero содержимое удаляется. Пример дозаписи в конец файла: 11 Текстовый режим дозаписи std:: ofstream file 1 (rrfile . txt rr, std:: ios: : out I std:: ios: : арр); 11 Бинарный режим дозаписи std: : ofstream f ile2 (rrf ile. txt rr , std::ios::out I std::ios::app I std::ios::binary); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  30  1712.10 При использовании режима доз аписи, если файл не существует, то он автоматически создается. Содержимое существующеrо файла не удаляется. Запись производится в конец файла. Теп ерь откр оем файл на ввод и вывод одновременно: 11 Те кс то ВЫЙ р е;:ю.rм ввод а и ВЫВОД а std: : fstream f ile 1 (rrf ile. txt rr, std:: ios: : in I std:: ios: : out) ; 11 Бинарный ре;:ю.rм ввода ИВЫБОда std: : fstream f ile2 (rrf ile. txt rr , std::ios::in I std::ios::out I std::ios::binary); В этом случае при отсутствии файла устанавливается флаr io s: : f ai1bi t. Содержимое суще ствующеrо файла не удаляется. По сле открытия файла курс ор устанавливается на начало файла. Запись производится в текущую позицию курсора. Обратите внимание на то, что после чтения из файла необходимо переместить курсор прежде чем записывать в файл, иначе данные записаны не будут. Необязательный параметр <Блокир овка> задает режим доступа, который будет использоваться после открытия файла. Блокировка снимается после закрытия файл а. В параметре MOryT быть указ аны следующие макросы (определены в зarоловочном файле share. h) или их значения: -+ SH DENYRW  Ох 1 О  друrие потоки не Moryт одновременно читать из файл а и записывать в файл, пока файл не буд ет закрыт; -+ SH DENYWR  Ох 2 О  дрyrи е потоки MOryт одновременно читать из файла, но не MOryT записывать в файл; -+ SH DENYRD  О х3 О  дрyrи е потоки не Moryт одновременно читать из файла, но MOryT записывать в файл, если файл был открыт ранее; -+ SH DENYNO  Ох 40  дрyrие потоки Moryт одновременно читать из файла и записывать в файл (значение по умолчанию). Пример открытия файла на запись в текстовом режиме с запретом ввода и вывода для друrих потоков: #include <fstream> #include <share.h> 11 ... Фрarмент опущен std: : ofstream file (rrfile. txt rr , std:: ios: : out, SHDENYRW) ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  31  1712.10 ОТКIIЬПИf И заКIIЬПИf файла Открыть файл файл можно сразу при создании объ екта, передав конструктору путь к Ф айлу. Этот способ мы рассматривали в предыдуще м разделе. Если при создании объекта использовался конструктор по умолчанию, то открыть файл можно с помощью метода оре n ( 1 . Прототип метода: void ореn«Путь к файлу>[, <Режим>[, <Блокировка>]]); Предн азн ачение всех парамеТРОБ совпадает с предназначением парамеТРОБ конструктора. Пример открытия файла на запись: std::ofstream file; file. ореn (rrfile. txt rr ) ; Этот код эквивалентен следующему коду. std: : ofstream f ile (rrf ile. txt rr) ; Если файл открыть не удало сь, то устанавливается фл ar оши бки для потока и rло6альной переменной е rrno присваивается КОД ошибки. Проверить успешность открытия файла можно следующим образом: std: : ofstream f ile (rrf ile. txt rr) ; if (! file) std:: cout « rrИе удалось открыть файл rr « std:: endl; Проверить открыт файл или нет позволяет такж е метод lS ор en (1 . Если файл открыт, то метод возвращает значение tr ие. Прототип метода: bool isopen() const; Пример проверки: lf (file .15 ореn ()) std:: cout « rrФайл открыт rr « std:: endl; Для закр ытия файла предназначен метод close 11. Если файл закрыть не удалось, то устанавливается флar ошибки для потока и rло6альной переменной err по присваивается код ошибки. Прототип метода: void close () ; в каче стве при мера откроем файл на запись в текстовом режиме и запишем в Hero две строки, разделенные символом \ n (листинr 12.8). Файл блокируем на чтение и запись. .1IИСТIПП 12.8. Обрnботкn ошибок при ОТкрЫТIШ фnЙJШ #include <fstream> #include <iostream> #inc1ude <cstd1ik> Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  32  1712.10 #include <share.h> #include <cstring> void prlllt error(lnt err); int ,"ain (1 std::ofstream file; file. ореn (rrfile. txt rr , std:: ios: : out, SHDENYRW) ; lf (Iflle) prlllt error(errno); file « rrStringl \nString2 rr; file. flush (1 ; lf (file .15 ореn ()) std:: cout « rrOpenrr « std:: endl; else std:: cout « rrClose rr « std:: endl; file. c10se (1 ; lf (file .15 ореn ()) std:: cout « rrOpenrr « std:: endl; else std:: cout « rrClose rr « std:: endl; std: : cin. get (1 ; return о; // Open / / C10se void prlllt error(lnt err) char str[200] = {О{; strerror  s (str, 200, err); std::cout « rrError: rr «str «std::endl; std: : cin. get (1 ; std: : exit (11 ; Как видно из примера, для записи в файл можно использовать оператор «. Для ускорения работы производится буферизация записываемых данных. Информация из буфера записывается в файл полностью только в момент закрытия файла. Сбросить буфер в файл явным образом можно с помощью метода f 1 us h ( 1 . Прототип метода: ostream &flush(); '3аIШfЬ в файл и 'ПflШf из файла Для записи в файл предназначены следующие методы: -+ оператор « позволяет записать данные лю60rо типа. Пример: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  33  1712.10 int х = 250; do uk1e у = 12.5; char ch = I w I ; char str [] rrStringl\nString2 rr ; file « х « rr rr « у « rr rr « ch « rr rr « str; -+ ри t (1  записывает символ. Прототип метода: ostream &put(char Ch); Пример: char ch I w I ; fi1e. put (chl ; -+ wr it е (1  записывает объект в файл. Обратите внимание на то, что файл должен быть открыт в бинарном режиме. Прототип метода: ostream &write(const char *Str, streamsize Count); в первом параметре метод принимает символьный указатель. Чтобы передать объект следует выполнить приведение типа к char * Во втором параметре указывается размер объекта в байтах. Размер объекта следует определять с помощью оператора s ize of. В качестве примера запише м структуру в файл, открытый на запись в бинарном режиме: std: : ofstream file (rrfile. txt rr, std: : ios : : out I std:: ios: :binary) if ('filel std::cout « rrError rr « std: :endl; std: :exit(ll; struct Point int х, У; point; point. х 10; point.y 20; file.write( (char *)&point, sizeof(Point)) fi1e. f1ush (1; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  34  1712.10 file. close () ; Перечислим методы, предназначенные для чтения файла: -+ оператор » позволяет считать данные лю60rо типа. Про6ельные символы перед данными иrнорируются. Пример считывания одноrо символа: 11 Содержимое файла: rr \ t \ nSt r ing rr char ch; file » ch; std: : cout « ch « std:: endl; 11 Результат: I S I 06раште внимание на то, что считывание строки ПРОИЗВОДИТСЯ до первоrо пробельноrо символа (например, пробела, табуляции, символа перевода строки и т. д.). Пробельный символ удаляется из потока, но в строку не записывается. Чтобы считать строку определенной длины следует использовать методы ge t (1 или get1ine (1 ; -+ ge t (1  считывает один символ или строку определенной длины. В отличие от оператора » при считываниии символа про6ельные символы не иrнорирJ'lOТСЯ. Метод имеет несколько ПрОТОТИПОВ. Первый прототип: int get(l; Считывает один символ и возвращает ero код. Если достиrнут конец файла, то метод возвращает значение макроса EOF. Пример считывания символа: char ch = fi1e.get(l; std::cout « ch « std: :endl; Второй прототип: istream &get(char &Ch); Считывает ОДИН символ и записывает ero в переменнJ'lO, адрес которой передан в параметре. Если достиrнут конец файла, то в переменнJ'lO записывается значение макро са EOF и устанавливается флаr eofbi t. Кроме Toro, поток, связанный с файл ом, принимает значение f a1se. Проверить установку флarа позволяет метод ео f (1 . Прототип метода: bool eof () const; Метод возвращает значение tr ие, если достиrнут кон ец файла. В противном случае метод возвращает знач ение false. Пример считывания одноrо символа с проверкой корректности: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  35  1712.10 char ch; fi1e. get (chl ; 11 Ис поль 30 вание метод а е of () if (' fi1e. eof (11 std:: cout « ch « std:: end1; else std: :cout « rrEOF rr « std: :endl; 11 Проверка потока if (f ile) std:: cout « ch « std:: endl; else std: :cout « rrEOF rr « std: :endl; Третий прототип: istream &get(char *Str, streamsize Count); Считывает из файла строку длиной Count  1 символов. Если раньше встретится символ перевода строки или будет достиrнут конец файла, то считывание прекращается досрочно. Символ перевода строки остается в потоке. В конец строки записывается нулевой символ. Пример: char str[100] = {О{; fi1e. get (str, 501; std::cout « str « std::endl; Четв ерты й пр ототип : is tre ат &get (с har * St r, s tre ams iz е С оиn t, char De lim) ; Считывает из файла строку длиной Count  1 символов. Если раньше встретится символ De1im или буд ет достиrнут конец файла, то считывание прекращается досрочно. Символ De1im остается в потоке и доступен при следующей операции считывания. В конец строки записывается нулевой символ. Пример : char st r [ 10 О] = {О { ; file.get(str, 50, Igl); std::cout « str « std::endl; -+ ре ek (1  читает один символ из файла и возвращает ero код. Символ остается в потоке и доступен при следующей операции считывания. Прототип метода: lnt type peek (1 ; Пример: 11 Содержимое файла: rr St r ing rr Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  36  1712.10 char chl, ch2; ch1 = fi1e.peek(l; std::cout « chl « std::endl; ch2 = fi1e.get(l; std: : cout « ch2 « std:: endl; // s // s -+ ge t1ine ( 1 читает строку из файла. В отличие от тpenero и четвертоrо фор матов метода ge t (1 метод ge t1ine (1 считывает символоrpаничитель, а не оставляет ero в потоке. Символоrpаничитель не записывается в строку. Прототипы метода: istream &getline(char *Str, streamsize Count); is tre ат &get line (с har * S tr, st reamsi ze Со unt, с har Delim); Метод, соответствующий первому прототипу, считывает из файла строку длиной Со unt  1 СИМВОЛОВ. Если раньше встретится символ перевода строки или будет достиrнут конец файла, то считывание прекращается досрочно. Символ перевода строки считывается из потока, но не записывается в строку St r. В конец строки записывается нулевой символ. Пример: char str[100] = {О{; fi1e.get1ine(str, 501 std::cout « str « std::endl; Метод, соответствующий второму прототипу, считывает из файла строку длиной Со unt  1 СИМВОЛОВ. Если раньше встретится символ De lim или будет достиrнут конец файла, то считывание прекращается досрочно. Символ De lim считывается из потока, но не записывается в строку st r. В конец строки записывается нулевой символ. Пример: char str[100] = {О{; file. getline (str, 50, I 9 1) ; std::cout « str « std::endl; -+ igno re ()  считывает указ анное количество символов, но ниrде их не сохраняет. Прототип метода: is tre ат &ignor е (st r eamsi z е Со иn t= 1, ln t type Met adeli:m= EOF) ; Первый параметр задает максимальное количество считываемых символов (по умолчаншо один символ). Второй параметр задает символразделитель. Если символразделитель встреТ1lТСЯ раньше, чем будет почитано указанное количество Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  37  1712.10 СИМВОЛОВ, то считывание прекращается. В ЭТОМ случае символразделитель также считывается из потока. Пример: file.ignore(9, I\n l ); -+ re ad (1  считывает объект из файла. Обратите внимание на то, что файл должен быть открыт в бинарном режиме. Прототип метода: istream &read(char *Str, streamsize Count); в первом параметре метод принимает символьный указатель. Чтобы передать объект следует выполнить приведение типа к char * Во втором параметре указывается размер объекта в байтах. Размер объекта следует определять с помощью оператора sizeof. Нулевой символ в конец Str автоматически не вставляется. Если в файле меньше байтов, чем указано в параметре Со un t, то устанавливается флаr failk i t. Выполнить проверку установки фл аса можно с помощью метода fai1 ( 1 , а получить реальное количество считанных байтов позволяет метод gc оиn t () . Прототип метода gc ount (1 : st reamsi ze gc ount () const; Запишем структуру в файл, открытый на запись в бинарном режиме, а затем считаем с труктуру из файла и выведем значения (листинr 12.9). I .1IИСТIПП 12.9. Coxpnнe ине с тр)']( Т)l' ы в фnйл #include <fstream> #include <iostream> #inc1ude <cstd1ik> #include <cstring> struct Point int х, У; } point; void prlllt error(int err); int ,"ain (1 std: : fstream f ile (rrf ile. txt rr, std:: ios: : in I std:: ios: : out I std::ios::trunc I std::ios::binary); if (!file) prlllt error(errno); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  38  1712.10 point. х = 10; point.y = 20; file.write((char *)&point, sizeof(Point)); 11 Записываем структуру file. flush (1 ; f ile. seekg (О, std:: ios: : beg); 11 Перемещаем указатель в начало point.x = о; point.y = о; file.read((char *)&point, sizeof(Point)); 11 Считываем структуру std::cout «point.x «std::endl; 11 10 std::cout «point.y «std::end1; //20 file. c10se (1 ; std: : cin. get (1 ; return о; void prlllt error(lnt err) char str[200] = {О{; strerror s (str, 200, err); std::cout « rrError: rr «str «std::endl; std: : cin. get (1 ; std: : exit (11 ; { в качестве еще одноrо примера запишем строку в файл, а затем произведем п осимвольное считывание (листинr 12.1 О). I .1IИСТIПП 12.10. Посиmолыюе счпrывnние из фnй:rm #include <fstream> #include <iostream> int ,"ain (1 char ch О' , std: : fstream f ile (rrf ile. txt rr, std:: ios: : in I std:: ios: : out std::ios::trunc); if ('filel std::cout « rrError rr «std::endl; std: : cin. get (1 ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  39  1712.10 return 1; file « rrStringl \nString2 rr; file. flush (1 ; file.seekg(O, std::ios::beg); while ('fi1e.get(chl.eof(11 std: : cout « ch « rr (rr « (int) ch « rr) rr « std:: endl; file. c10se (1 ; std: : cin. get (1 ; return о; о бр атите вн и мани е н а этот Ф р асм е НТ: while ('fi1e.get(chl.eof(11 std: : cout « ch « rr (rr « (int) ch « rr) rr « std:: endl; Символы из файла считываются до тех пор, пока не будет достиrнут конец файла. В этом случае метод ео f (1 вернет значение t rue. Так как метод get (1 возвращает ссылку на поток, можно составить цепочку из вызовов методов и сразу после считывания символа проверить достиrнут ли конец файла. При достижении конца файла поток принимает значение fa1se. Следовательно предыдущий фраrмент можно записать еще проще: while (f ile. get (chll std: : cout « ch « rr (rr « (int) ch « rr) rr « std:: endl; Некоторые считанные символы можно вернуть в поток Обратите внимание, именно вернуть в поток, а не запис ль в файл. Этот символ будет доступен при следующей операции чтения. Вернуть последний считанный символ позволяет метод unget () . Прототип метода: istream & unget () ; Для примера считаем первый символ, выведем ero, а затем вернем ero в поток Далее прочитаем строку из файла и выведем ее: 11 Содержимое файла: rrStr ingl \ nStr ing2 rr char str[ 100] = {О{, ch = о; ch = file. get (1 ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  40  1712.10 std::cout «ch« std::endl; 11 S file. unget (1 ; f ile. getline (str, 50); std::cout «str «std::endl; 11 Stringl Вернуть произвольный символ в поток можно с помощью метода р utb ack (1 . Прототип метода: istream &putback (char Ch); Пример: 11 Содержимое файла: char str[ 100] = {О{, ch = file. get (1 ; std::cout «ch« std::endl; file.putback( 1;з 1); f ile. getline (str, 50); std::cout «str «std::endl; rrStr ingl \ nStr ing2 rr ch = о; // s // string1 Файлы ЩIоизвольноrо доступа Файл можно читать не только с caMoro начала, НО и с произвольной позиции. Как правипо в этом случ ае файл открывают в бинарном режиме. Записывать в файл также можно с произвольной позиции. Для работы с файлами произвольноrо доступа предназначены следующи е методы: -+ te 11g ( 1 и te 11p (1  возвращают позицию соответствующеrо курсора относительно начала файл а. При ошибке возвращается значение  1. Метод t e11g (1 возвращает позицию курсора чтения, а te11p (1  позицию курсора записи. Прототипы методов: pos type te11g (1 ; pos type te11p (1 ; Пример: std: : ifstream file (rrfile. txt rr, std: : ios: : in I std:: ios: : binary) ; if (! file) return 1; std: : cout « f i1e. te11g (1 «std:: end1; / / О char ch = fi1e.get(l; std::cout « ch « std: :endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 ii  41  171 2.10 std: : cout « f i1e. te11g (1 «std:: end1; / / 1 file. close () ; -+ se ekg ( 1 и see kp (1  устанавливают соотвествующие кур соры в позицшо, имеющую смещение Off se t относительно позиции Or igin, или в ПОЗИЦИЮ Ро s относительно начала файла. Метод se ekg (1 устанавливает позицшо курсор а чтения, а seekp (1  позицшо курсора записи. Прототипы методов: istream &seekg(pos type Pos); is tre ат &5 ее kg (о ff typ е Offs et, ios:: se ekdir Or igin) ostream &seekp(pos type Pos); 05 tre ат &5 ее kp (о ff typ е Offs et, ios:: se ekdir Or igin) В параметре Or igin MOryт быть указ аны следующие значения: . ios: :beg  начало файла; . io s : : с ur  текущая позиция курс ора; . io s : : е nd  конец файла. Считаем из файла вначале пятый символ, дале е первый символ, а затем последний с имвол и выведем их в окно консоли (листинr 12.11). I .1IИСТIПП 12.11. Ф nйлы пр ОIfЗволъноrо до сr)'ШI #include <fstream> #include <iostream> int ,"ain (1 char ch о. , std: : ifstream f ile (rrf ile. txt rr, std:: ios: : in I std:: ios: : binary) ; if ('filel std::cout « rrError rr «std::endl; std: : cin. get (1 ; return 1; file.seekg(4, std::ios::cur); 11 П=ремещаем курсор относительно 11 текущей позиции ch file.get (1; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  42  1712.10 std: : cout « ch « std:: endl; file.seekg(O, std::ios::beg); 11 П=ремещаем курсор в начало ch = fi1e. get (1 ; std::cout «ch« std::endl; file.seekg(l, std::ios::end); 11 П=ремещаем курсор в конец ch = fi1e. get (1 ; std::cout «ch« std::endl; file. c10se (1 ; std: : cin. get (1 ; return о; ПI1ОВfllЮl состояния потока После кажд ой операции с потоком прОИЗВОДИТСЯ установка одноrо из фл arOB: -+ io s: : goo db i t  ошибок нет; -+ io s: : е ofbi t  достиrнут конец файл а; -+ io s: : f ailk i t  последняя операция окончил ась неудачей. Посл е сброса флаrа поток rOTOB к дальнейшим операциям; -+ io s: : Ь adbi t  критическая ошибка в потоке. Проверить состояние фл асов позволяют следующие методы: -+ rdst at е (1  возвращает текуще е состояние потока. Вместо метода rdst at е ( 1 удоб нее использ овать методы go od ( 1 , eof (1 , fai1 (1 и ь ad ( 1 . Прототип метода: iostate rdstate () const; Проверить успешность выполнения операции можно следующим образом: if (f i1e. rdstate (1 == std:: ios: : goodbit 1 std: : cout « rrgoodbit rr « std:: endl; Проверка остальных флarов ПРОИЗВОДИТСЯ с использованием побитовых операторов. Например, проверить, достиrнут ли конец файла, можно так: if (( int 1 fi1e. rdstate (1 & (intl std: : ios: : eofbit 1 std::cout « rreofbit rr « std::endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  43  1712.10 -+ go od ()  возвращает значение true, если установлен флar ios:: go odb it, и false  в противном случае. Прототип метода: Ьооl good () const; -+ ео f (1  возвращает значение true, если достиrнут конец файла, и fa1se  в противном случае. Прототип метода: Ьооl eof () const; -+ fail ()  возвращает значение true, если установлен флar ios:: failb it, и false  в противном случае. Прототип метода: Ьо 01 fail () const; Проверить установку флаrа ios:: fai1b it можно также указав поток внутри лоrическоrо выражения в операторе ветвления. Если фл ar установлен, то поток буд ет иметь значение fa1se. Пример проверки: if ('filel std: : cout « rrfailbit rr « std:: endl; Обратите внимание на то, что в VC++ флаr ios: : failk i t устанавливается также при достижении конца файла вместе с флarом ios: : ео fb i t. Поэто му поток будет иметь значение f als е не только в случае ошибки; -+ bad (1  возвращает значение true, если установлен флаr io s: : Ь adb it, и false  в противном случае. Прототип метода: Ьооl bad() const; Установить флаr из проrp аммы позволяет метод se ts ta te (1 . Прототип метода: void setstate(iostate State, Ьооl Reraise = false); Пример проверки и установки флarа ios : : fai1b it: if (file. fail ()) std:: cout « rrfailbit rr « std:: endl; else std:: cout « rrио failbit rr « std:: endl; file.setstate(std::ios::failbit); if (file. fail ()) std:: cout « rrfailbit rr « std:: endl; else std:: cout « rrио failbit rr « std:: endl; При установке флаrов старые фл arи не сбрасываются. Чтобы сбросить все флаrи ошибок следует вызвать метод с 1ear (1 без параметров. Прототип метода: void clear(iostate State = goodbit, bool Reraise = false); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 44  1712.10 Если в параметре S ta te указан флar, отличный от флаrа ios:: go odb it, то вместо сбрасывания флarа производится ero установка. Пример: file.clear(); 11 Сбрасываем все флarи ошибок file.clear(std::ios::failbit I std::ios::eofbit); 11 Устанавливаем флarи failbit и eofbit std::cout «file.good(1 «std::end1; //0 std::cout «file.eof(1 «std::end1; // 1 std::cout «file.fai1(1 «std::end1; // 1 std::cout «file.bad(1 «std::end1; //0 По умолчанию установка флarов происходит ех се pt io ns () позволяет включить rенерацию Прототипы метода: без rенерации исключения. исключения ДЛЯ зад анных Метод флarов. iostate exceptions() const; void exceptions(iostate Newexcept); Первый прототип возвращает флаrи, для которых включен режим rенерации исключения. Второй прототип устан авливает фл arи. При установке нескольких фл асов используется побитовый оператор 1. Объектом исключения является экз емпляр класса io s: : f ail ur е. Этот класс является наследником класса ех се pt io n, поэтому получить описание ошибки можно с помощью метода what ( ). в качестве примера включим rенерацию исключения для флarа io s: : f ailb i t и обработаем исключение (листинr 12.12). I .1IИСТIПП 12.12. ИсIЮЛЪЗОВnние "TOД<l exceptiolt'O #include <fstream> #include <iostream> #include <clocale> int ,"ain (1 std: : setlocale (LC  ALL, rr. 1251 rr) ; char ch = о; std::ifstream file; std::cout «file.exceptions() «std::endl; 11 о file.exceptions(std::ios::failbit); std::cout «file.exceptions() «std::endl; 112 try { Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  45  1712.10 f ile. ореn (rrf ile8 71. txt rr, std:: ios: : in I std:: ios: : binary) ; catch (std::ios::failure &err) std: : cout « rrИе удалось открыть файл rr « std:: endl; std: : cout « err. what () « std:: endl; std: : cin. get (1 ; return 1; file. c10se (1 ; std: : cin. get (1 ; return о; Если файла не существует или ero нельзя открыть на чтение, то результат будет следующим: о 2 Не уд ало с ь о ткрыть файл ios base: : failbit set KТIaccы basic ishUlgМl"f.аш, basic  оshUlgsh'fЮП и basic  sh'illgsh'fШП Классы baslc 15 tr lngs tr е am, Ь aS1C о st r lngs t re ат И Ь aS1C s tr lngst r еат позволяют работать со строкой, как с ПОТОКОМ. Класс Ь as lC 1st r lngs t re ат предназначен ДЛЯ чтения данных из строки, класс baS1C 05 tr lngs tr еат  ДЛЯ записи данных в строку, а класс Ь aS1C s tr lngst r еат позволяет как читать из строки, так и записывать в строку. Прежде чем использовать классы bas lC 1st r lngst r еат, baS1C 05 tr lngs tr е am И bas lC str lngs tr е am необходимо ПОДКЛЮЧИТЬ зarоловочный файл sstream: #include <sstream> Иерархия наследования для ввода данных выrлядит так: ios base  basic ios  basic istream  baslc lstrlngstream Иерархия наследования для вывода данных: ios base  basic ios  basic ostream  baslc ostrlngstream Иерархия наследования для ввода и вывода данных: ios base  basicios  (basicistream, basic ostream)  basic iostream  baslC str lngstream Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  46  1712.10 Для удобства использования шаблонных кл ассов в зarоловочном файл е определяются более короткие имена с помощью оператора t ур edef: typedef baS1C lstrlngstream<char, char traits<char>, allocator<char> > istr ingstream; typedef baS1C ostrlngstream<char, char traits<char>, allocator<char> > ostringstream; typedef baS1C strlngstream< char, char traits<char>, allocator<char> > stringstream; typedef baS1C lstrlngstream<wchar t, char traits<wchar t>, allocator<wchar t> > wlstrlngstream; typedef baS1C ostrlngstream<wchar t, char tralts<wchar t>, allocator<wchar t> > WQstrlngstream; typedef baS1C strlngstream< wchar t, char tralts<wchar t>, allocator<wchar t> > wstrlngstream; В последующих примерах мы будем рассматривать только классы для работы с обычными строками. Работа с расширенными строками выполняется аналоrично. При создании экземпляра класс а чаще Bcero используются четыре формата: <Класс> <Переменная>; <Класс> <Переменная>«Режим»; <Класс> <Переменная>«Сстрока>[, <Режим>]); <Класс> <Переменная>«Объект класса baslC strlng>[, <Режим>]); Назв ание клас са зависит от необходимой операции со строкой: -+ is tr ings tr е am  только чтение; -+ os tr ings tr е am  только запись; -+ st r ingst re ат  одновременно и чтение и запись. Параметр <Режим> задает режим открытия. Используются те же режимы, что и при работе с файлами. Если параметр не указ ан, то используются следующие режимы по умолчанию: -+ istr ingstream  ios: : in; -+ ostr ingstream  ios: : out; -+ str ingstream  ios: : in ios: : out. При использовании первоrо формата создается объект с режимом по умолчанию: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 47  1712.10 std::ostringstream str; str « rrStr ing rr; 11 Записываем строку std::cout «str.str() «std::endl; 11 String Второй формат позволяет указать режим открытия: std::ostringstream str(std::ios::out); str « rrStr ing rr; 11 Записываем строку std::cout «str.str() «std::endl; 11 String Тр етий формат копирует Ccтpoкy в объект: std: : ostr ingstream str (rrStr ing rr , std:: ios: : out I std:: ios: : ate) ; str « r'123 rr; std::cout «str.str(1 «std::end1; // string123 Четвертый формат копирует строку из экзе мпляра класса Ь aSlC s tr lng std: : str ing s (rrStr ingrr) ; std::ostringstream str(s, std::ios::out I std::ios::ate); str « r'123 rr; std::cout «str.str() «std::endl; std::cout «s «std::endl; // string123 // String Записать строку из экземпляра класса Ь as lC s tr lng после создания объекта, а также получить СтрОКОБое представление объекта позволяет метод str () . Прототипы метода: void str(const baslc strlng &Newstr); baslc strlng str() const; Первый прототип очищает содержимое объекта и записывает в Hero строку из экз емпляра класса Ь aS1C s tr lng Второй прототип возвращает экз емпляр класса baslc st r lng Пример std::strng sl, s2(rrHello rr ); std::ostrngstream str; str « rrstrngrr; std::cout «str.str() «std::endl; 11 Strng sl = str.str(); std::cout «sl «std::endl; 11 Strng str.str(s2); std::cout «str.str() «std::endl; 11 Hello Для записи в поток используется оператор «, а также методы put (1 и write (1 Чтение производится с помощью оператора », а также методов get (1 , get1ine (1 и Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  48  1712.10 re ad () . Кроме Toro, можно перемещаться внутри потока и проверять состояние потока. Вс е эти операторы и методы мы уже рассматривали при изучении работы с файлами, поэтому повторно их описывать не будем. Основные операции показаны в листинrе 12.13. -Тшст IПП 12.13. ОС НOB:ньre ОIrep;[щ= :при рnбот е со строк ОЙ, K;[IK С по TOKOI'rI #include <iostream> #include <string> #include <sstream> int ,"ain(1 { char s [50] int х = о; std::string 52(,rr,); std::stringstream str; str « rrString rr « 250; str . put ( I . I ) ; {О{, ch О' , str. write (rr аЬс rr, 4); std: : cout « str. str () « std:: endl; str.seekg(O, std::ios::beg); str » s » Х; std: : cout « s « std:: endl; std::cout «х «std::endl; ch = str. get (1 ; str.getline (5, 5, 'Ь ' ); std: : cout « ch « std:: endl; std::cout «s «std::endl; str . read (s, 1); s[l] = '\0'; std: : cout « s « std:: endl; str.seekg(O, std::ios::beg); while (' str . get (ch 1 . eof (11 std: : cout « ch « std:: endl; str . clear О ; 11 Записываем данные 11 Записываем символ 11 Записываем с тр о КУ // String 250. akc 11 С тавим курс о р в начало 11 Считываем данные / / String / / 250 11 Считываем с имво л 11 Считываем строку // // а 11 Считываем один символ 11 в с тавляем ну лево й с имво л // с 11 С тавим курс о р в начало 11 Посимвольное считывание 11 СчJoШ.lаем от ошиб о к Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  49  1712.10 52 = str. str () ; 11 Преобразуем в объект 11 класса str ing // String 250. akc std::cout «52 «std::endl; std: : cin. get (1 ; return о; С'ппъmаlШf ДaIПlЫХ ИJ БУФfllа Для ускор ения работы данные вначале помещаются в буфер. Коrда буфер заполнится ПРОИЗВОДИТСЯ ВЫВОД данных на консоль или в файл. При вводе данных из консоли нажатие кл авиши <Enter> приводит к считыванию данных в буф ер. Если количество введенных данных больше тpe6yeMoro количества, то лишние данные ОСТaIOТСЯ в буфере и доступны для последующих операций чтения. Например, считаем два символа: char chl = О, ch2 = о; std::cout « rrch1 = rr «std::flush; std: : cin » chl; std::cout «chl «std::endl; / / ВВОДИМ: ak // а std: : cout « rrch2 = rr « std:: flush; std::cin » ch2; 11 Считывается из буфера std::cout «ch2 «std::end1; // ь Если при вводе первоrо символа вместо одноrо символа ввести сразу два и нажать кл авишу <Enter>, то в буф ер запишутся три символа I а 1, I Ь I И I \ n 1. Символ I а I записывается в переменнJ'lO с hl, символ I Ь 1, не дожидаясь ввода пользователя, считывается из буфера и записывается в переменнJ'lO ch2, а символ 1\ n I остается в буфере. Результат выполнения примера в этом случае выrлядит так: ch1 = ak а сЫ = ь Если вводить символы отдельно, то результат будет друrим: ch1 = а а сЫ = ь ь Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  50  1712.10 Как видно из примера результаты ОТЛИЧaIOТСЯ. Это может запутать пользователя, если в первой операции ввода второй символ был введен случайно. Кроме Toro, символ I \ n I может стать причиной закрытия окна консоли, если задержка ВЫПОЛН.яrIась с ПОМОЩЬЮ инструкции: std: : cin. get (1 ; Проиrнорировать определенное количество символов, находящихся в буфере, позволяет метод ignor е ( 1 . Прототип метода: istream &ignore(streamsize Count=l, inttype Metadelim=EOF); Первый параметр задает максимальное количество считываемых символов (по умолчанию один символ). Второй параметр задает символразделитель. Если символ разделитель встретится раньше, чем 6уд ет почитано указанное количество символов, то считывание прекращается. В ЭТОМ случае символразделитель также считывается из потока. Перед елаем предыдущий пример и сделаем так, чтобы каждый раз считывалось только по одному символу: char chl = О, ch2 о; std::cout «rrch1 rr« std::flush; std: : cin » chl; std::cout «chl «std::endl; std: :cin.ignore (200, I\n l ); std: : cout « rrch2 = rr « std:: flush; / / ВВОДИМ: ak // а std: : cin » ch2; std::cout «ch2 «std::endl; std: :cin.ignore (200, I\n l ); Результат выполнения примера в этом случае выrлядит так: // // ь ВВОДИМ: Ь ch1 = ak а сЫ Ь Ь Число 2 О О в первом параметре метода igno re () является произвольным значением. Чтобы считать все символы, содержащи еся в буфер е, то можно воспользоваться методом reads оте ( ) . Прототип метода: streamsize readsome(char *Str, streamsize Count); В первом параметре передается указатель на символьный массив, в котором будут сохранены считанные символы, а во втором параметре задается количество символов. Нулевой символ в конец символьноrо массива автоматически не вставляется. Метод Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  51  1712.10 возвращает количество считанных символов или значение О, если символов в буфере больше нет. Переделам наш пример и используем метод r eads оте () вместо метода ignore (1 : char ch1 = О, сЫ = О, buf[5] = {О{; std::cout « rrch1 = rr «std::flush; std: : cin » chl; std::cout «chl «std::endl; while (std:: cin. readso,"e (buf, 511 {{ std: : cout « rrch2 = rr « std:: flush; / / ВВОДИМ: akcd // а std: : cin » ch2; std::cout «ch2 «std::endl; while (std:: cin. readso,"e (buf, 511 {{ Обратите внимание на инструкции, которые выводш под сказки пользователю. После вывода под сказки вызывается манипулятор f lush, который сбрасывает содержимое буфера. При использовании некоторых компиляторов буфер сбрасывается только после вывода символа I \ n I . Поэтому можно не дождаться вывода под сказки вовсе. Ч то6ы избежать этоrо следует сбрасывать буфер явным образом с помощью манипулятора f1ush: // // ь ВВОДИМ: Ь std::cout « rrch1 = rr «std::flush; или метода f 1ush (1 : std::cout « rrch1 = rr. , std::cout.f1ush(l; Вме сто вызова манипулятора f 1 ush или метода f 1ush (1 можно синхр онизировать потоки cin и со ut с помощью метода t ie ( ) . в этом случае прежде чем получать данные от пользователя будет автоматически произведен сброс буф ера объ екта с out. По умолчанию в VC++ потоки cin и cout синхронизированы. Прототип метода: ostream *tie(ostream *Newtie); Пример: char ch = о; std::cin.tie(&std::cout); std: : cout « rrch = rr; 11 Синхронизируем потоки std: : cin » ch; std::cout «ch« std::endl; / / ВВОДИМ: а // а Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  52  1712.10 Насч, ойка ЛОЮ1ЛИ дЛЯ потока Для каждоrо потока можно настроить СБОЮ локаль . По умолчанию ДЛЯ потоков настроена локаль С. Что бы настроить дрyrую локаль для конкретиоrо потока следует передать объект класс а 10 ca1e в метод imk ие (1 . Прототип метода: locale illibue(const locale &Loc); Метод возвращает объект с предыдущими настройками локали. Для получения текущих настроек локали предназначен метод get 10 с (1 . Прототип метода: locale getloc() const; Пример настройки локали для объекта cout приведен в листише 12.14. I ЛИСТИIП' 12.14. НnСТРОЙКn ЛОКt"lJШ для ПОТОК[I #include <iostream> #include <locale> int ,"ain (1 std: : locale loc (rrRussian  Russia. 1251 rr) ; std: : locale : : global (loc ); 11 rлобальная настройка лакали std: : cout . imbue (loc) ; 11 Настройка лакали для поrroка std::cout « std::cout.getloc().c str() « std::endl; 11 Russian Russia. 1251 std: : cout « rrЭТQТ текст корректно отображается в окне консоли,r « std:: endl; std: : cin. get (1 ; return о; ФОрl\НlТпроваННЫII ввод/вывод В языке С++ При выводе (в некоторых случаях и при вводе) данных можно произвести форматирование, например, указ ать ширину поля, выравнивание внутри поля, количе ство цифр после десятичной точки и т. д. Для этоrо предварительно следует установить соотвеТСТВYIOщие фл arи с помощью определенных методов или специальных функцийманипуляторов. В этом разделе мы рассмотрим форматированный ввод/вывод на примере объектов с out и cin. Форматированный ВЫВОД в файл осуществляется аналоrичным образом. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  53  1712.10 l\Iподы rш(), IIl'ffisioll{) и ,,'illtll() Для указания минимальной ширины поля предназначен метод widt h ( 1. Ширина устанавливается только для послеДJ'lOщей операции вывода. После выполнения операции значение сбрасывается. Если указанная ширина поля не достаточна для отображения данных, то знач ение иrнорируется и данные ВЫВОДЯТСЯ полностью. Прототипы метода: streamsize width() const; streamsize width(streamsize Newwidth); Первый прототип метод а позволяет определить текуще е значение. Пример : std::cout «std::cout.width(1 «std::end1; //0 std::cout.width(101; std::cout «std::cout.width(1 «std::end1; // 10 std::cout «std::cout.width(1 «std::end1; //0 Второй прототип предназначен для указания минимальной ширины. Метод возвращает предыдущее значение. Пример: std: :cout « 1\ 11; std::cout.width(101; std: : cout « rrabc rr ; std::cout « 1\11 «std::endl; 11 Результат: abc l Внутри поля данные выравниваются по правому краю, а перед данными по умолчанию добавляются пробелы. Метод f i11 (1 позволяет задать дрyrой символ. Прототипы метода: char f ill () const; char f ill (char Newf i111 ; Первый прототип возвращает текущий символзаполнитель. Второй прототип предназначен для указания дрyrоrо символа. Метод возвращает предыдущий символ заполнитель. Пример: std: : cout « 1\ I 1; std::cout.width(101; std::cout.fill('*'); std: : cout « rrabc rr ; std: : cout « 1\ I I « std:: endl; 11 Результат: I *******аЬс I Метод р re cision () предназначен для указания точность для чисел. Если количество цифр в числе больше указанн oro значения, то производится окрyrл ение. Обратите Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  54  1712.10 внимание, чтобы указать количество ци фр после десятичной точки для вещественных чисел необходимо дополнительно установить флar f ixe d, например, с помощью одноименноrо манипулятора. Прототипы метода: streamsize precision() const; streamsize precision(streamsize Newprecision); Первый прототип возвращает текущее значение. Второй прототип предназначен для указ ания HOBoro значения. Метод возвращает предыдущее значение. Пример: std::cout «std::cout.precision() « std::end1; // 6 std::cout « 3.14159265359 « std: :end1; // 3.14159 std::cout.precision(l); std::cout « 123.1234567 «std::end1; std::соut.рrесisiоn(З); std::cout « 123.1234567 «std::end1; std::cout.precision(6); std::cout « 123.12367 «std::end1; std::cout «std::fixed « 123.1234567 « std:: endl; // 1е-ЮО2 // 123 // 123.124 // 123.123457 Установка н сбllОС флаrов ФОll]Ш1Пl В предыдущем разделе мы рассмотрели возможность указания ширины поля, символа заполнителя и количества цифр в числе. Остальные параметры форматирования задаются с помощью установки соответствующих фл асов. Для установки и сброса флarов предназначены следующие методы: -+ f 1ags (1  устан авливает указанные в параметре флarи, а все остальные сбрасывает. Прототипы метода: f'"tf1ags f1ags(1 const; f'"tf1ags f1ags(f'"tf1ags Newf,"tf1agsl; Первый прототип возвращает текущее значение. Второй прототип устанавливает указанные фл arи. Чтобы указ ать сразу несколько флarов следует между ними вставить побитовый оператор 1. Пример: std: : cout « std: : cout. f 1ags (1 « std:: end1; / / 513 std::cout.flags(std::10S base: :hex std::cout.width(101; std: : ios base:: left) ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  55  1712.10 std::cout.fill('*') ; std: : cout « 14 « std:: endl; 11 е** ** ** ** * std: : cout « std: : cout. f 1ags (1 « std:: end1; / / 840 -+ se tf (1  устанавливает флarи. Прототипы метода: f'"tf1ags setf(f,"tf1ags Newf,"tf1agsl; f'"tf1ags setf(f,"tf1ags Newf,"tf1ags, f'"tf1ags Maskl; Первый прототип устанавливает указанные фл arи. Флarи, установленные ранее, не сбрасываются. Метод возвращает предыдуще е значение. Пример : std: : cout « std: : cout. f 1ags (1 « std:: end1; / / 513 std::cout.setf(std: :ios base::left); std::cout.width(101; std::cout.fill('*') ; std: : cout « 14 « std:: endl; 11 14* ** ** ** * std: : cout « std: : cout. f 1ags (1 « std:: end1; / / 577 Второй прототип производит вычисление значения следующим образом: «Текущее значение> & Mask) (Newfmtflags & Mask & Oxffff) Пример установки фл асов hex и 1e Н: std: : cout « std: : cout. f 1ags (1 « std:: end1; / / 513 std:: cout. setf (std: :ios base:: hex I std: :iosbase: :left, std: : ios base: :basef ield std: :10;3 base: :ad]ustfleld); std::cout.width(101; std::cout.fill('*') ; std: : cout « 14 « std:: endl; 11 е** ** ** ** * std: : cout « std: : cout. f 1ags (1 « std:: end1; / / 841 -+ unse tf (1  сбрасывает указанные флarи. Прототип метода: void unsetf(fmtflags Mask); В методах f 1ags (1, se tf (1 и unse tf (1 можно указ ать следующие флаrи (или их ко мбинацию через побитовые операторы): -+ boolalpha  позволяет вводить и ВЫВОДИТЬ лоrические значения true и false. По умолчанию выводятся числа 1 и О соответственно. Пример: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  56  1712.10 bool is = true; std: : cout « is « std:: endl; 11 1 std::cout.flags(std::10S base: :boolalpha) std::cout « is « std: :endl; 11 true -+ de с  десятичное отображение числа: std::cout.flags(std::10S base: :dec) std::cout « 10 « std: :end1; // 10 -+ ос t  восьмеричное ото6раж ение числа: std::cout.flags(std::10S base: :oct) std::cout « 10 « std: :end1; // 12 -+ he х  шестнадцатеричное отображение числа: std::cout.flags(std::10S base: :hex) std: : cout « 10 « std:: end1; / / а -+ base f ie1d  комбинация флarов de с hex втором параметре метода se tf (1 . Пример: std::cout.setf(std: :ios base::hex, std: : ios base:: basef ield) ; std::cout « 14 « std: :end1; // е ос t. Обычно указывается во -+ showbase  для восьмеричных значений добавляет в начало символ rro rr, для шестнадцатеричных значений добавляет комбинацию символов rr Ох rr: std: : cout. f lags (std: : 105 base:: oct I std:: ios base:: sho1Albase) std::cout « 10 « std: :end1; // 012 std: : cout. f lags (std: : 105 base:: hex I std:: ios base:: sho1Albase) std::cout « 10 « std: :end1; // Ох а -+ showpo s  ВЫВОДИТ знак перед положительным числом: std::cout.flags(std::10S base: :showpos) std::cout « 10 « std: :end1; // +10 -+ showpo in t  выводит десятичнJ'lO точку и нули для веще ственных чисел: do uble х = 10.; std::cout « х « std::end1; // 10 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  57  1712.10 std::cout.flags(std::10S base: :showpOlnt); std::cout « х « std::end1; // 10.0000 -+ sc ie nt if ic  вещественное число в экспоненциальной фор ме: douk1e х = 100.; std::cout.flags(std::10S base: :scientific); std::cout « х « std::end1; // 1.000000е+002 -+ f ixe d  при указании вместе с методом р rec is ion () позволяет задать количество ци фр после десятичной точки. Если флar не указ ан, то метод pr ecis io n (1 задает количество цифр в числе. Пример: std::cout.precision(6) ; std: : cout « 123.1234567 « std:: end1; / / 123.123 std::cout.flags(std::10S base: :fixed); std::cout.precision(2) ; std: : cout « 123.1234567 « std:: end1; / / 123.12 std::cout.precision(6) ; std: : cout « 123.1234567 « std:: end1; / / 123.123457 -+ f 10a tf ie 1d  комбинация флarов f ixe d I scien ti f ic. Обычно указ ывается во втором параметре метода se tf (1 . Пример: douk1e х = 100.; std::cout.setf(std: :ios base::scientific, std: : ios base:: floatf ield) ; std::cout « х « std::end1; // 1.000000е+002 -+ ир ре rc as е  ВЫВОДИТ 6J'Iffibl в шести адцатеричном числе в верхне м реrистре. Кроме Toro, в верхнем реrистре ВЫВОДИТСЯ rr X rr при отображении основания счисления и 6J'Iffia rre rr при выводе вещественноrо числа в экспоненциальной форме. Пример: std: : cout. f lags (std: : 105 base:: hex I std:: ios base:: sh01Albase I std:: 10S base: : uppercase) ; std::cout « 10 « std: :endl; / / ОХА std::cout.flags(std::10S base: :sc1ent1f1c std: :10S base: :uppercase) ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  58  1712.10 std::cout « 100. « std: :end1; // 1.000000Е+002 -+ r igh t  выравнивание по правому краю поля (по умолч анию): std: : cout « 1\1 1; std::cout.width(101 std::cout.f1ags(std::los base: :rightl; std: : cout « rrabc rr; std::cout « 1\1 I « std: :endl; 11 Результат: аЬс ' -+ 1e ft  выравнивание по левому краю поля: std: : cout « 1\1 1; std::cout.width(101 std::cout.f1ags(std::los base: :leftl std: : cout « rrabc rr; std: : cout « 1\1 I « std: : endl; 11 Результат: I аЬс -+ in te rnal  знак числа выравнивается по левому кpaIO, а само число выравнивается по правому кpaIO. Между :знаком и числом вставляются символы заполнители (по умолчанию пробелы). С помощью метода f i11 (1 можно задать дрyrой символзаполнитель. Пример : std: : cout « 1\1 1; std::cout.width(101 std::cout.flags(std::10S base: :internal); std::cout « 10; std::cout « 1\1 I « std: :endl; 11 Результат: 10 ' -+ adjustfie1d  комбинация флarов interna1 I 1eft указывается во втором параметре метод а se tf ( 1 . Пример: right. Обычно std: :cout « 1\ 11; std::cout.width(101 std:: cout. fill (1 * 1) std::cout.setf(std: :ios base::internal, std: : 105 base:: adJ ustfleld) ; std::cout « 10; std: : cout « 1\1 I « std: : endl; 11 Результат: I *** ** ** 10 I Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  59  1712.10 -+ unitbu f  сбр асывает сод ержимое буф ера после каждой операции вывода; -+ skipws  если фл ar установлен, то при вводе данных пробельные символы иrнорируются (по умолчанию флar установлен). Введем один символ, а затем сбросим флar skipws и запросим ввод еще одноrо символа. После ввода первоrо символа в буф ере остается символ перевода строки. Именно этот символ будет считан при сброшенном флarе skipws во второй операции ввода. Пример: char ch = о; std: : cin » ch; std::cout « ch « std: :endl; / / ВВОДИМ а // а std::Cln.unsetf(std::10S base: :sklPWS); std::cin » ch; 11 СИМВОЛ \n считывается из буфера std: : cout « (int 1 ch « std: : end1; / / 10 (символ \ nl l\IаНИПУШIТОIIЫ ФОll]Ш1Пl Установить и сбросить флarи формата можно не только с помощью методов f 1ags (1 , se tf (1 и uns et f ( 1 , но с помощью манипуляторов. Манипуляторы формата являются функциями, принимающими и возвращающими ссыпку на поток, поэтому их можно указывать после операторов « и ». Вначале рассмотрим манипуляторы, ПРИНИМaIOщие дополнительный параметр : -+ re se tios f 1ags (f",tf 1ags F 1ags 1  сбрасывает указ анные флаrи; -+ se tios f 1ags (f",t f 1ags F 1ags 1  устанавливает указанные флarи. Пример: #include <iomanip> 11 ... Фраrмент опущен std::cout « std: :resetlosflags(std: :10;3 base: :dec) « std: :setlosflags(std::10S base: :hex) « 14 « std: :end1; // е -+ setw (streamsize NeliJ1iJidth)  задает минимальнYIO ширину поля; -+ se tf i11 (char С h 1  задает символзаполнитель. Пример: std: : cout « std: : setw (10) « std:: setf ill ( 1* I ) « rrabc rr « std:: endl; 11 ** ** ** *аЬс Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  60  1712.10 -+ se tp re cisio n (s tre ams iz е Newpr ее isio n)  указывает точность для чисел. Если количество цифр в числе больше указанноrо значения, ТО ПРОИЗВОДИТСЯ окруrле ние. Обратите внимание, чтобы указать количество цифр после десятичной точки для вещественных чисел необходимо дополнительно установить флar f ix ed. Пример: std: : cout « std: :setprecision(6) « 123.1234567 « std: : endl; // 123.123 std: : cout « std: :setprecision(6) « std: : fixed « 123.1234567 « std: : endl; // 123.123457 -+ setbase (int Base)  задает систему счисления ДЛЯ чисел: std: : cout « std: : setbase (101 « 10 « std: : endl; // 10 std: : cout « std: : setbase (81 « 10 « std: : endl; // 12 std: : cout « std: : setbase (161 « 10 « std: : endl; // а Обратите внимание Для исп Олъ:J о В3lПIЯ манипулят ор ОВ, пр ИНИМ3IOЩIIX ДОПО линт ельный парам етр, нео б ха ;ЦИМО по ;ЦКЛЮЧИТЬ зar алов очный файл iomani р. Пер е ч и ел им о сталь н ы е маи и пулятор ы : -+ end1  выводит символ перевода строки и сбрасывает буфер: std::cout « 10 « std: :endl; -+ ends  ВЫВОДИТ нулевой символ; -+ f 1 us h  сбрасывает буфер: std: : cout « 10 « std:: f lush; -+ boo1a1pha  устанавливает флar boo1a1pha: bool is = true; std: : cout « std: :boolalpha « is « std:: endl; 11 true -+ noboo1a1pha  сбрасывает флar boo1a1pha; -+ de с  устан авл ив ает фл ar de с : std: : cout « std: : dec « 10 « std:: end1; / / 10 -+ ос t  устан авливает флаr oct: std: : cout « std: : oct « 10 « std:: end1; / / 12 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  61  1712.10 -+ he х  устан авл ив ает фл ar he х : std: : cout « std: : hex « 10 « std:: endl; 11 а -+ showbase  устанавливает флаr sho1Alb ase: std: : cout « std:: oct « std:: sho1Albase « 10 « std:: end1; / / 012 std: : cout « std: : hex « std:: sho1Albase « 10 « std:: end1; / / Ох а -+ по showbase  сбрасывает флar s howbas е; -+ showpo s  устанавливает флar s howpo s: std: : cout « std: : showpos « 10 « std: : endl; 11 +10 -+ по showpo s  сбрасывает флаr showp 05; -+ showpo in t  устанавливает флar s howp oint: do uble х = 10.; std: : cout « std: : showpoint « х « std:: end1; / / 10.0000 -+ по showpo in t  сбрасывает флаr showpo in t; -+ sc ie nt if ic  устанавливает фл ar sc ie nt if ic: douk1e х = 100.; std::cout « std: :scientific « х; // 1.000000е+002 -+ f ixe d  устанавливает фл ar f ixe d: std: : cout « std: : f ixed « std: : setprecision (2) « 123.1234567 « std:: end1 / / 123.12 « std: :setprecision(6) « 123.1234567 « std:: end1; / / 123.123457 -+ de fa ul tf 10 а t  сбрасывает флarи f ixe d и sc ie nt if ic; -+ uppercase  устанавливает флar uppercase: std: : cout « std: : hex « std:: sho1Albase « std:: uppercase « 10 « std:: end1; / / ОХА std::cout « std: :scientific « std: :uppercase « 100. « std: :end1; // 1.000000Е+002 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  62  1712.10 -+ nouppercase  сбрасывает флar uppercase; -+ r igh t  устанавливает фл ar r igh t; -+ 1e ft  устан авл ивает Ф л ar 1 е ft ; -+ in te rnal  устанавливает флаr in ter nal; -+ unitbu f  устанавливает флar unitbu f; -+ по unitbu f  сбрасывает флаr uni tb uf; -+ skipws  устанавливает флar skipws; -+ по skipws  сбрасывает фл ar skipws. СоздаlШf пользоваТfЛЬfКИХ lШ1НИПУЛЯТОIIОВ Создание манипулятора вывода осуще ствляется следующи м образом: std::ostream &<Название>(std::оstrеam &stream) / / ... return stream; 11 Во з вращаем ссылку на по ТО к с О:ЗД ан и е мани пулят ор а ЕВ ОД а в ыrляд ит так: std::istream &<Название>(std::istrеam &stream) / / ... return stream; 11 Во з вращаем ссылку на по ТО к в качестве параметров функции принимают ссылку на соответствующий поток Внутри функции необходи мо вернуть ссылку на поток, чтобы иметь возможность составлять цепочки из ВЫЗОВОВ. При мер создания пользовательскоrо манипулятора вывода показ ан в листинrе 12.1 s. I .1IИСТIПП 12.15. С оздшше mНIЩ\.ЛЯТорn BЫВOД<l #include <iostream> std::ostream &mymanip(std::ostream &stream) stream « rrHello, c++ rr ; return stream; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  63  1712.10 int ",ain (1 std::cout «mymanip «std::endl; 11 Hello, с++ std: : cin. get (1 ; return о; Реализация манипулятор а, прИНИМaIOщеrо один параметр, зависит от компилятора. В ко мпиляторе, который входит в VC++ 2010, такие манипуляторы реализуются с помощью шаблонной структуры 3"'anlp Пример создания манипуляторов с одним параметром показ ан в листинrе 12.1 б. .1IИСТIПП 12.16. С оздшше mНIЩ\.ЛЯТорn с ОДНИIII Шlрnreтр O' #include <iostream> #include <iamanip> void funcl(std::iosbase &stream, int х) std::ostream *р = dynamlc cast<std::ostream *>(&stream); if (рl (*р) « rr x = rr « Х; void func2(std::iosbase &stream, char *str) std::ostream *р = dynamlc cast<std::ostream *>(&stream); if (рl (*р) «str; std:: Smanlp<lnt> cdecl mymanlpl(lnt х) return (std:: Smanlp<lnt> (&funcl, х)); std:: Smanlp<char *> cdecl mymanlp2(char *str) return (std:: Smanlp<char *>(&func2, str)); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  б4  1712.10 int ",ain (1 std: : cout « ",y",anip1 (1001 «std:: end1; / / х = 100 std: : cout « mymanip2 (rrИеllо rr ) «std:: endl; 11 Hello std: : cin. get (1 ; return о; Работа С файловой CIICTel\IOII в предыдущих разделах были описаны способы работы с файлами в языках С и С++. Теперь мы переходим к рассмотрению вопросов переименования и удаления файлов, получения ин формации о файлах, а также созданию, удал ению и чтению каталоrов. Следует сразу заметить, что больши ство функций, описанных в этом разделе, не входят ни в стандарт языка С, ни в стандарт языка С++. Реализация этих функций зависит от операционной системы и компилятора. Описанные в этом разделе функции применимы ДЛЯ операционной системы Windоws и ИСПОЛЬЗJ'lOТСЯ В компиляторе, входящем в состав Мiсrоsоft Visual С++ 2010. ПllfобllазоваlШf ПУПI К файлу или юпалоrу Преобразовать путь к файлу или каталоry в VC++ позволяют следующи е функции: -+ f u11p at h (1 и  wf u11p а th (1  преобразуют относительный путь в абсолютный путь, учитывая местоположение текущеrо рабочеrо каталоrа. Прототипы функций: # inc 1ude <s td1ik . h> char * fullpath(char *FullPath, const char *path, size t SlzelnBytes); wchar t * wfullpath(wchar t *FullPath, const wchar t *path, size t SizelnWords); в первом параметре передается указатель на буф ер, в который будет записан абсолютный путь. Если в первом параметре передать нулевой указатель, то память под абсолютный путь будет выделена динамически с помощью функц ии ",a11o с (1 . В этом случае после использования па:мяти ее следует освободить с помощью функц ии f ree (1 . Во втором параметре указывается относительный путь, а в третьем параметре  максимальный размер буфера. В качестве максимальноrо размера буфер а обычно указывается макрос МАХ  РА тн Определение макро са выrлядит так Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  65  1712.10 #define МАХ РАТН 260 Пример преобразования относительноrо пути в абсолютный путь: char fu11 path[ МAXPATH] = {О{, *р = о; р = fullpath (full path, rrtest. txt rr , :мд.х РАТИ) ; if (рl std: : cout « full path « std:: endl; // Результат: C:\book\test\test\test.txt р = fu11path(0, "..\\..\\test.txt", МAXPATHI; if (рl std::cout « р « std: :end1; // C:\book\test.txt std: :free(pl; -+ sp1lt ра th s (1 и wsp1lt р at h s (1  раз бивают абсолютный путь на составляющи е: имя диска, путь, имя файла и расшире ние. Прототипы функций: # inc 1ude <s td1ik . h> errno t splltpath s(const char *FullPath, char *Drive, size t DriveSize, char *Dir, size t DirSize, char *Filename, size t FilenameSize, char * Ext, size t ExtSize); errno t wsplltpath s(const wchar t *FullPath, wchar t *Drive, size t DriveSize, wchar t *Dir, size t DirSize, wchar t *Filename, size t FilenameSize, wchar t *Ext, size t ExtSize); в параметре Fu11P а th задается аб солютный путь. В параметре Dr i ve передается указатель на буф ер, в котором будет сохранено имя диска и двоеточие, а в параметре Dr ive S iz е  максимальный размер этоrо буф ера. В параметре Dir передается указатель на буфер, в котор ом будет сохранен путь, а в параметр е D ir Si "е  максимальный размер этоrо буфера. В параметре F i1ena",e передается указатель на буфер, в котором будет сохранено имя файла без расширения, а в параметре F i1ena",e Si z е  максимальный размер этоrо буфера. В параметре Ех t передается указатель на буф ер, в котором будет сохран ено расширение файла с предваряющей точкой, а в параметре Ех tS iz е  максимальный размер этоrо буфер а. Функция Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  бб  1712.10 возвращает значение О, е ели ошибок нет, и КОД ошибки при неудачном выполнении. В качестве раз меров обычно указываются следующи е макросы: #define МАХ DRIVE 3 #define МАХ DIR 256 #define МАХ F ЫАМЕ 256 #define МАХ ЕХТ 256 Пример разбиения абсолютноrо пути на составляюшие: errno t err = о; char fu11 path[] = "C:\\book\\test.txt"; char drive[MAXDRIVE] = {О{, dir[MAXDIR] = {О{; char na",e[ МАХ FNAME] = {О{, ext[ МAXEXT] = {О{; err = splltpath s(fullpath, drlve, МAXDRIVE, dir, МAXDIR, пате, MAXFNAME, ext, МAXEXT); if (еп == 01 std: : cout « rrdrive: rr « drive « std: : endl; 11 dr ive: с: std: : cout « rrdir: " « dir « std: : endl; // dir: \book\ std: : cout « rr name : " « пате « std: : endl; // пате: test std: : cout « rrext: " « ext « std: : endl; // ext: .txt Если какаяли60 из составЛЯЮЩИХ не нужна, то в соотвеТСТВYIOщем параметре следует передать нулевой указ атель и в качестве размера указать значение о. Пример получения только имени файла: errno t err = о; char fu11 path[] = "C:\\book\\test.txt"; char na",e[ МАХ FNAME] = {О{; err = splltpath s(fullpath, О, О, О, О, пате, MAXFNAME, О, О); if (еп == 01 std: : cout « rr name : rr « пате « std:: endl; 11 пате: test Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  б7  1712.10 -+ ",akep at h s (1 и wmake ра t h s (1  соединяют элементы пути (имя диска, путь, имя файла и расширение) в абсолютный путь. Прототипы функций: # inc 1ude <s td1ik . h> errno t makepaths(char *PathResult, size t SizelnWords, с onst с har * Dr ive, const с har * Dir, с onst с har * F ile пате, const с har * Ех t) ; errno t  wmakepath s (wchar t * PathResult, size t S IZE, с onst wchar t * Dr ive, const wchar t * Dir, const wchar t *Filename, const wchar t *Ext); в первом параметре передается указатель на буф ер, в который будет записан абсолютный путь, а во втором параметре указывается максимальный размер буфер а. В параметре Dr i ve задается и:мя диска, в параметре D ir  путь, в параметр е F i1ena",e  имя файла, а в параметре Ех t  расширение файла. Некоторые из этих четырех парамеТРОБ можно не указывать, в этом случ ае следует передать нулевой указатель ипи пустую строку. Функция возвращает значение О, е ели ошибок не было, и код ошибки при неудачном выполнении. Пример: errno t err = о; char fu11 path[ МАХ РАТН] = {О{; err = makepaths(full path, :мд.х РАТИ, rrC rr , rr\\book\\rr, rrtest rr, rrtxt rr ); if (еп == 01 std::cout « fu11 path « std::end1; // C:\book\test.txt ПfllfИlllfноваlШf и удаЛflШf файла Для переименования и уд аления файла предназначены следующи е функции: -+ re na",e (1  переименовавает файл. В первом параметре указывается старое название файла, а во втором параметр е  новое название. Если операция успешно произведена, то фукция возвращает значение О. В противном случае функция возвращает ненулевое значение и rл 06альной переменной err по присваивается КОД ошибки. Прототип функции: #nclude <cstdo> nt rename(const char *OldFlename, const char *NewFlename); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  68  1712.10 Пример переименования файла: if (std:: rename (rrf ile. txt rr, rrf ile2 . txt rr) ) std::cout « rrError rr « std: :endl; else std::cout « rrOK rr « std: :endl; -+ re",ove (1  удаляет файл, название KOToporo передано в параметре. Если операция успешно произведена, то фукц ия возвращает значение о. В противном случае функция возвращает значение  1 и rло6альной переменной er rno присваивается код ошибки. Прототип функции: #include <cstdio> int remove(const char *Filename); Пример уд аления файла: if (std:: rеnюvе (rrf ile2 . txt rr ) ! = О) std::cout « rrError rr « std: :endl; else std::cout « rrOK rr « std: :endl; ПI1ОВfllЮl Пllав доступа к файлу и юпалоrу Для проверки существования файла и каталоrа, а такж е ВОЗМОЖНОСТ1l чтения и записи файла в VC++ предназначены функции асс es s ( 1 и  wacc es s ( 1. Прототипы функций: # include <io. h> int access(const char * Filename, int AccessMode); #include <wchar.h> int waccess(const wchar t * Filename, int AccessMode); В первом параметре указывается путь к файлу или катал ory, а во втором параметре задается ОДНО из следующих значений: -+ о  проверка существ ования файла или каталоrа; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  69  1712.10 -+ 2  проверка возможности записи в файл; -+ 4  проверка возможности чтения файла; -+ 6  проверка возможности чтения и записи файла. В случае успешности проверки функции возвращают значение О. В противном случае функции БОЗВращmoт значение  1 и rло6альной переменной err по присваивается н омер ошибки. Пример проверки доступа к файлу приведен в листинrе 12.17. I .1IИСТIПП 12.17. Про верк n ДОСТ)'ШI к фn йлi #include <iostream> #include <io. h> #include <cstdio> #include <clocale> int ",ain(1 { char path [] = "С: \ \book \ \ test. txt"; std: : setlocale (LC  ALL, rr rr) ; if ( access (path, 01 ,= 11 std: : cout « rrфайл сущ=ствует rr « std:: endl; if ( access (path, 21 ,= 11 std:: cout « rrфайл доступен на запись,r « std:: endl; else std::perror(rrError rr ); if ( access (path, 41 ,= 11 std: : cout « rrфайл доступен для чтения,r « std:: endl; else std::perror(rrError rr ); if ( access (path, 61 ,= 11 std: : cout « rrфайл доступен для чтения и записи,r « std:: endl; else std::perror(rrError rr ); else std::perror(rrError rr ); std: : cin. get (1 ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  70  1712.10 return о; ИЗ!llfНflШf Пllав доcrупа к файлу Для изменения прав доступа к файлу в VC++ предн",начены функции ch",o d (1 и  wch",o d ( 1 . Прототипы функций: #include <io. h> int chmod(const char * Filename, int Mode); #include <wchar.h> int wchmod(const wchar t * Filename, int Mode); В первом параметре указывается путь к файлу, а во втором параметре задается один из следующих макросов (макросы определены в зarоловочном файле еуе/ stat.h): -+ S I READ  разрешает только чтение файла, -+ S IWR ITE  разрешает запись в файл В случае успешн ости установки прав доступа функции возвращают значение О. В противном случае функции возвращают значение  1 и rло6альной переменной err по присваивается номер ошибки. Пример установки прав доступа только для чтения приведен в листинrе 12.18. -Тшст IПП 12.18. У сп}нов Kn IIPn в дост:'rШI только для чтеlШЯ #include <iostream> #include <io. h> #inc1ude <sys/stat.h> #include <cstdio> int ",ain(1 { char path [] = "С: \ \book \ \ test. txt"; if ( chmod (path, S IREADI ,= 11 std: : cout « rrOK rr « std:: endl; else std::perror(rrError rr ); std: : cin. get (1 ; return о; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  71  1712.10 ПОЛУЧflШf lШФОlllШ1ЦIШ О фаЙЛf Получить размер файла и время создания, изменения и доступа к файлу, а также значения дрyrих метад анных позволяют в VC++ функц ии s tat (1 , st at 32 (1 , stat64(1, stati64(1, stat32i64(1, stat64i32(1, wstat (1, wstat32(1, wstat 64 (1, wstati64 (1, wstat32i64 (1 и wstat64i32 (1. По умолчанию в VC+ + 201 О функция st at (1 эквивалентна функции st at 64 i3 2 (1. Число 64 в этой функции означает количество бит, выделяемых ПОД дату, а число 32 означает количе ство бит, выделяемых под размер файла. Прототип функции st at 6413 2 (1 #inc1ude <sys/types.h> #inc1ude <sys/stat.h> int stat64i32 (const char *Мате, struct stat64i32 *Stat); В первом параметре указывается путь к Ф айлу. Результат записывается в структуру St at. Функция возвращает значение О, если ошибок не было, и значение  1 в случае ошибки. КОД ошибки сохраняется в rло6альн ой переменной er rno. Структур а st at 6413 2 объявлена следующи м образом: struct stat64i32 dev t ino t unsigned short short short short dev t оН t time 64 t time 64 t time 64 t stdev; stino; stnюdе; stnlink; stuid; stgid; strdev; st size; st atime; st :mtime; st ctime; 11 Номер диска 11 Мs!.c:кa прав доступа // Размер в байтах // Дата по след не I" о доступа // Дата изменения // Дата создания {; Поле st ",о de содержит маску типа устройства и прав доступ а. следующих флarов: # def ine S IFMT # def ine #define # def ine S IFD IR S IFCIIR S IFIFO OxFOOO Ох4000 О х2 000 Ох 1000 Возможна комбинация 1* Маска для типа файла */ 1* КаталоI" */ 1* Символьное 1* Канал */ устройство * I Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  72  1712.10 #define S IFREG Ох8000 /* Обычный файл */ # def ine S IREAD О хО 100 1* Разрешение на чтение * I # def ine S IWRITE О хОО80 1* Разрешение на запись * I #define S IEXEC ОхОО40 1* Разрешение на выполнение/поиск *1 Пример использования функции stat (1 приведен в листинrе 12.19. .1IИСТIПП 12.19. ПрИrep ИСIЮЛЪ ЗОВnИИЯ ф)...к. ЦlШ  s tntO #include <iostream> # inc 1 ude <с time > #inc1ude <sys/types.h> #inc1ude <sys/stat.h> #include <cstdio> void prlllt tlme( time64 t &t); int ",ain (1 struct char ch stat info; о; int err stat (rrc: \ \book \ \ test. txt rr, &info); if (еп == 01 std::cout «info.st size «std::endl; 11 Размер файла ch = info. st dev + I А I ; std::cout «ch« std::endl; prlllt tlme(lnfo.st ctlme); prlllt tlme(lnfo.st atlme); prlllt tlme(lnfo.stmtlme); // // // // с о зд ание файла По след ний Д О ступ Имя диска Изме не ние файла else std::perror(rrError rr ); std: : cin. get (1 ; return о; void prlllt tlme( time64 t &tl std: : tm ptm; const short S IZE char str [S IZE] = 100; {о{; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  73  1712.10 sizet count = о; errno t err = localtime s(&ptm, &t); if ('епl count = std:: strftime (str, SIZE, rr%d. %т. %У %Н: %М: %srr, &ptт); if (countl std::cout «str «std::endl; Обновить время последнеrо доступа и время изменения файла в функции utime(l, utime32 (1, uti",e64 (1, wuti",e(l,  wut ime 6 4 (1 . Прототип функции uti",e ( 1 : #include <sys/utime.h> int utime(const char * Filename, struct utillibuf *Utillibuf); В первом параметре функц ия принимает указатель на строку, в которой находится путь к файлу. Во втором параметре передается указатель на структуру u timb uf . Объявление структуры выrлядит так: struct utimbuf { VC++ позволяют wutime32 (1 и time t actime; time t nю d time ; 1* Дата последнеrо доступа */ 1* Дата изменения */ {; Если во втором параметре передать нулевой указатель, то дата буд ет текуще й. Функция возвращает значение О, если ошибок не было, и значение  1 в противном случ ае. КОД ошибки сохраняется в rло6альной переменной er rno. Пример использования функции u tl",e (1 приведен в листинrе 12 20 .1IИСТIПП 12.20. ПрИrep ИСIЮЛЪ ЗОВnИИЯ ф)...к. ЦlШ  пthпеО #include <iostream> # inc 1 ude <с time > #include <sys/utime.h> #include <cstdio> int ",ain (1 struct utimbuf newtime; new time.actime = std::time(O)  3600; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  74  1712.10 new time.modtime = std::time(O)  7200; int err = utime (rrc: \ \book \ \ test. txt rr, &new time); if (еп == 01 std: : cout « rrOK rr « std:: endl; else std::perror(rrError rr ); // текущее время err = utime (rrc: \ \book \ \ test. txt rr, О); if (еп == 01 std: : cout « rrOK rr « std:: endl; else std::perror(rrError rr ); std: : cin. get (1 ; return о; ФУНКЦIШ для llаботы f ДИfЮ1IIШ н Ю1П1ЛОП1IIШ ДЛЯ работы с дисками и каталоrами в VC++ используются следующие функции: -+ getdr lve (1  возвращает номер текущеrо диска (1  диск А, 2  диск в и т д.). Прототип функции: #include <direct.h> int getdrlve(VOld); Пример: int ch = О, drive = о; dr ive = getdr lve () ; ch = drive  1 + 'А ' ; std: : cout « (charl ch « std:: end1; / / с -+ chdr l ve (1  делает указанный диск текущим Прототип функции: #include <direct.h> int chdrive(int Drive); в параметре Dr ive указывается номер диска (1  диск А, 2  диск в и т. д.). Функция возвращает значение О, если ошиб ОК нет, и значение  1 в противном случае. Код оши бки сохраняется в rлобальной переменной еп по. Пример: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  75  1712.10 if ( chdr ive (41 01 std: : cout« getdr lve (1 « std:: end1; / / 4 -+ get cwd ( 1 и  wget cwd (1  позволяют получить строковое представление текущеrо ра60чеrо каталоrа. От этоrо значения зависит прео6разование относительноrо пути в абсолютный. Кроме Toro, важно помнить, что текущим рабочим каталоrом будет каталоr, из KOToporo запускается файл, а не каталоr с исполняемым файлом. Прототипы функций: #include <direct.h> char * getcwd (char *DstBuf, int Size InBytes) ; #incl ude <t\Ic har. h> wchar t * wgetcwd(wchar t *DstBuf, int SizelnWords); В первом параметре функции ПРИНИМaIOт указатель на буф ер, а во втором параметре  максимальный размер буфера. В качестве максимальноrо размера буфера обычно указывается макрос МАХ РАТН. В случае ошибки функции в озвр ащaIOТ нул ев о й указ ател ь. Пр и мер: char buf[MAX РАТН] = {О{; getcwd(buf, МАХ PATHI; std: :cout « buf « std: :end1; // C:\book\test\test Если в качестве парамеТРОБ указаны нулевые значения, то строка создается динамически с помощью функц ии ",a11o с ( 1 . В этом случае функция get cwd ( 1 возвращает указ атель на эту строку или нул евой указ атель в случае ошибки. После окончания работы со строкой следует освободить память с помощью функции free (1 . Пример: char *buf = о; buf = getcwd (О, 01; if (bufl std: :cout « buf « std: :end1; // C:\book\test\test std: : free (buf 1 ; buf = о; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  76  1712.10 -+ get dcwd (1 и wget dcwd (1  функции аналоrичны функциям get cwd (1 и  wget cwd (1 , но позволяют получить строковое представление текущеrо рабочеrо катал ora не для текущеrо диска, а для указ aHHoro в первом параметре. Прототипы функций: #include <direct.h> char * ge tdcwd (lnt Dr ive, char * Ds tB uf, int Si ze InByt es) ; #incl ude <t\Ic har. h> wchar t * wgetdcwd (lnt Drive, wchar t * DstBuf, int SizelnWords); в первом параметре указ ывается номер диска (о  диск по умолчанию, 1  диск А, 2  диск в и т. д.). Пример: char buf[MAX РАТН] = {О{; getdcwd(3, buf, МAXPATHI; std: :cout « buf « std: :end1; // C:\book\test\test -+ с hdir (1 и wchdir (1  делают указ анный каталоr текущи м. Функции БозвращaIOТ значение О, если ошибок не было, и значение  1 в противном случае. Код ошибки сохр аняется в rло бальной переменной е rrno. Прототипы функций: #include <direct.h> int chdir(const char *Path); #incl ude <t\Ic har. h> int wchdir(const wchar t *Path); Пример: char buf[MAX РАТН] = {О{; if ( chdir("C:\\book\\"1 01 getcwd(buf, MAX PATHI; std: : cout « buf « std:: end1; / / С: \book -+ ",kdir (1 и wmkdir (1  создают новый каталоr. Функции возвращают значение О, е ели каталоr создан, и значение  1 в противном случае. КОД ошибки сохраняется в rлобальной переменной е rrno. Прототипы функц ий: #include <direct.h> int mkdir(const char *Path); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  77  1712.10 #incl ude <t\Ic har. h> int wmkdir(const wchar t *Path); Пример: if ( ",kdir("C:\\book\\fo1der1"1 01 std::cout « rrOK rr « std: :endl; -+ r",dlr (1 и wr",dlr (1  удаляют каталоr Обратите внимание на то, что удалить можно только пустой каталоr. Функции БОЗВращmoт значение О, если каталоr удален, и значение  1 в противном случае. Код ошибки сохраняется в rлобальной переменной еп по. Прототипы функций: #include <direct.h> int rmdir(const char *Path); #incl ude <t\Ic har. h> int wrmdir(const wchar t *Path); Пример уд аления пустоrо каталоrа: if (r",dir("C:\\book\\fo1der1"1 01 std::cout « rrOK rr « std: :endl; П   fl1fOOll ООЪfIПОВ, lНlfПОЛОЖfШIЫХ В юпаЛОrf Пере брать все (или только некоторые) функции f ind f irs t (1 , f indnex t (1 следующим образом: 1. вызывается функция f ind f irs t (1. Функция возвращает де скриптор, KOToporo ПРОИЗВОДИТСЯ дальнейший поиск; объекты в указанном каталоrе позволяют и f indc10s е (1. Поиск осуществляется с ПОМОЩЬЮ 2. в цикле вызывается функция f indnex t (1. Этой функции необходимо перед ать дескриптор, возвращаемый функцией f indf ir st ( 1 . Если объектов больше нет, то функция возвращает значение  1; 3. с помощью функции f lndc10s е (1 завершается поиск По умолчанию в findf irst 64i3 2 (1, VC++ 2010 а фукция функция findnext (1 f indfirst (1  функции с о ответству ет Ф ун кц И И f indnex t 64 i3 2 ( 1. Число Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  78  1712.10 64 в этих функц иях означает количество бит, выделяемых под дату, а число 32 означает количе ство бит, выделяемых под размер файла. Прототипы функций: #include lntptr t <io.h> findfirst64i32 (const char * Filename, struct finddata64i32 t *FindData); fllldnext64l32 (lntptr t FlndHand1e, struct finddata64i32 t *FindData); int int fllldclose(lntptr t FlndHandle); В первом параметре функции f ind f irs t 6 4 i3 2 (1 указ ывается путь к палке и маска поиска. Если путь не указан, то поиск производится В текуще м рабочем каталоrе. В маске можно использовать слеДJ'lOщие специальные символы: -+ ?  любой ОДИНОЧНЫЙ символ; -+ *  любое количество СИМВОЛОВ. Рассмотрим несколько примеров масок: -+ *  все файлы и подкаталоrи; -+ *. tx t  все файлы с расшир ением txt; -+ t??? с??  файлы с названием из четырех 6уп:, наЧИНaIOщиеся с 6J'Iffibl 11 t", имеющие расширение из трех 6ym, наЧИНaIOщееся с 6J'Iffibl 11 c ll ; -+ t*  файлы и подкаталоrи, наЧИНaIOщиеся с 6Ylffibl Ilt". В параметре F indD at а передается указ атель на структуру f indda t а6 4i3 2 t, в которую будет записаны атрибуты найденноrо объекта. Структура объявлена так: struct finddata64i32 t { unsigned time64 t time 64 t time64 t fsize t char attrib; /* ФлаI" И */ time create; /* Дата с озд ания */ time access; /* Дата по след не I" о доступа */ time write; /* Дата изменения */ size; /* Размер файла */ пате [260]; /* Название объекта */ {; Поле at tr ib может содержать комбинацшо следующих фл асов: #define А ЫORМAL ОхОО /* Обычный файл */ # def ine А RDONL У О хО 1 1* Файл только для чтения * I Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  79  1712.10 # def ine А НIDDEN Ох02 /* скры'Iый файл */ # def ine А SYSTEM ОхО4 /* Системный файл */ # def ine А SUBD IR ОхlО /* Под ка тало I" */ # def ine А ARCH Ох20 /* Архивный файл */ Если объект, соответствующий параметру F i1ename, найден, то функция f lndf lr s t 6 413 2 (1 записывает атрибуты объекта в структуру f inddat а 64 i3 2 t и возвращает дескриптор. Если поиск окончился неудачей, то функция возвращает значение  1 и присваивает rло6альной переменной е rr по код ошибки. Поиск остальных объектов производится в цикле с помощью функции f indnex t 64 i3 2 (1 . В первом параметре функция принимает дескриптор, который был получен с помощью функции f indf irs t 6 4 i3 2 (1, и указатель на структуру f lnddat а 6413 2 t Если объект найден, то ero атрибуты записываются в структуру и возвращается значение о. Если поиск окончился неудачей, то функция возвращает значение  1 и присваивает rло6альной переменной е rr по код ошибки. Завершение поиска осуществляется с помощью функц ии f indc 10s е ( 1 , которая в кач естве параметра принимает дескриптор. Если ошибок не произошло, то функция возвращает значение о. В противном случае функция возвращает значение  1 и присваивает rл 06альной переменной е rrno КОД ошибки. Пример поиска всех файлов и подкаталоrов показан в листинrе 12.21. -ТШСТIПП' 12.21. Перебор всех объектов, рnсполткен:ны:{ в К;[IТ;[Iлоrе #include <iostream> #include <io. h> #include <cstdio> int ",ain (1 struct finddata t info; lntptr t h; h = findfirst (rrc: \ \book\ \ * rr, &info); if (h ==  1) std:: perror (rrError rr) ; e1se { do std::cout.width(301; std::cout «std::left «info.name; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  80  1712.10 if (info. attr ik & ASUBDIRI std: : cout « " А:::-;UВDIRrr; if (info. attr ik & ARDONLYI std: : cout « " ARDONLyrr; if (info. attr ik &  А  НIDDENI std: : cout « "  А  НIDDЕи rr ; if (info. attr ik & ASYSTEMI std: : cout « " ASYSTEMrr; if (info.attrik & AARCHI std: :cout « rr AARCHrr; std::cout «std::endl; while( findnext(h, &infol == 01; f indc10se (hl ; std: : cin. get (1 ; return о; Примерный результат выполнения: converts.cpp converts.h helloworld helloworld.exe test.txt А SUBD IR А SUBD IR А ARCH А ARCH А SUBD IR А ARCH А RDONLY А ARCH Обратите внимание на первые две строки. Одна точка обозначает текущий каталоr. Две точки 060значaIOТ каталоr выше уровнем, например, если поиск осуществляется в каталоrе C:\book\, то две точки указывают на корень диска С:. Если поиск производится В корневом катал ore диска, то этих двух строк не буд ет. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  2  1712.10 Стандартная бllбЛlIотеЮl шаблонов (STL) IIтераторы Итератор  это объект, выполняющий в контейнере роль указателя. С помощью итератора можно перемещаться внутри контейнера и получать доступ к отдельным элементам. В классах deque, list, vector, тар, multimap, set и multiset определены следующие типы итераторов: -+ it er at or  итератор. При увеличении значения итератор перемещается к концу контейнера. Пример объявления переменной: std::vector<int>::iterator it; -+ со ns t  it era t or  константный итератор. lЬменить значение, на которое ссылается итератор, нельзя. Пример объявления переменной : std: : vector<int>: : const iterator it; -+ reve rs е lt е ra t or  обратный итератор При увеличении значения итератор перемещается к началу контейнера. Пример объявления переменной: std: :vector<int>::reverse iterator it; -+ со ns t reve r se it е ra to r  константный обратный итератор. Изменить значение, на которое ссылается итератор, нельзя. Пример объявления переменной: std::vector<int>::const reverse iterator it; Присвоить значения переменным позволяют следующи е методы: -+ Ье gin (1  возвращает итератор, установленный на первый элемент контейнера. Прототипы метода: iterator begin(); const lterator begln () const; Выведем первый элемент вектора: std::vector<int> v; std::vector<int>::iterator it; v.pushback(ll; v.pushback(21; v.pushback(31; it = v.begin(); std: : cout « * it « std:: endl; 11 1 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  3  1712.10 -+ сЬ eg in ()  возвращает кон стантный итератор, установленный на первый элемент контейнера. Прототип метода: со nst lt er а to r сЬе gln () с ons t; -+ rb eg in (1  возвращает обратный итератор, установленный на последний элемент контейнера. Прототипы метода: reverse lterator rbegln(); со nst reve r se lt er а to r rbe gln () с ons t; Выведем последний элемент вектора: std::vector<int> v; std::vector<int>::reverse iterator it; v.pushback(ll; v.pushback(21 it = v.rbegin(); std: : cout « * it « std:: endl; 11 3 v. pus h  back (31 -+ crbegin (1 возвращает константный обратный итератор, установленный на последний элемент контейнера. Прототип метода: const reverse lterator crbegln () const; -+ end (1  возвращает итератор, установленный на позицшо после последнеrо элемента контейнера Прототипы метода: iterator end () ; const iterator end () const; Выведем последний элемент вектора: std::vector<int> v; std::vector<int>::iterator it; v. pushback (11 it = v. end ( ) ; std:: cout « * (itl «std: :end1; / / 3 v. pushback (21 v. pus h  back (31 -+ се nd ()  возвращает константный итератор, установленный на позицию после последнеrо элемента контейнера. Прототип метода: const iterator cend () const; -+ re nd (1  возвращает обратный итератор, установленный на позицию перед первым элементом контейнера. Прототипы метода: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  4  1712.10 reverse iterator rend(); со nst reve r se it er а to r rend () со ns t; Выведем первый элемент вектора: std::vector<int> v; std::vector<int>::reverse iterator it; v.pushback(ll; v.pushback(21 it = v. rend (1 std:: cout « * (itl «std: :end1; / / 1 v. pus h  back (31 -+ cr end (1  возвращает константный обратный итератор, установленный на позицию перед первым элементом контейнера. Прототип метода: со nst reve r se it er а to r cre nd () const; Над итераторами можно производить такие же операции, как и с указателями. Чтобы получить или изменить значение, на котор ое с сылается итератор, перед названием переменной указывается оператор * (* i t). Перемещение итератора осуществляется с помощью операторов ++ и . Кроме Toro, итераторы можно сравнивать с помощью операторов сравнения. В качестве примера изменим значение первоrо элемента, а затем выведем все элементы вектора в прямо м И обратном порядке с помощью цикла fo r (листинr 131). .1IИСТIПП 13 .1. Перебор 'леreнrов Бекторn с IЮЮШ;ЬЮ итерnтор ОБ #include <iostream> #include <vector> int ",ain (1 std::vector<int> V; std::vector<int>::iterator itl; std::vector<int>::reverse iterator it2; for (int i = 1; i <= 10; ++i) v.pushback(i); it1 = v.begin(l; *it1 = 800; 11 ИЗменение значения 11 Перебор элементов в прямом направлении for (it1=v.begin(l; it1'=v.end(l; ++it11 std::cout «*it1 «std::endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  5  1712.10 std::cout « rrrr «std::endl; 11 перебор элементов в обратном порядке for (it2=v.rbegin(l; it2'=v.rend(l; ++it21 std::cout «*t2 «std::endl; std: : cin. get (1 ; return о; Функторы Функтор  это класс, в котором определен "операторный" метод operator () () . в этом случае можно обработать вызов экземпляра кл асса как вызов функции. Пример и спользования пользовательскоrо функтора приведен в листинrе 13.2. I .1IИСТIПП 13.2. ПрИI>'ер ИСIЮЛЪ ЗОВNНИЯ Ф )...к.т opn #include <iostream> с las s MyClas s int х ; р uk1ic : MyC1ass (1 {х = о; { void operator () (int х) {х = Х; int operator() () { return х {; int ",ain (1 MyClas s оЬ j ; obj (101 ; std::cout «obj(1 «std::end1; std: : cout « MyC1ass (1 (1 «std:: end1; std: : cin. get (1 ; return о; // 10 // о Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  б  1712.10 В б и бл и отеке SТL и ме ется зarоловочном файле functional. # include <functional> Встроенные функторы делятся на унарные и бинарные. Ун арны е функторы принимают один параметр. Перечислим унарные функторы: множество встроенных функторов, Пример подключения файла: определенных в -+ negate  унарный минус: std: : cout « std: : negate<int> (1 (101 ; -+ 10 gical  по t  лоrическо е отрицание: std::cout « std: :boolalpha « std: : 10glca1 not<boo1> (1 (fa1se 1; / / true / /  10 Бинарные функторы принимают два параметра. Перечислим бинарные функторы: -+ p1 us  оператор сложения +: std: : cout « std: : p1us<int> (1 (5, 31; -+ minus  оператор вычитания : std: : cout « std: :minus<int> () (5, 3); -+ mult ip lies  оператор умн ожения *: std: : cout « std: :multiplies<int> () (5, 3); -+ di vide s  оператор деления /: std: : cout « std: : divides<int> () (15, 3); -+ nю dulus  остаток от дел ения %: std: : cout « std: :modulus<int> () (10, 3); -+ bi t and  двоичное И &: std: : cout « std: :bit and<int> (1 (100, 751; -+ bi t or  двоичное ИЛП 1: std: : cout « std: :bit or<int> (1 (100, 751; -+ bi t ха r  двоичное ИСКЛЮЧaIOще е ИШI .....: std: : cout « std: :bit xor<int> (1 (100, 2501; -+ equa1 to  оператор равно == std::cout « std: :boolalpha // 8 // 2 // 15 // 5 // 1 // 64 // 111 / / 158 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  7  1712.10 / / fa1se « std: :equa1to<int>( 1 (4, 51; -+ по t equal  t о  оператор 1= std::cout « std: :boolalpha « std: : not equa1 to<int> (1 (4, 51; / / true -+ less  оператор меньше <: std::cout « std: :boolalpha « std: : 1ess<int> (1 (4, 51; / / t rue -+ le 55 equal  оператор меньше или равно -с= std::cout « std: :boolalpha « std: : 1ess equa1<lnt> (1 (5, 51; -+ greater  оператор больше >: std::cout « std: :boolalpha « std: : greater<int> (1 (4, 51; -+ gr еа te r equal  оператор больше или равно >= std::cout « std: :boolalpha « std: : greater equa1<lnt> (1 (5, 51; / / true / / t rue / / fa1se -+ 10 glcal and  лоrический оператор && std::cout « std: :boolalpha « std: : 10glca1 and<boo1> (1 (fa1se, truel; / / fa1se -+ 10 glca1 or  лоrический оператор I 1: std::cout « std: :boolalpha « std: : loglcal or<bool> () (false, true); / / t rue Как видно из примеров, созд ание объекта производится по следующей схеме: Название функтора<Тип>О Тип данных должен совпадать с типом данных контейнера. В каче стве типа может выступать объект пользовательноrо класса. В этом случае внутри класса необходимо переrpузить оператор, соответствующий функтору. Например, при использовании функтора 1ess внутри кл асса должен быть метод оре ra to r< ( 1, принимающий в кач естве параметра ссылку на экземпляр Toro же кл асса, или СОО1БетствJ'!OЩая дружественная функция. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  8  1712.10 Чтобы вызвать функтор необходимо добавить крyrлые скобки, внутри которых передать один или два параметра: Название функ то р а <Тип> () (Параме тры) При создании пользовательских шаблонных функторов обычно наследуют класс unaryfunction (для унарных функторов) или blnary functlon (для бинарных функторов). Объявления классов: template<class Arg, class Result> struct unaryfunction { typedef Arg argwment type; typedef Result result type; {; template<class Argl, class Arg2, class Result> struct binaryfunction { typedef Argl flrst argument type; typedef Arg2 secondargument type; typedef Result result type; {; Например, объявление функтора les s выrлядит следующи м образом: template<class Т> struct less : public std::binaryfunction<T, Т, bool> { bool operator () (const Т &Left, const Т &Right) const return (Left < Right); {; IIнверторы Инверrпoр предназначен ДЛЯ изменения лоrическоrо значения, Бозвращаемоrо функтор о м, на протиположное. Существуют два инвертора: -+ по t 1  инвертирует значение YHapHoro функтора. Пример: std::cout « std: :boolalpha « std: : loglcal not<bool> (1 (false 1 ; / / true std::cout « std: :boolalpha « std: :not1( std: :logicalnot<kool>(1 1 (falsel; // false Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  9  1712.10 -+ по t2  инвертирует значение бинарноrо функтора. Пример: std::cout « std: :boolalpha « std: : less<int> (1 (4, 51; std::cout « std: :boolalpha « std: : not2 ( std:: less<int> (1 1 (4, 51; Для использования инверторов необходимо добавить зarоловок: #include <functional> / / tr ие / / false Редакторысвязеп Редакторы связей позволяют указать конкретное значение в одном из парамеТРОБ бинарноrо функтора, создавая таким образ ом унарный функтор. Существуют два р ед актор а связ ей: -+ bind ls t  передает 3 наче ние 1 в первый параметр функтора Функтор, а Значение2 во второй параметр функтора Функтор: bindlst (Функтор, Значение 1) (Значение2) 3m ивал е нтн о: ФуНКТQ Р ( Значе ние 1, Значение 2 ) Пример: std::cout « std: :boolalpha « std: :bind1st (std: : less<int> (1, 41 (51; // true (4 < 51 -+ bind2nd  передает Значение1 во второй параметр функтора Функтор, а Значе ние 2 в первый пара метр функтора Функтор: bind2 nd (ФуНКТQ р, Значе ние 1) (Значе ние 2) 3m ивал е нтн о: ФуНКТQ Р ( Значе ние 2, Значение 1) Пример: std::cout « std: :boolalpha « std: :bind2nd (std: : less<int> (1, 41 (51; / / false (5 < 41 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  10  1712.10 Для использования ред акторов связей необходимо добавить зarоловок: # include <functional> Наиболее часто редакторы связей применя:ются совместно с алrоритмами. В каче стве примера найдем первый элемент вектора, который имеет значение больше 4, с помощью алrоритма f ind  i f (листинr 13.3). Боле е подробно алrоритмы будут рассматриваться далее в этой rлаве. .1IИСТIПП 13.3. ПрИI>'ер ИСIЮЛЪ зовnния редnктор ов связей #include <iostream> #include <vector> #include <functional> #include <algorithm> int ",ain (1 std::vector<int> V; std::vector<int>::iterator res; for (int i = 1; i <= 10; ++i) v.pushback(i); 11 v = {1, 2, 3, 4, 5, 6, 7, 8, g, 10} res = std::findif(v.begin(l, v.end(l, std::bind2nd(std::greater<int>(I, 411; if ( res == v. end (1 std::cout « rrNo rr «std::endl; else std::cout «*res «std::endl; 115 std: : cin. get (1 ; return о; Адаптеры Адаптеры преобразуют указатели на функции и методы класс а таким образом, чтобы обычные функц ии и методы класса можно было передавать вместо функтор ов. Перечислим адаптеры, доступные в SТL: -+ pt r fun  преобразует указатель на функцию Синтаксис: ptr fun(Название функции) Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 11  1712.10 в параметре Наз вание функции можно передать название функции, ПРИНИМaIOщей один или два параметра. Адаптер возвращает экземпляры кл ассов ро lnt е r to unar у funct 10 пИЛИ ро lnt е r to blnary f unct 10 n В зависимости от количества параметров функции. Пример передачи адреса функции с двумя пар аметр ами: Ьооl func (nt х, nt у) return х < У; { 11 ... Фраrмент опущен std::cout « std::boolalpha « std: :blnd2nd(std: :ptr fun(funcl 41 (51; / / false ВЫЗОВ func (5, 4) -+ тет fun  позволяет использовать указатель на метод класса при хранении в контейнере указателей на экземпляры класса. Пример передачи адреса метода pr int клас са Мус lass в алrоритм fo r еас h, который осуще ствляет пере60Р элементов контейнера: void MyClass: :print(1 std: : cout « х « rr rr. , { 11 ... Фраrмент опущен std::vесtоr<муСlаss *> v2; 11 ... Фраrмент опущен std::for each( v2.begin(l, v2.end(l, std: :memfun (&MyClass:: print) ); -+ тет fun re f  позволяет использовать указатель на метод кл асса при хранении в контейнере объектов класса. Пример: std: : vесtоr<МуСlаss> vl; 11 ... Фраrмент опущен std::for each( v1.begin(l, v1.end(l, std::memfun ref(&MyClass: :print) Для использования ад алтеров необходимо добавить заrоловок: # include <functional> Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  12  1712.10 Пример использования адаптеров memfun Иmеm fun ref показан влистинrе 13.4. .1IИСТIПП 13.4. ПРИI>.ер ИСlЮлъзовnния nД<lII'еров шешjШ1И шешjШ1Jеf # include <iostream > #include <vector> #include <functional> #include <algorithm> с las s MyClas s int х ; р uklic : MyClass (1 {х = о; { MyClass (int хl {х = х; { MyClass (const MyClass &obj 1 {х = оЬ]. х ; void print (1 ; void plus (int х); {; void MyClass:: pr int (1 std::cout «х « rr rr. , void MyClass::plus(int хl Х += Х; int ",ain (1 std::vесtоr<МуСlаss> vl; std: : vector <МyClass * > v2; МyClass okj1(401; MyClass obj2(501; MyClass obj3(601; 11 Хранит объекты класса MyClass 11 Хр анит указ а тели на об ъе к ты 11 Использование адаптера тет fun ref v1.pushback(MyClass(1011; v1.pushback(MyClass(2011; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  13  1712.10 v1.pushback(MyClass(3011; std::for each( v1.begln(l, v1.end(l, std: : тет  fun  ref (&MyClass: : pr int) ); std::cout «std::endl; // 102030 11 ИЗменяем значение каждоrо объекта std::for each( v1.begln(l, v1.end(l, std::bind2nd(std::,"e,"funref(&MyClass::plusl, 51 1; std::for each( v1.begln(l, v1.end(l, std: : тет  fun  ref (&MyClass: : pr int) ); std::cout «std::endl; // 152535 11 Ис по ль з о вание ад апте р а rrem f иn v2.pushback(&obj11; v2.pushback(&obj21; v2.pushback(&obj31; std::for each( v2.begln(l, v2.end(l, std: : тет  fun (&MyClass: : pr int) ); std::cout «std::endl; //4050 60 std: : cin. get (1 ; return о;    Оозор контепнеРО8 Итак, вспомоrательные средства (итераторы, функторы, инверторы, редакторы связей и адаптеры) библиотеки SТL расс мотрены и теперь можно переходить к изучению контейнеров и алrоритмов. Начнем с контейнеров, а если быть точне е, ТО прОДОЛЖИМ изуч ение контейнеров, так как ранее мы рассматривали кл ассы st r ing и wst r ing. Эш кл ассы являются спецификация:ми ша6лонноrо класса bas lC s tr lng, который хотя и не является частью STL, но полностью совместим с этой библиотекой. Таким образом к кл ассам s tr ing и ws tr ing можно применять алrоритмы, имеющиеся в библиотеке STL. Кроме Toro, объекты этих классов можно сохранить в друrих контейнерах. В библиотеке STL контейнеры делятся на три типа: -+ последовательные контейнеры. К этому (двусторонняя очередь), list (список) и vector типу ОТН О сятся кл ас с ы (динамический массив); deque Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  14  1712.10 -+ ассоциативные контейнеры. К этому типу относятся классы тар (ассоциативный массив, в котором каждому ключу соответствует одно значение), multimap (ассоциативный массив, в котором ключу может соответствовать несколько :значений), set (множество, состоящее из уникальных элементов) и multiset (множество, в котором элементы MOryт повторяться); -+ КОiiтеЙiiерыадаптеры. К этому типу относятся кл ассы pr lor lt у que ие (очередь с приоритетами), queue (очередь) и stack (стек). Обратите внимание на то, что контейнерыадаптеры не позволяют использовать итераторы. Ве е контейнеры являются динамическими. Это означает, что при до6 авлении HOBoro элемента следить за размерами контейнера нет необходимости. Управление динамической па:мятью осуществляется автоматически с помощью распред елителя па:мяти, который реализуется классом allo са to r. При создании объектов контейнера можно указать экземпляр класса, который реализует пользовательский распределитель па:мяти. Получить доступ к распределителю па:мяти через объект контейнера позволяет метод get alloc at о r ( ) Так как в больши НС1Бе случаев достаточно возможностей BcтpoeHHoro распределителя па:мяти мы не будем создавать собственные кл ассы, а также расс матривать класс allo са to r. Чтобы получить подробные сведения по этим вопросам обращайте сь к документации. KlIacc (Iеqпе. Двусторонняя очередь Класс deque реализует двустороннюю очередь. Добавлять элементы можно в JПOбую позицию очереди. Прежде чем использовать класс необходимо доб авить зarоловок: # include <deque> СоздаlШf оБЪfкта Создать экземпляр класс а de que можно следJ'lOЩИМИ способами: -+ объявить экземпляр класс а без инициализации. Для этоrо перед названием переменной указывается название клас са. После названия класса внутри yrловых скобок задается тип данных. В этом случ ае объект не содержит элементов. Пример объявления без инициализации: std::deque<nt> d; -+ указать внутри крyrл ых скобок количество элементов. Пример: std::deque<int> d(51; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  15  1712.10 Все элементы будут иметь значения по умолчанию для типа Например, для типа in t все элементы будут содержать значение о. Указать друто е значение можно ВО втором параметре. Пример создания объекта из 5 элементов со значением 1: std: : deque<int> d (5, 11; -+ указать объект класс а de que внутри круrлых скобок или после оператора =: std: : deque<int> d1 (5, 11; std::deque<int> d2 (d11; std::deque<int> d3 = dl; -+ указать диапазон внутри контейнера с помощью итераторов. В первом параметре передается итератор, ука:зывaIOЩИЙ на начало диапазона, а во втором параметре  итератор, указывающий на кон ец диапазона. Пример: std: : deque<int> d1 (5, 11; std: : deque<int> d2 (d1. begin (1, d1. end (11 ; Над двумя объектами класса deque определены операции ==, '=, <, <=, > и >=. Пример сравнения двух объектов: std::deque<int> d1(5, 11; std::deque<int> d2(d1.begin(1, d1.end(ll; if (d1 == d21 std::cout « rrdl == d2 rr «std::endl; Кроме Toro, один объект можно присвоить дрyrому объекту. В этом случае выполняется поэлементное копирование. Пример : std: : deque<int> d1 (3, 11, d2; std::deque<lnt>::const lterator i; d2 = d1; for (i=d2.begin(l; i'=d2.end(l; ++il std: :cout « *i « rr rr; { // 1 1 1 Вме СТО оператора = для присваивания значения можно воспользоваться метод о м as sign (1 . Прототипы метода: void asslgn(slze type Count, const Т &Val); template<class It> void assign(It First, It Last); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  16  1712.10 Первый прототип удаляет сущеСТВJ'lOщие элементы, а затем вставляет Со иn t элементов Val. Пример: std::deque<int> d1(2, 11; std::deque<lnt>::const lterator i; d1.assign(3, 51; for (i=d1.begin(l; i'=d1.end(l; ++il std: :cout « *i « rr rr; { // 5 5 5 Второй прототип удаляет суще ствующие элементы, а затем вставляет элементы из диапазона, оrpаниченноrо итераторами F ir st и Las t. Пример: std::deque<int> d1(2, 11; std::deque<int> d2(3, 51; std::deque<lnt>::const lterator i; d1.assign(d2.begin(l, d2.end(ll; for (i=d1.begin(l; i'=d1.end(l; ++il std: :cout « *i « rr rr; { // 5 5 5 Вставка 'IЛf!llfffrОВ Вставить элементы позволяют слеДJ'lOщие методы: -+ push  Ь ас k (1  добавляет элемент в конец очереди. Прототип метода: void pushback(const Т &Val); Пример: std: : deque<int> d (2, 11; std::deque<lnt>: :const lterator i; d. pushback (51; for (i=d.begin(l; i'=d.end(l; ++il std::cout « *i « rr rr; // 1 1 5 -+ push f ro nt (1  добавляет элемент в начало очереди. Прототип метода: vOld push front(const Т &Val); Пример: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  17  1712.10 std: : deque<int> d (2, 11; std::deque<int>: :const iterator i; d. push front (51 ; for (i=d. begin (1 i '=d. end( 1 ++il std::cout « *i « rr rr; // 5 1 1 -+ inse rt ()  вставляет элемент в определеннJ'lO позицию. Прототипы метода: iterator insert(const iterator Where, const Т &Val); void insert (const iterator Where, Slze type Count, const Т &Val); template<class It> void insert (const iterator Where, It First, It Last); Первый прототип вставляет эле мент в позицию, на которую указ ывает итератор Where. Остальные элементы сдвиrmoтся в конец очереди. Метод возвращает итератор, указывающий на вставленный элемент. Пример: std: : deque<int> d (2, 11; std::deque<int>: :const iterator i; std: : deque<int>: : iterator it = d.begin () ; ++it; d. insert (it, 5); for (i=d. begin (1 i '=d. end( 1 ++il std::cout « *i « rr rr; // 1 5 1 Второй прототип вставляет Count элементов Val в позицию, на KOTOpJ'lO указывает итератор Whe re. Остальные элементы сдвиrаются в конец очереди. Пример: std: : deque<int> d (2, 11; std::deque<int>: :const iterator i; std: : deque<int>: : iterator it = d.begin () ; ++it; d.insert(it, 3, 5); for (i=d. begin (1 i '=d. end( 1 ++il Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  18  1712.10 std::cout « * « rr rr; //15551 Третий ПрОТОТ1lП вставляет элементы из диапазона, orp аниченноrо итераторами F irst и Last, в позицию, на KOTOpJ'lO указывает итератор Whe re. Остальные элементы сдвиrаются в конец очереди. Пример : std: : deque<int> d1 (2, 11; std::deque<int> d2 (3, 51; std::deque<lnt>: :const lterator i; std: : deque<int>: : iterator it = dl. begin () ; ++it; d1.insert(it, d2.begin(l, d2.end(ll; for (i=d1.begin (1; i' =d1. end (1; ++il std::cout « *i « rr rr; //15551 -+ swap (1  меняет элементы двух контейнеров ме стами. Прототип метода: void swap(deque &Right); Пример: std: : deque<int> d1 (2, 11, d2 (3, 51; std::deque<lnt>: :const lterator i; d1.swap (d21; for (i=d1.begin (1; i' =d1. end (1; ++il std::cout « *i « rr rr; // 5 5 5 std::cout « std: :endl; for (i=d2 .begin (1; i' =d2. end (1; ++il std::cout « *i « rr rr; / / 1 1 УдаЛflШf 'IЛf!llfffrОВ Для удаления элементов предназначены следующие методы: -+ ро р Ьас k (1  удаляет последний элемент. Пр ототип метода: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  19  1712.10 vOld рор back (1 ; Пример: std::deque<nt> d; std::deque<lnt>: :const iterator i; d.pushback(ll; d.pushback(21; d. рор back ( 1 ; for (i=d.begin(l; i'=d.end(l; ++il std::cout « *i « rr rr; / / 1 -+ ро р fr оп t (1  уд аляет первый элемент. Прототип метода: vOld рор front(); Пример: std::deque<int> d; std::deque<lnt>: :const iterator i; d.pushback(ll; d.pushback(21; d. рор front (1 ; for (i=d.begin(l; i'=d.end(l; ++il std::cout « *i « rr rr; // 2 -+ er as е ()  удаляет один элемент или элементы из диапазона. Прототипы метода: iterator erase(const iterator Where); it era t or erase (с ons t i te r at о r F irs t, const i te r at о r Last); Первый прототип уд аляет элемент на который указыв ает итератор. Пример: std::deque<int> d; std::deque<lnt>: :const iterator i, it; d.pushback(ll; d.pushback(21; it = d.end(l; d. erase (it); for (i=d.begin(l; i'=d.end(l; ++il std::cout « *i « rr rr; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  20  1712.10 { / / 1 Второй прототип удаляет элементы из диапазона, оrpаниченноrо итераторами F ir st и Last. Пример: std::deque<int> d; std::deque<lnt>: :const iterator i; d.pushback(ll; d.pushback(21; d.pushback(31; d. erase (d.begin( 1, d.end( 11; for (i=d.begin(l; i'=d.end(l; ++il std::cout « *i « rr rr; // 3 -+ clear (1  удаляет все элементы. Пр ототип метода: void clear () ; -+ empt у ()  возвращает значение t rue, если контейнер не содержит элементов, и false  в противном случае. Прототип метода: Ьооl empty () const; Пример проверки: std::deque<int> d; d.pushback(ll; d.pushback(21; d.pushback(31; d.clear(l; if (d.e"'pty(11 std::cout « rrИет элементов,r « std: :endl; -+ si ze ()  возвращает количество элементов в контейнере. Прототип метода: Slze type size () const; Пример: std::deque<int> d; d.pushback(ll; d.pushback(21; d.pushback(31; std: : cout « d. size (1 « std:: endl; / / 3 -+ тах SlZ е ()  возвращает максимальное количество элементов, которое может содержаться в контейнере. Прототип метода: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  21  1712.10 Slze type тах size () const; Пример: std::deque<int> dl; std: : cout « d1.,"ax size (1 « std:: endl; / / 1073741823 st d: : deque <char> d2; std: : cout « d2.,"ax size (1 « std:: endl; / / 4294967295 -+ re si ze ()  задает количество элементов, равное числу Newsi ze. Если указ анное количество элементов меньше текущеrо количества, ТО лишние элементы будут удалены. Если количество элементов необходимо увеличить, то в параметре Val можно указать значение, которое заполнит новое пространство. Прототипы метода: void reSlze (slze type Newsize); void reSlze (slze type Newsize, const Т &Val) ; Пример: std::deque<int> d; std::deque<lnt>: :const iterator i; d.pushback(ll; d.pushback(21; d.pushback(31; d. resize (2) ; for (i=d.begin(l; i'=d.end(l; ++il std::cout « *i « rr rr; / / 1 2 std::cout « std: :endl; d. resize (5, О); for (i=d.begin(l; i'=d.end(l; ++il std::cout « *i « rr rr; //12000 Доступ к 'IЛf!llfНП1!ll К любому элементу можно обратиться как к элементу массива. Достаточно указ ать ero индекс в квадратных скобках. Нумерация начинается с нуля. Можно как получить значение, так и изменить ero. Если индекс ВЫХОДИТ за rpаницы диапазона, то возвращаемое значение не определено. Пример до ступа к элементу по индексу: std::deque<int> d(2, 11; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  22  1712.10 std: : cout « d[O] « " " « d[ 1] « std:: endl; / / 1 1 d[l] = 2; std: : cout « d[O] « " " « d[ 1] « std:: endl; / / 1 2 Для доступа к элементам предназначены следующи е методы: -+ at (1  возвращает ссылку на элемент, расположенный по индексу Ро s. Метод позволяет как получить значение, так и изменить ero. Если индекс ВЫХОДИТ за rpаницы диапазона, ТО метод rенерирует исключение. Прототипы метода: reference at (slze type Pos); const reference at (slze type Pos) const; Пример: std: : deque<int> d (2, 11; std::cout «d.at(OI « " " « d.at(ll « std::endl; // 1 1 d.at(ll = 2; std::cout «d.at(OI « " " « d.at(ll « std::endl; // 1 2 -+ fr оп t (1  возвращает ссылку на первый элемент. Метод позволяет как получить значение, так и изменить ero. Прототипы метода: reference front () ; const reference front () const; Пример: std: : deque<int> d (2, 11; d. front (1 = 5; std: : cout « d. front (1 « std:: endl; / / 5 std: : cout « d [О] « " " « d[ 1] « std:: endl; / / 5 1 -+ back (1  возвращает ссылку на последний элемент. Метод позволяет как получить значение, так и изменить ero. Прототипы метода: reference back(); со nst re fe r еnс е back () const; Пример: std: : deque<int> d (2, 11; d.back(1 = 5; std: : cout « d .back (1 « std:: endl; / / 5 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  23  1712.10 std: : cout « d [О] « " " « d[ 1] « std:: endl; / / 1 5 -+ Ье gin (1  возвращает итератор, установленный на первый элемент контейнера. Прототипы метода: iterator begin () const lterator begln () const; -+ сЬ eg in ()  возвращает кон стантный итератор, установленный на первый элемент контейнера. Прототип метода: со nst lt er а to r сЬе gln () с ons t; -+ rb eg in (1  возвращает обратный итератор, установленный на последний элемент контейнера. Прототипы метода: reverse lterator rbegln(); со nst reve r se it er а to r rbe gin () с ons t; -+ crbegin (1  возвращает константный обратный итератор, установленный на последний элемент контейнера. Прототип метода: const reverse lterator crbegln () const; -+ end (1  возвращает итератор, установленный на позицшо после последнеrо элемента контейнера Прототипы метода: iterator end () ; const iterator end () const; -+ се nd ()  возвращает константный итератор, установленный на позицию после последнеrо элемента контейнера. Прототип метода: const iterator cend () const; -+ re nd (1  возвращает обратный итератор, установленный на позицию перед первым элементом контейнера. Прототипы метода: reverse iterator rend(); со nst reve r se it er а to r rend () со ns t; -+ cr end (1  возвращает константный обратный итератор, установленный на позицию перед первым элементом контейнера. Прототип метода: со nst reve r se it er а to r cre nd () const; в качестве при мера изменим значение первоrо элемента, а затем выведем все элементы в прямо м и обратном порядке с помощью цикла for (листннr 13.5). Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  24  1712.10 .1IИСТIПП 13.5. Перебор 'леrelПОВ с IЮЮШ;ЬЮ lПерnт орОВ #include <iostream> # inc 1 ude <deque> int ",ain (1 std::deque<int> d; std::deque<int>::iterator itl; std::deque<lnt>::reverse lterator it2; for (int i = 1; i <= 10; ++i) d.pushback(i); it1 = d.begin (1 ; *itl = 800; 11 Изменение значения 11 Пере бор элементов в прямом направлении for (it1=d.begin(l; it1'=d.end(l; ++it11 std::cout «*itl «std::endl; std::cout « rrrr «std::endl; 11 перебор элементов в обратном порядке for (it2=d.rbegin(l; it2'=d.rend(l; ++it21 std::cout «*it2 «std::endl; std: : cin. get (1 ; return о; KlIacc list. СПIIСОК Класс list реализует список Добавить элементы можно в любое место списка. В отличие от класса deque получить доступ к элементу списка по индексу нельзя. Для списков определены дополнительные операции: сортировка, объединение списков, изменение порядка следования элементов на противоположный и др. Прежде чем использовать класс list необходимо добавить зarоловок: #include <list> СоздаlШf оБЪfкта Создать экземпляр класс а list можно следJ'lOЩИ ми способами: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  25  1712.10 -+ объявить экземпляр класс а без инициализации. Для этоrо перед названием переменной указывается название клас са. После названия класса внутри yrловых скобок задается тип данных. В этом случ ае объект не содержит элементов. Пример объявления без инициализации: std::list<int> L; -+ указать внутри крyrл ых скобок количество элементов. Пример: std::list<int> L(51; Все элементы будут иметь значения по умолчанию для типа Например, для типа in t все элементы будут содержать значение о. Указать друто е значение можно ВО втором параметре. Пример создания объекта из 5 элементов со значением 1: std: : list<int> L (5, 1); -+ указать объект класс а list внутри крyrлых скобок или после оператора =: std: : list<int> L 1 (5, 11; std::list<int> L2(L11; std::list<int> L3 = Ll; -+ указать диапазон внутри контейнера с помощью нтераторов. В первом параметре передается итератор, ука:зывaIOЩИЙ на начало диапазона, а во втором параметре  итератор, указывающий на кон ец диапазона. Пример: std: : list<int> L 1 (5, 11; std::list<int> L2(L1.begin(l, L1.end(1 1; Над двумя объектами класса lis t определены операции ==, '=, <, <=, > и >=. Пример сравнения двух объектов: std::list<int> L1(5, 11; std::list<int> L2(L1.begin(1, L1.end(ll; if (Ы == Ы1 { std: : cout « rrLl == L2 rr « std:: endl; Кроме Toro, один объект можно присвоить друrому объекту. В этом случае выполняется поэлементное копирование. Пример : std::list<int> Ll(З, 1), L2; std::list<int>::const iterator i; L2 = L1; for (i=L2.begin(l; i'=L2.end(l; ++il Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  26  1712.10 std: :cout « *i « rr rr; // 1 1 1 Вме СТО оператора = для присваивания значения можно воспользоваться метод о м as sign (1 . Прототипы метода: void asslgn(slze type Count, const Т &Val); template<class It> void assign(It First, It Last); Первый прототип удаляет сущеСТВJ'lOщие элементы, а затем вставляет Со иn t элементов Val. Второй прототип удаляет суще ствующи е элементы, а затем вставляет элементы из диапазона, оrpаниченноrо итераторами F ir st и Las t. Вставка 'IЛf!llfffrОВ Вставить элементы позволяют слеДJ'lOщие методы: -+ push  Ь ас k (1  добавляет элемент в конец контейнера. Прототип метода: void pushback(const Т &Val); -+ push f ro nt (1  добавляет элемент в начало контейнера Прототип метода: vOld push front(const Т &Val); -+ inse rt ()  вставляет элемент в определеннJ'lO позицию. Прототипы метода: iterator insert(const iterator Where, const Т &Val); void insert (const iterator Where, Slze type Count, const Т &Val); template<class It> void insert (const iterator Where, It First, It Last); Первый прототип вставляет эле мент в позицию, на которую Where. Остальные элементы сдвиrmoтся в конец списка. итератор, указывmoщий на вставленный элемент. Второй прототип вставляет Count элементов Val в позицию, на KOTOpJ'lO указывает итератор Whe re. Остальные элементы сдвиrmoтся в конец списка. указ ыв ает итер атор Метод возвращает Третий протоТ1lП вставляет элементы из диапазона, orp аниченноrо итераторами F irst и Last, в позицию, на KOTOpJ'lO указывает итератор Whe re. Остальные эл е ме нты сдв иrmoтся в к о н е Ц с писка; -+ swap (1  меняет элементы двух контейнеров ме стами. Прототип метода: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  27  1712.10 void swap(list &Rightl УдаЛflШf 'IЛf!llfffrОВ Для удаления элементов предназначены следующие методы: -+ ро р Ьас k (1  удаляет последний элемент Пр ототип метода: vOld рор back (1 ; -+ ро р fro nt (1  уд аляет первый элемент Прототип метода: vOld рор front () ; -+ er as е ()  удаляет один элемент или элементы из диапазона. Прототипы метода: iterator erase(const iterator Where); it era t or erase (с ons t i te r at о r F irs t, const i te r at о r Last); Первый прототип удаляет элемент на который указывает итератор. Второй прототип удаляет эле менты из диапазона, оrpаниченноrо итераторами F ir st и L ast; -+ clear (1  удаляет все элементы. Пр ототип метода: void clear () ; -+ empt у ()  возвращает значение t rue, если контейнер не содержит элементов, и false  в противном случае. Прототип метода: bool empty () const; -+ si ze ()  возвращает количество элементов в контейнере. Прототип метода: Slze type Slze () const; -+ тах SlZ е ()  возвращает максимальное количество элементов, которое может содержаться в контейнере. Прототип метода: Slze type тах Slze () const; -+ re si ze ()  задает количество элементов, равное числу Newsi ze. Если указ анное количество элементов меньше текущеrо количества, то лишние элементы будут удалены. Если количество элементов необходимо увеличить, то в параметре Val можно указать значение, которое заполнит новое пространство. Прототипы метода: void reSlze (slze type Newsize); void reSlze (slze type Newsize, const Т &Val) ; Помимо расс мотренных методов, имеющихся также в клас се deque, в классе list присутствJ'lOТ дополнительные методы: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  28  1712.10 -+ rеnюvе ()  уд аляет все элементы, имеющие значение Val. Прототип метода: void remove(const Т &Val); Пример: std: : list<int> L (3, 1); std: : list<int>: : const iterator i; L.push front(OI; L.pushback(21; for (i=L.begin(l; i'=L.end(l; ++il std::cout « *i « rr rr; //01112 std::cout « std: :endl; L.remove(l) ; for (i=L.begin(l; i'=L.end(l; ++il std::cout « *i « rr rr; / / О 2 -+ re",ove i f (1  удаляет элементы, для которых унарный функтор Р re d вернул значение true. Функтор, БозвращaIOЩИЙ лоrиче ское значение, называется предикатом Прототип метода: template<class Pr> vOld remove lf(Pr pred); Удалим все элементы, значения которых меньше числа 2: std: : list<int> L (3, 1); std: : list<int>: : const iterator i; L.push front(OI; L.pushback(21; L.pushback(ll; for (i=L.begin(l; i'=L.end(l; ++il std::cout « *i « rr rr; //011121 std::cout « std: :endl; L.re",ove if(std: :bind2nd(std::less<int>(I, 211; for (i=L.begin(l; i'=L.end(l; ++il std::cout « *i « rr rr; // 2 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  29  1712.10 -+ unique (1  удаляет повторяющиеся элементы. Прототипы метода: vo id unique () ; template<class Pr> void unique(Pr pred); Первый прототип уд аляет повторяющиеся элементы, расположенные рядом. Чтобы список состоял только из уникальных элементов необходимо предварительно отсортировать список Второй прототип передает два элемента бинарному функтору. Если функтор вернет значение true, то повторяющийся элемент будет удален. Пример: st d: : lis t<int > L 1 (3, 1), L2; std: : list<int>: : const iterator i; L1.pushfront (01; L1.pushback(21; L1.pushback(11; L2 = L1; Ll.unique() ; for (i=L1.begin( 1; i'=L1. end (1; ++il std::cout « *i « rr rr; // О 1 2 1 std::cout « std: :endl; L2.unique(std: :equalto<int>(1 1; for (i=L2 .begin (1; i' =L2. end (1; ++il std::cout « *i « rr rr; // О 1 2 1 Доступ к 'IЛf!llfНП1!ll Для доступа к элементам предназначены следующи е методы: -+ fr оп t (1  возвращает ссылку на первый элемент. Метод позволяет как получить значение, так и изменить ero. Прототипы метода: reference front () ; const reference front () const; -+ back (1  возвращает ссылку на последний элемент. Метод позволяет как получить значение, так и изменить ero. Прототипы метода: reference back(); со nst re fe r еnс е back () const; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  30  1712.10 -+ Ье gin (1  возвращает итератор, установленный на первый элемент контейнера. Прототипы метода: iterator begin () const lterator begln () const; -+ сЬ eg in ()  возвращает кон стантный итератор, установленный на первый элемент контейнера. Прототип метода: со nst lt er а to r сЬе gln () с ons t; -+ rb eg in (1  возвращает обратный итератор, установленный на последний элемент контейнера. Прототипы метода: reverse lterator rbegln(); со nst reve r se it er а to r rbe gin () с ons t; -+ crbegin (1  возвращает константный обратный итератор, установленный на последний элемент контейнера. Прототип метода: const reverse lterator crbegln () const; -+ end (1  возвращает итератор, установленный на позицшо после последнеrо элемента контейнера Прототипы метода: iterator end () ; const iterator end () const; -+ се nd ()  возвращает константный итератор, установленный на позицию после последнеrо элемента контейнера. Прототип метода: const iterator cend () const; -+ re nd (1  возвращает обратный итератор, установленный на позицию перед первым элементом контейнера. Прототипы метода: reverse iterator rend(); со nst reve r se it er а to r rend () со ns t; -+ cr end (1  возвращает константный обратный итератор, установленный на позицию перед первым элементом контейнера. Прототип метода: со nst reve r se it er а to r cre nd () const; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  31  1712.10 СОIIПlIIОВЮ1, оБЪfДlПlflШf И ПfllfВОII<l'пm<llШf пшеков Помимо методов, расс мотренных в предыдущих разделах, в классе lis t присутствуют дополнительные методы, позволяющие отсортировать список, объединить два списка, а также изменить порядок следования элементов на ПРОТ1lВОПОЛОЖНЫЙ. ДЛЯ сортировки списка предназначен метод sor t ( 1 . Прототипы метода: void sort () ; template<class Pr> void sort(Pr pred); Первый прототип ПРОИЗВОДИТ сортировку ПО умолч анию, а второй прототип позволяет указ ать пользовательскую функцию сортировки. Отсортируем список в прямо м И о братном порядке (листинr 13. б). I .1IИСТIПП 13.6. Сортиров Kn спискn # include <iostream > #include <list> #include <functional> int ",ain (1 std::list<int> L; std::list<int>::const iterator i; L.pushback(51; L.pushback(21; L.pushback(41; 11 Сортировка в прямом порядке L.sort(l; for (i=L .begin (1; i '=L. end (1; ++il std: :cout « *i « rr rr; { // 2 4 5 std::cout «std::endl; 11 Сортировка в обратном порядке L.sort(std::greater<int>()); for (i=L .begin (1; i '=L. end (1; ++il std: :cout « *i « rr rr; { // 5 4 2 std::cout «std::endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  32  1712.10 std: : cin. get (1 ; return о; { Для объединения списков предназначены методы s plic е (1 и ",е rge ( 1. Прототипы метода splic е ( 1 void splice(const iterator Wher е , list &Right 1 ; void splice(const lterator Wher е , list &Right, const iterator First) ; void splice(const lterator Wher е , list &Right, const iterator First, const iterator Last) ; Первый прототип вставляет все элементы списка Righ t, в ПОЗИЦИЮ, на KOTOpJ'lO указывает итератор Where, и очищает список Right. Если вставка ПРОИСХОДИТ не в конец списка, то сущеСТВJ'lOщие элементы сдвиrmoтся в конец списка. Пример добавления элементов перед последним элементом списка: std: : list<int> L1 (3, 11, L2 (3, 21; std::list<int>::const iterator i; L1.splice(L1.end(l, L21; for (i=L1.begin (1; i '=L1. end (1; ++il std: :cout « *i « rr rr; {//112221 std::cout «std::endl «L2.size(1 «std::endl; //0 Второй прототип уд аляет элемент, на который указ ывает итератор Righ t и вставляет ero в ПОЗИЦИЮ, на KOTOpJ'lO указывает Существующие элементы сдвиrаются в конец списка. Пример: std::list<int> Ll(З, 1), L2; std::list<int>::const iterator i; L2.pushback(11; L2.pushback(21; L2.push back(31; L1.splice(L1.end(l, L2, ++L2.begin(ll; for (i=L1.begin (1; i '=L1. end (1; ++il { std: :cout « *i « rr rr; {//1112 std::cout «std::endl; for (i=L2.begin(l; i'=L2.end(l; ++il std: :cout « *i « rr rr; { / / 1 3 Листинrи на странице http://unicros s.narod.ru/cpp/ F ir st, из списка итератор Where. 
@Прохоре,ю/С НА, 2010 '.  33  1712.10 Тр етий ПрОТОТ1lП удаляет элементы, ВХОДЯЩИ е в диапазон, оrpаниченный итераторами F irs t и L as t, из списка Right и вставляет их в позицию, на KOTOpJ'lO указ ыв ает итератор Where. Существующие элементы сдвиrаются в конец списка. Пример: std::list<int> Ll(З, 1), L2; std::list<int>::const iterator i; L2.pushback(11; L2.pushback(21; L2.push back(31; L1.splice(L1.end(l, L2, ++L2.begin(l, L2.end(ll; for (i=L1.begin (1; i '=L1. end (1; ++il { std: :cout « *i « rr rr; {//11231 std::cout «std::endl; for (i=L2.begin(l; i'=L2.end(l; ++il std: :cout « *i « rr rr; { // 1 Метод "'erge (1 предназначен для объединения упорядоченных списков. Результатом выполнения метода является упорядоченный список ПрОТОТ1lПЫ метода: void ",erge(list &Rightl; template<class Pr> void merge(list &Right, Pr pred); Первый прототип доб авляет все элементы списка Righ t и очищает ero. Пример: std::list<int> Ll, L2; std::list<int>::const iterator i; L1.pushback(31; L1.pushback(61; L1.pushback(11; L2.pushback(51; L2.pushback(21; L2.pushback(41; L1.sort(l; L2.sort(l; L 1.",erge (Ы1 ; for (i=L1.begin (1; i '=L1. end (1; ++il std: :cout « *i « rr rr; {//123456 std::cout «std::endl «L2.size(1 «std::endl; //0 Второй прототип позволяет дополнительно указать пользовательскYIO функцию сравнения. Произведем объединение списков, отсортированных в обратном порядке: std::list<int> Ll, L2; std::list<int>::const iterator i; L1.pushback(31; L1.pushback(61; L1.pushback(11; L2.pushback(51; L2.pushback(21; L2.pushback(41; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  34  1712.10 L1.sort(std::greater<int>(II; L2.sort(std::greater<int>(II; Ll.merge(L2, std::greater<int>()); for (i=L1.begin (1; i '=L1. end (1; ++il std: :cout « *i « rr rr; {//654321 std::cout «std::endl «L2.size(1 «std::endl; //0 Для изменения порядка следования элементов на противоположный предназначен метод r ever se () . Обратите внимание на то, что метод переворачивает СПИСОК, а не сортирует ero. Элементы будут следовать в обратном порядке относительно исходноrо списка. Прототип метода: void reverse () ; Пример: std::list<int> L; std::list<int>::const iterator i; L.push back(31; L.push back(61; L.pushback(ll; L.pushback(51; L.pushback(21; L.pushback(41; for (i=L .begin (1; i '=L. end (1; ++il { std: :cout « *i « rr rr; {//361524 std::cout «std::endl; L.reverse(); for (i=L .begin (1; i '=L. end (1; ++il std: :cout « *i « rr rr; {//425163 KlIacc YectOl'. Дпнаl\шчеСКПII масспв Класс vec to r реализует динамический массив. ОН во MHorOM похож на класс de que, но имеет важное отличие  все элементы вектора размещаются в па:мяти последовательно, а двусторонняя очередь может располаrаться в памяти фрarментами. Блаrодаря последовательному размещению в па:мяти доступ к элементам вектора выполняется быстрее, но вставка новых элементов приводит к выделению объема па:мяти, достаточноrо для размещения всей последовательности элементов, и переносу всех элементов в HOBJ'lO область Кроме Toro, вектор не имеет методов р ush f r оп t () и ро р fr оп t (), предназначенных в класс е deque для вставки элемента в начало и Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  35  1712.10 уд аления первоrо элемента соответственно. Пре жде чем использ овать класс необходимо добавить зarоловок: # include <vector> СоздаlШf оБЪfкта Создать экземпляр класс а ve ct or можно следYIOЩИМИ способами: -+ объявить экземпляр класс а без инициализации. Для этоrо перед названием переменной указывается название клас са. После названия класса внутри yrловых скобок задается тип данных. В этом случ ае объект не содержит элементов. Пример объявления без инициализации: std::vector<nt> v; -+ указать внутри крyrл ых скобок количество элементов. Пример: std::vector<int> v(5); Все элементы будут иметь значения по умолчанию для типа Например, для типа in t все элементы будут содержать значение о. Указать друто е значение можно ВО втором параметре. Пример создания объекта из 5 элементов со значением 1: std: : vector<int> v (5, 1); -+ указать объект класс а ve ct or внутри крyrлых скобок или после оператора =: std: : vector<int> vl (5, 1); std::vector<int> v2(vl); std::vector<int> v3 = vl; -+ указать диапазон внутри контейнера с помощью нтераторов. В первом параметре передается итератор, ука:зывaIOЩИЙ на начало диапазона, а во втором параметре  итератор, указывающий на кон ец диапазона. Пример: std: : vector<int> vl (5, 1); std::vector<int> v2(v1.begin(l, v1.end(ll; Над двумя объектами класса ve cto r определены операции ==, '=, <, <=, > и >=. Пример сравнения двух объектов: std::vector<int> vl(5, 1); std::vector<int> v2 (v1.begin(1 , v1.end(ll; if (v1 == v21 std: : cout « rrvl == v2 rr « std:: endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  36  1712.10 Кроме Toro, один объект можно присвоить друrому объекту. В этом случае выполняется поэлементное копирование. Пример : std::vector<nt> vl(З, 1), v2; std::vector<int>::const iterator i; v2 = vl; for (i=v2.begin(l; i'=V2.end(l; ++il std: :cout « *i « rr rr; { // 1 1 1 Вме СТО оператора = для присваивания значения можно воспользоваться метод о м as sign (1 . Прототипы метода: void asslgn(slze type Count, const Т &Val); template<class It> void assign(It First, It Last); Первый прототип удаляет сущеСТВJ'lOщие элементы, а затем вставляет Со иn t элементов Val. Второй прототип удаляет суще ствующи е элементы, а затем вставляет элементы из диапазона, оrpаниченноrо итераторами F ir st и Las t. Вставка 'IЛf!llfffrОВ Вставить элементы позволяют слеДJ'lOщие методы: -+ push  Ь ас k (1  добавляет элемент в конец вектора. Прототип метода: void pushback(const Т &Val); -+ inse rt ()  вставляет элемент в определеннJ'lO позицию. Прототипы метода: iterator insert(const terator Where, const Т &Val); vod nsert (const terator Where, Slze type Count, const Т &Val); template<class It> vod nsert (const terator Where, It Frst, It Last); Первый прототип вставляет эле мент в позицию, на которую указ ывает итератор Where. Остальные элементы сдвиraIOТСЯ в конец вектора. Метод возвращает итератор, указ ЫВaIOщий на вставленный элемент. Второй прототип вставляет Count элементов Val в позицию, на KOTOpJ'lO указывает итератор Where. Остальные элементы сдвиraIOТСЯ в конец вектора. Третий прототип вставляет элементы из Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  37  1712.10 диапазона, оrpаниченноrо итераторами F irs t и L ast, в позицию, на KOTOpJ'lO ук аз ыв ает итер атор W he r е. Осталь н ы е эл е ме нты еДЕ иrmoтся в к о н е Ц в ектор а; -+ swap (1  меняет элементы двух векторов местами. Прототип метода: void swap(vector &Right) УдаЛflШf 'IЛf!llfffrОВ Для удаления элементов предназначены следующие методы: -+ ро р Ьас k (1  удаляет последний элемент Пр ототип метода: vOld рор back (1 ; -+ er as е ()  удаляет один элемент или элементы из диапазона. Прототипы метода: iterator erase(const iterator Where); it era t or erase (с ons t i te r at о r F irs t, const i te r at о r Last); Первый прототип удаляет элемент на который указывает итератор. Второй прототип удаляет эле менты из диапазона, оrpаниченноrо итераторами F ir st и L ast; -+ clear (1  удаляет все элементы. Пр ототип метода: void clear () ; -+ empt у ()  возвращает значение true, если вектор не содержит элементов, и false  в противном случае. Прототип метода: bool empty () const; -+ si ze ()  возвращает количество элементов в контейнере. Прототип метода: Slze type Slze () const; -+ тах SlZ е ()  возвращает максимальное количество элементов, которое может содержаться в контейнере. Прототип метода: Slze type тах Slze () const; -+ re si ze ()  задает количество элементов, равное числу Newsi ze. Если указ анное количество элементов меньше текущеrо количества, то лишние элементы будут удалены. Если количество элементов необходимо увеличить, то в параметре Val можно указать значение, которое заполнит новое пространство. Прототипы метода: void reS1ze (slze type Newsize); vo id re Sl ze (s 1 ze t уре News iz е, Т Val) Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  38  1712.10 Доступ к 'IЛf!llfНП1!ll К любому элементу вектора можно обратиться как к элементу массива Достаточно указать ero индекс в квадратных скобках. Нумерация начинается с нуля. Можно как получить значение, так и изменить ero. Если индекс ВЫХОДИТ за rpаницы диапазона, ТО возвращаемое значение не определено. Пример до ступа к элементу по индексу: std::vector<int> v(2, 1); std::cout «v[O] « rr rr «v[l] «std::endl; 11 1 1 v[l] = 2; std::cout «v[O] « rr rr «v[l] «std::endl; 11 12 Для доступа к элементам предназначены следующи е методы: -+ at (1  возвращает ссылку на элемент, расположенный по индексу Ро s. Метод позволяет как получить значение, так и изменить ero. Если индекс ВЫХОДИТ за rpаницы диапазона, ТО метод rенерирует исключение. Прототипы метода: reference at (slze type Pos); const reference at (slze type Pos) const; -+ fr оп t (1  возвращает ссылку на первый элемент. Метод позволяет как получить значение, так и изменить ero. Прототипы метода: reference front () ; const reference front () const; -+ back (1  возвращает ссылку на последний элемент. Метод позволяет как получить значение, так и изменить ero. Прототипы метода: reference back () ; со nst re fe r еnс е back () const; -+ Ье gin (1  возвращает итератор, установленный на первый элемент контейнера. Прототипы метода: iterator begin () const lterator begln () const; -+ сЬ eg in ()  возвращает кон стантный итератор, установленный на первый элемент контейнера. Прототип метода: со nst lt er а to r сЬе gln () с ons t; -+ rb eg in (1  возвращает обратный итератор, установленный на последний элемент контейнера. Прототипы метода: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  39  1712.10 rever s е lt е ra t or rbe gln ( ) со nst reve r se it er а to r rbe gin () с ons t; -+ crbegin (1  возвращает константный обратный итератор, установленный на последний элемент контейнера. Прототип метода: const reverse lterator crbegln () const; -+ end (1  возвращает итератор, установленный на позицшо после последнеrо элемента контейнера Прототипы метода: iterator end () ; const iterator end () const; -+ се nd ()  возвращает константный итератор, установленный на позицию после последнеrо элемента контейнера. Прототип метода: const iterator cend () const; -+ re nd (1  возвращает обратный итератор, установленный на позицию перед первым элементом контейнера. Прототипы метода: reverse iterator rend(); со nst reve r se it er а to r rend () со ns t; -+ cr end (1  возвращает константный обратный итератор, установленный на позицию перед первым элементом контейнера. Прототип метода: со nst reve r se it er а to r cre nd () const; Ве е элементы вектора размещaIOТСЯ в па:мяти последовательно. Поэтому вектор поддерживает возможность перебора элементов с помощью указателей. Для указателей имеются специальные типы: -+ ро in te r  обычный указ атель. Можно как получить значение, так и изменить; -+ со ns t ро ln t er  константный указ атель IЬменить значение нельзя Присвоить указателю адрес первоrо элемента вектора позволяет метод da ta (1 Прототипы метода: pointer data () ; const pOlnter data() const; Пример перебора элементов с помощью указателей показан в листише 13.7. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  40  1712.10 -Тшст IПП 13.7. ДОСТ:'rП ]с 'Элel'rleШ;[lI"I :вeKTop;[l с птrlOIЦЬЮ :'r"К;[Iзnтелей # include <iostream > #include <vector> int ",ain (1 std::vector<int> V; std::vector<int>::pointer р; std::vector<lnt>::const pOlnter ер; v.reserve (10); 11 Резервируем минимальный размер for (int i=l; i<=10; ++i) v.pushback(i); р = v.data(); 11 Сохраняем обычный указатель *р = 800; 11 Изменяем значение первоrо элемента ер = v.data(); 11 Сохраняем константный указатель for (int j=O, c=v. size (); j<c; ++j, ++ср) std: : cout « *ср « rr rr; // 800 2 3 4 5 6 7 8 9 10 std::cout «std::endl; std: : cin. get (1 ; return о; ПОЛУЧflШf И ИЗlllfИflШf II;lЗlllfll;l ВfIПОll;l Как вы уже :знаете, вектор является динамическим массивом, который может автоматически ув еличивать объем зар езервированной па:мяти. Вставка новых элементов ПРИВОДИТ к выделению 06ъе ма па:мяти, достаточноrо для размещения всей последовательности элементов, и переносу всех элементов в HOBJ'lO область. Если зарезервированной па:мяти достаточно, то перераспределение па:мяти не производится. Получить количеС1БО элементов, для которых зарезервирована па:мять, позволяет метод capacity (1. Прототип метода: Slze type capacity() const; Пример: std::vector<int> v(З, 1); std::cout «v.size() «std::endl; std::cout «v.capacity() «std::endl; v. рор back (1 ; // 3 // 3 11 Удал..qем элемент Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 41  1712.10 std::cout «v.size() «std::endl; 112 std::cout «v.capacity(1 «std::endl; //3 Если добавление элементов ПРОИЗВОДИТСЯ часто, ТО это может снизить эф фективность проrpаммы, так как перераспределение памяти будет выполнено несколько раз. Поэтому, если минимальное количество элементов зар анее известно, то следует указ ать ero с помощью метода res erve () . Прототип метода: void reserve(slze type Count); Пример указания минимальноrо размера вектора: std::vector<int> V; v.reserve (10); std::cout «v.size() «std::endl; std::cout «v.capacity() «std::endl; v.pushback(ll; v.pushback(21; v.pushback(31; std::cout «v.size() «std::endl; std::cout «v.capacity() «std::endl; Уменьшить размер вектора ДО минимальноrо shr lnk to f lt (1 Прототип метода void shrinkto fit(); Пример: std::vector<int> V; v.reserve (10); std::cout «v.size() «std::endl; std::cout «v.capacity() «std::endl; v.pushback(ll; v.pushback(21; v.pushback(31; v.shrinktofit() ; std::cout «v.size() «std::endl; std::cout «v.capacity() «std::end1; СПfциализация \'fftOl"':bool> // о // 10 // 3 // 10 значения п озв оляет метод // о // 10 // 3 // 3 Для специализации ve ct or <ь о 01> определены дополнительные методы: -+ f lip (1  инвертирует значения всех эле ментов. Прототип метода: void flip (1 ; Пример: std::vector<boo1> v; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  42  1712.10 std: : vector<bool>: : const iterator i; v. pushback (true); v. pushback (false); v.flip(l; for (i=v.begin(); i!=v.end(); ++i) std: : cout « std: :boolalpha « * i « rr rr; / / false true -+ swap ()  меняет два элемента вектора местами. Пр ототип метода: static void swap(reference Left, reference Right); Пример: std::vector<bool> V; std: : vector<bool>: : const iterator i; v. pushback (true); v. pushback (false); v. pushback (false); v.swap(v[O], v[l]l; for (i=v.begin(); i!=v.end(); ++i) std: : cout « std: :boolalpha « * i « rr rr; // false true false KlIacc шар. АссоцпаТПВНЫII I\IaССПВ С )'НПЮlЛЬНЫI\Ш ключаl\ПI Класс тар реализует ассоциативный массив, в котором каждому ключу соответствует одно значение. ОСНОВНЫМ отличием ассоциативных массивов от обычных является возможность обращения к элементу массива не только по числовому индексу, но и, например, по индексу, состоящему из строки. Индексы ассоциативноrо массива назЫВaIOТся КЛЮЧ,aмlt. Пр ежде чем использовать класс необходимо добавить зarоловок: # include <тар> КТlaСС llail' Класс pair, объявленный в зarоловочном файле utility, реализует пару ключ/значение. Ключ доступен через атрибут f ir st, а значение  через атрибут sec ond. Создать экз емпляр кл асса можно так: -+ объявить экземпляр класс а без инициализации. Для этоrо перед названием переменной указывается название класса pair. После названия клас са внутри Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  43  1712.10 утл ОВЫХ СКО бок через запятую задmoтся типы данных ключа и значения. В этом случае атрибуты будут иметь значения по умолч анию для KOHкpeTHoro типа. Например, для типа int атрибут будет содержать значение о. Пример объявления без инициализации: std::pair<int, int> pr; std: : cout « pr. f irst « std:: endl; std::cout « pr.second « std::endl; // о // о -+ указав после названия переменной внутри запятую. Пример: typedef struct std::pair<std::string, PAIR pr (rrKeyrr, 10); std: : cout « pr. f irst « std:: endl; 11 Кеу std: : cout « pr. second « std:: endl; 11 10 круrлых скобок два значения через int> Р АI R; -+ указав после названия переменной внутри круrлых скобок дрyrой объект класса pair. Пример: typedef struct std::pair<std::string, int> PAIR; PAIR pr 1 (rrKeyrr, 10); PAIR pr2 (pr 11 ; std::cout « pr2.first « std::endl; std::cout « pr2.second « std: :endl; / / Кеу / / 10 Кроме Toro, можно воспользоваться шабл онной функцией ",ake ран (1 . Пример : typedef struct std::pair<int, int> PAIR; PAIR pr = std::",ake palr(5, 101; std::cout «pr.first «std::endl; 115 std::cout «pr.second «std::endl; 11 10 Над двумя объектами кл асса р air определены операции ==, '=, <, <=, > и >=. Кроме Toro, один объ ект можно присвоить друrому объекту. В этом случае выполняется копирование значений атрибутов. СоздаlШf оБЪfкта Создать экземпляр класса тар МОЖНО следYIOЩИМИ способами: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '. 44  1712.10 -+ объявить экземпляр класс а без инициализации. Для этоrо перед названием переменной указывается название клас са. После названия класса внутри yrловых скобок через запятyIO задmoтся типы данных ключа и знач ения. В ЭТОМ случае объект не содержит элементов. Пример объявления без инициализации: std: :map<std: :strng, nt> т; Внутри уrловых скоб ОК после типов данных ключа и значения можно дополнительно указать функцию сравнения для ключа: std::map<nt, nt, std: :less<nt> > т; Внимание Меж ду закрывающими yr лов ыми ско бками пр о б ел до бавлен специально. Если пр о б ел не ДО бавить, т о н еко тор ые ко:r...mлят ар ы считаю т это ОIШIб кой. -+ указать объект класса "'ар внутри круrлых скобок или после оператора =: std: : map<int, int> тl; std: : map<int, int> ",2 (",11 std: : map<int, int> ",3 = тl; -+ указать диапазон внутри контейнера с помощью итераторов. В первом параметре передается итератор, ука:зывaIOЩИЙ на начало диапазона, а во втором параметре  итератор, указывающий на кон ец диапазона. Пример: typedef struct std::pair<int, int> PAIR; std::map<int, int> тl; ",l.insert(PAIR(O, ",l.insert(PAIR(l, 1011 ; 2 011 ; std::map<int, int> т2 (ml.begin() ",1. end ( 11 ; Над двумя объектами класса "'ар определены операции ==, ,= <, <=, > и >=. Кроме Toro, один объект можно присвоить дрyrому объекту. Пример: typedef struct std::pair<int, int> PAIR; std::map<int, int> тl, т2; std::map<lnt, lnt>::const lterator i; ",l.insert(PAIR(O, 1011; ",l.insert (PAIR (1, 2011; т2 = тl; for (i=m2.begin(l; i'=m2.end(l; ++il Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  45  1712.10 std: :cout « i>first « rr > rr « i >second « { / / о > 10; 1 > 2 о; rr. rr. , , Вставка 'IЛf!llfffrОВ Вставить элемент можно указав ключ внутри квадратных скобок Значение элемента задается после оператора присваивания. Если ключ уже существует, то вместо вставки элемента ПРОИЗВОДИТСЯ изменение значения. Пример: std::map<std::string, int> т; std::map<std::string, int>::const iterator i; т[ rronerr] = 1; т[ rrtwo rr ] = 2; for (i=m.begin (1; i '=m. end (1; ++il std: :cout « i>first « rr > rr « i >second « } 11 оnе > 1; two > 2; Вставить элементы позволяют слеДJ'lOщие методы: rr. rr. , , -+ inse rt ()  вставляет один или несколько элементов. Прототипы метода: pair<iterator, bool> insert(const pair &Val) iterator insert(const iterator Where, const pair &Val); template<class It> void insert (It F irst, It Last); Первый прототип вставляет экземпляр класса р air и возвращает объект Toro же клас са. Через атрибут f irs t буд ет доступен итератор, указывающий на вставленный элемент, а через атрибут sec ond  лоrическое значение true, если элемент вставлен, и fals е в противном случае. Обратите внимание на то, что вставить можно только элемент, ключ KOToporo не содер жится в массиве. Пример: typedef struct std::pair<std::string, int> PAIR; std::map<std: :string, int> т; std: : map<std: : string, int>:: const iterator i; std: : pair< std: :map<std: : str ing, int>:: iterator, bool > pr; pr = т. insert (PAIR (rronerr, 1)); if (р r. s е со nd) { 11 Про ве рка успешно сти вставки Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  46  1712.10 std: : cout « (pr. first)  >f irst « rr > rr « (pr.first)>second « std: :endl; { // one > 1 else std: :cout « rrError rr « std::endl; 11 Использование value type вместо PAIR т. insert (std: : map<std: : string, int>: :value type (rrtwo rr, 2)); for (i=,". begin (1 i'=,".end(1 ++il std: : cout « i>first « .. > .. « i  >se со nd « ". ". , , { // one > l' two > 2 . , , Второй прототип позволяет указ ать позицию вставки с помощью итератора. В каче стве результата возвращается итератор, указ ЫВaIOЩИЙ на вставленный элемент. Третий ПрОТОТ1lП вставляет элементы из диапазона, orp аниченноrо итераторами F irst и Las t. Пример : typedef struct std::pair<std::string, int> PAIR; std::map<std: :string, int> тl, т2; std: : map<std: : string, int>:: const iterator i; тl. insert (PAIR (rrorr, 1)) ml.insert (PAIR (rrl rr , 2)) ml.insert(ml.end(), PAIR(rrl0 rr , 3)); for (i=,"l.begin( 1; i'=,"l. end (1 ++il std::cout « >frst « rr > rr « >second « rr; ". , { / / о > 1; 1 > 2; 10 > 3; std::cout « std: :endl; ,"2.insert(++m1.begin(l, ,"l.end(ll; for (i=,"2 .begin (1; i' =,"2. end (1 ++il std: : cout « >frst « .. > .. «   >se со nd « ". ". , , { // 1 > 2 . 10 > 3 . , , -+ swap (1  меняет элементы двух контейнеров ме стами. Прототип метода: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '. 47  1712.10 void swap(map &Right); Пример: typedef struct std::pair<std::string, int> PAIR; std::map<std: :string, int> тl, т2; std: : map<std: : string, int>:: const iterator i; тl. insert (PAIR (rrorr, 1)); тl. insert (PAIR (rr 1 rr, 2)); т2 . insert (PAIR (rr one rr, 1)); т2. insert (PAIR (rrtwo rr, 2)); ,"2 .swap (,"11; for (i=,"l.begin (1; i' =,"1. end (1 ++il std::cout « i>first « rr > rr « i>second « rr; ". , } 11 оnе > 1; two > 2; std::cout « std: :endl; for (i=,"2 .begin (1; i' =,"2. end (1 ++il std::cout « i>first « rr > rr « i>second « rr; ". , { / / о > 1; 1 > 2; УдаЛflШf 'IЛf!llfffrОВ Для удаления элементов предназначены следующие методы: -+ er as е ()  удаляет один элемент или элементы из диапазона. Прототипы метода: 51 ze t ур е е ras е (с onst ke у  type &Ке y-val) iterator erase(const iterator Where); it era t or erase (с ons t i te r at о r F irs t, const i te r at о r Last); Первый прототип удаляет элемент с указанным ключом. Пример: typedef struct std::pair<std::string, int> PAIR; std::map<std: :string, int> т; std: : map<std: : string, int>:: const iterator i; т. insert (PAIR (rr one rr, 1)); т. insert (PAIR (rrtwo rr, 2)); т. erase (rronerr) ; for (i=,". begin (1 i ,='". end (1; ++il Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  48  1712.10 std::cout « >frst « rr > rr « i>second « rr; ". , { / / two > 2; Второй прототип удаляет элемент на который указывает итератор. При мер: typedef struct std::pair<std::string, int> PAIR; std::map<std: :string, int> т; std: : map<std: : string, int>:: const iterator i; т. insert (PAIR (rr one rr, 1)); т. insert (PAIR (rrtwo rr, 2)); m.erase(m.end() ); for (i=,". begin (1 i'=,".end(1 ++il std::cout « i>first « rr > rr « i>second « rr; ". , { / / one > 1; Третий прототип уд аляет элементы из диапазона, оrpаниченноrо итераторами F irst и Last. Пример: typedef struct std::pair<std::string, int> PAIR; std::map<std: :string, int> т; std: : map<std: : string, int>:: const iterator i; m.insert(PAIR(rrorr, 1)); m.insert(PAIR(rrl rr , 2)) т. insert (PAIR (rr2 rr, 3)); т. insert (PAIR (rrз rr, 4)) т. erase (т. begin (), т. end () ) ; for (i=,". begin (1 i'=,".end(1 ++il std::cout « i>frst « rr > rr « >second « rr; ". , { / / 3 > 4; -+ clear (1  удаляет все элементы. Пр ототип метода: vod clear () ; -+ empt у ()  возвращает значение t rue, если контейнер не содержит элементов, и false  в противном случае. Прототип метода: bool empty () const; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  49  1712.10 -+ si ze ()  возвращает количество элементов в контейнере. Прототип метода: Slze type Slze () const; Пример использования методов clear ( 1 , е",р ty (1 и siz е ( 1 : typedef struct std::pair<std::string, int> PAIR; std::map<std: :string, int> т; m.insert(PAIR(rrorr, 1)); m.insert(PAIR(rrl rr , 2)) std: : cout « т. size () « std:: endl; 11 2 m.clear(); if (",.e"'pty (11 std::cout « rrИет элементов,r « std: :endl; std: : cout « т. size () « std:: endl; 11 о -+ тах SlZ е ()  возвращает максимальное количество элементов, которое может содержаться в контейнере. Прототип метода: Slze type тах Slze () const; Доступ к 'IЛf!llfНП1!ll К любому элементу можно обратиться как к элементу массива. Достаточно указ ать ero ключ внутри maдpaTHblX скобок Можно как получить значение, так и изменить ero. Если прОИЗВОДИТСЯ присваивание значения по ключу и ключа не суще ствует, ТО ПРОИЗВОДИТСЯ вставка элемента, если элемент уж е суще ствует, то ero значение изменяется на новое. Если производится получение значения по ключу и ключа не суще ству ет, то эл е ме нт в ставляется с о з н ач е н и ем п о ум олч ан ию для ти п а, а з ате м это значение возвращается. Пример: std::map<std::string, int> т; std::map<std::strlng, lnt>::const iterator i; m [rr оnе rr] 1; 11 Вставляем но:ЕЫЙ элемент m [rrtwo rr] 2; m [ rr О nе rr ] 1 О о; 11 Изме няем з наче ние сущ= с твующе I" о э леме нта std: : cout « m[rronerr] « std: : endl; // 100 std: : cout « m[rrtwo rr ] « std: : endl; // 2 std: : cout « m[rrkeyrr] « std: : endl; // о ( элемент вс тавле н) for (i=m.begin (1 ; i!=m.end() ; ++il { Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  50  1712.10 std: :cout « i>first « rr > rr « i >second « rr; rr; { // key > о; one > 100; two > 2; Для доступа к элементам предназначены следующи е методы: -+ at ()  возвращает ссылку на элемент, ключ KOToporo соотвеТС1Бует значению Ке yval. Метод позволяет как получить значение, так и изменить ero. Если ключ не существует, то метод rенерирует исключение. Прототипы метода: ",apped type &at (const key type &Keyvall; со nst тар ре d  t ур е & at (с onst ke у  t уре &Ке y-val) с ons t; Пример: std::map<std: :string, int> т; 11 т. at ( rr оnе rr) = 1; 11 Ошибка. КтоЧ не сущее твует m [rr оnе rr] = 1; 11 Вставляем но ВЫЙ элеме нт т. at ( rr оnе rr) 10 о; 11 Изменяем з наче ние элемента std: : сои t « т. at (rr one rr) « std:: endl; 11 100 -+ со иn t ()  возвращает количество элементов, у которых ключ cooweTCТEJ'!OT значению Ке yval. Прототип метода: 51 ze t ур е с оиn t (с onst ke у  type &Ке y-val) с onst; Пример: std::map<std: :string, int> т; т[ rronerr] = l' , std: : cout « т. count (rr one rr) « std: : endl; // 1 std: : cout « т. count (rrtwo rr) « std: : endl; // о -+ f ind (1  возвращает итератор, установленный на элемент, ключ KOToporo соответствует значению Ке yval. Если элемент не найден, то метод возвращает итератор, указывaIOЩИЙ на позицию после последнеrо элемента. Прототипы метода: iterator find (const key type &Keyval); const iterator find(const key type &Keyval) const; Пример: std::map<std: :string, int> т; std: : map<std: : string, int>:: iterator i; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  51  1712.10 т[ rr one rr] = 1;  = m.fnd(rronerr); if (i ,= m.end(1 1 std::cout « i>second « std::endl; 11 1 i = m.find( rrtwo rr ); if (i == m.end(1 1 std::cout « rrNo rr « std: :endl; // Ыо -+ lowe r Ьо und ()  возвращает итератор, установленный на элемент, ключ KOToporo больше или равен значению Key-val. Если элемент не найден, то метод возвращает итератор, указЫВaIOЩИЙ на ПОЗИЦИЮ после последнеrо элемента. Прототипы метода: it era t or lower  Ь ound (с ons t ke у  type &Keyval) со nst it er а to r lower  Ь ound (с onst ke у  type &Ке y-val) const; Пример: std::map<int, int> т; std: : map<int, int>:: iterator i; т[О] = о; т[1] = 1; т[4] = 4; т[5] 5' , i = m.lowerbound(2); if (i ,= m.end(1 1 std::cout « i>second « std::endl; 11 4 i = m.lowerbound(l); if (i ,= m.end(1 1 std::cout « i>second « std::endl; 11 1 -+ ир ре r Ьо und (1  возвращает итератор, установленный на элемент, ключ KOToporo больше значения Keyval. Если элемент не найден, то метод возвращает итератор, указывaIOЩИЙ на позицию после последнеrо элемента. Прототипы метода: it era t or ирр er  Ь ound (с ons t ke у  type &Keyval); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  52  1712.10 const iterator upper bound (const key type &Key-val) const; Пример: std::map<int, int> т; std: : map<int, int>:: iterator i; т[О] = о; т[1] = 1; т[4] = 4; т[5] 5' , i = m.upperbound(l); if (i ,= m.end(1 1 std::cout « i>second « std::endl; 11 4 -+ equal range (1  возвращает экземпляр класс а р ан Через атрибут f lrs t будет доступен итератор, явля::ющийся результатом выполнения метода lower bound () , а через атрибут sec ond  итератор, явля::ющийся результатом выполнения метода ир per bound (1 Прототипы метода pair<iterator, lterator> equal range(const key type &Keyval) palr<const lterator, const iterator> equalrange (const key type &Keyval) const; Пример: typedef std: :map<int, int> М; м т; std::pair<M::iterator, M::iterator> pr; т[О] = о; т[1] = 1; т[4] = 4; т[5] = 5; pr m.equalrange(l); if (pr.first ,= m.end(11 11 Ключ существует { std: : cout « pr. f irst >second « std:: endl; / / 1 if (pr. second ,= т. end (11 std: : cout « pr. second >second « std:: endl; 11 4 pr = m.equalrange(2); if (pr.first ,= m.end(11 11 Ключ не существует { std: : cout « pr. f irst >second « std:: endl; / / 4 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  53  1712.10 if (pr. second ,= т. end (11 std: : cout « pr. second >second « std:: endl; 11 4 -+ Ье gin (1  возвращает итератор, установленный на первый элемент контейнера. Прототипы метода: iterator begin () const lterator begln () const; -+ сЬ eg in ()  возвращает кон стантный итератор, установленный на первый элемент контейнера. Прототип метода: со nst lt er а to r сЬе gln () с ons t; -+ rb eg in (1  возвращает обратный итератор, установленный на последний элемент контейнера. Прототипы метода: reverse lterator rbegln(); со nst reve r se it er а to r rbe gin () с ons t; -+ crbegin (1  возвращает константный обратный итератор, установленный на последний элемент контейнера. Прототип метода: const reverse lterator crbegln () const; -+ end (1  возвращает итератор, установленный на позицшо после последнеrо элемента контейнера Прототипы метода: iterator end () ; const iterator end () const; -+ се nd ()  возвращает константный итератор, установленный на позицию после последнеrо элемента контейнера. Прототип метода: const iterator cend () const; -+ re nd (1  возвращает обратный итератор, установленный на позицию перед первым элементом контейнера. Прототипы метода: reverse iterator rend(); со nst reve r se it er а to r rend () со ns t; -+ cr end (1  возвращает константный обратный итератор, установленный на позицию перед первым элементом контейнера. Прототип метода: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  54  1712.10 со nst reve r se it er а to r cre nd () const; KlIacc шпltiшар. АССОЦIIаТIIвныlI I\IaCCIIB С ПОВТОрЯЮЩIIМIIСЯ ключаМII Класс multimap реализует ассоциаТ1lВНЫЙ массив, в котором одному ключу MOryT соответствовать несколько значений. Класс содержит такие же методы, что и класс тар, поэтому В этом раздел е мы рассмотрим только основные операции и отличия между кл ассами. Прежд е чем использовать клас с необходимо добавить зarоловок: # include <тар> Создание экз емпляра класса mult шар выполняется точно также как и создание экземпляра класса тар. Над дву:мя объектами класса multimap определены операции ==, '=, <, <=, > и >=. Кроме Toro, один объект можно присвоить дрyrому объекту. Вставка элементов ПРОИЗВОДИТСЯ с ПОМОЩЬЮ метода inse rt (). Если ключ вставляемоrо элемента уже существует в массиве, то это не ПРИВОДИТ к ошибке. В этом случае элемент все равно вставляется. Прототипы метода inse rt () : iterator insert(const pair &Val); iterator insert(const iterator Where, const pair &Val); template<class It> void insert(It First, It Last); Первый прототип вставляет экземпляр клас са pair. В отличие от метода inser t () кл асса тар метод возвращает итератор, а не объект класса р air. Второй прототип позволяет указ ать позицию вставки с помощью итератора Whe re. Третий прототип вставляет элементы из диапазона, оrpаниченноrо итераторами F irs t и Las t. Пример : typedef struct std::pair<std::string, int> PAIR; std::multimap<std::string, int> т; std::multlmap<std::strlng, lnt>::const lterator i; i = т. insert (PAIR (rronerr, 1)); std: :cout « i>first « rr > rr « i>second « std: :endl; / / one > 1 11 Использование value type вместо PAIR т. l1lsert (std: : multlmap<std: : str lng, lnt>:: value type (rrtwo rr, 2)); т. insert (т. begin О, PAIR (rr one rr, 6)); 11 Вставка одинаковоI"О К.JIICЧа for (i=m.begin (1; i '=m. end (1; ++il { / / Перебор элементов std: :cout « i>first « rr > rr « i>second « rr; rr; 11 оnе > 6; оnе > 1; two > 2; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  55  1712.10 Обратите внимание на то, что ДЛЯ вставки и извлечения элементов нельзя использовать оператор [], так как ключи MOryT повторяться. Кроме Toro, класс multimap не имеет метода at (1. Чтобы получить доступ к элементам следует воспользоваться методами f lnd (1, lowe r Ьо und (1, ирр er  Ь ound (1 и equal range (1 Получить количество элементов с указанным ключом позволяет метод со иn t ( ) . Пример: typedef struct std::pair<std::string, int> PAIR; std::multimap<std::string, int> т; т. insert (PAIR (rronerr, 1)); т. insert (PAIR (rronerr, 2)); std::cout «m.count(rronerr) «std::endl; 112 КlIассы set 11 шпltisеt.l\Iножества Класс s et реализует :множество, состоящее из уникальных элементов, а класс mult is et  множество, в котором элементы Moryт повторяться. Прежде че м использовать класс ы необходимо до6 авить зarоловок: # include <set> Работа с классами ПРОИЗВОДИТСЯ аналоrичным образом, поэтому в этом разделе мы рассмотрим только возможности класса 5et. СоздаlШf оБЪfкта Создать экземпляр класс а 5е t можно следJ'lOЩИМИ способами: -+ объявить экземпляр класс а без инициализации. Для этоrо перед названием переменной указывается название клас са. После названия класса внутри yrловых скобок задmoтся Т1Iпы данных элемента. В этом случае объект не содержит элементов. Пример объявления б ез инициализации: 5td: : 5et<int> 5; Внутри yrл овых скобок после типа Д анных можно дополнительно указать функцию сравнения: 5td: : 5et<int, 5td:: le55<int> > 5; Внимание Меж ду закрывающими yr лов ыми ско бками пр о б ел до бавлен специально. Если пр о б ел не ДО бавить, т о н еко тор ые ко:r...mлят ор ы считаю т это ОIШIб кой. -+ указать объект класс а se t внутри круrлых скобок или после оператора =: 5td: : 5et<int > 51; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  56  1712.10 s 1. insert (1); 51. insert (2) std::set<int> 52 (51); std::set<int> 53 = 51; -+ указать диапазон внутри контейнера с помощью итераторов. В первом параметре передается итератор, ука:зывaIOЩИЙ на начало диапазона, а во втором параметре  итератор, указывающий на кон ец диапазона. Пример: std::set<int> 51; sl.insert (1); sl.insert (2); std::set<int> s2 (sl.begin(l, sl.end(ll; Над двумя объектами класса se t определены операции ,= <, <=, > и >=. Кроме Toro, один объект можно присвоить дрyrому объекту. Пример: std::set<int> 51, 52; std::set<int>::const iterator i; sl.insert (1); sl.insert (2) ; 52 = s 1; for (i=s2.begin(l; i'=s2.end(l; ++il std: :cout « *i « rr rr; { / / 1 2 Вставка 'IЛf!llfffrОВ Вставить элементы позволяют слеДJ'lOщие методы: -+ inse rt ()  вставляет один или несколько элементов. Прототипы метода: palr<lterator, bool> lnsert(const value type &Val); iterator insert(const iterator Where, const value type &Val); template<class It> void insert (It F irst, It Last); Первый прототип вставляет значение и возвращает объект класса pair. Через атрибут f irs t будет доступен итератор, указывающий на вставленный элемент, а через атрибут s есо nd  лоrическое значение t rue, если элемент вставлен, и false в противном случае. Пример : std: : set<int> 5; std: : set<int>: : const iterator i; std::pair<std: :set<int>: :iterator, bool> pr; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  57  1712.10 s. insert (1); pr = s.insert(21 if (pr.second) { 11 Про верка успешности вставки std: : cout « * (pr. f irstl « std:: endl; / / 2 else std: :cout « rrError rr « std::endl; for (i=s. begin (1 i ,=s. end( 1 ++il std::cout « *i « rr rr; / / 1 2 06раште внимание на то, что метод ins er t () в класс е mult is et возвращает итератор, а не обь ект класса pair. Прототип метода в классе mult is е t: lterator lnsert(const value type &Val); Второй прототип позволяет указ ать позицию вставки с помощью итератора. В каче стве результата возвращается итератор, указ ЫВaIOЩИЙ на вставленный элемент. Третий ПрОТОТ1lП вставляет элементы из диапазона, orp аниченноrо итераторами F irst и Las t. Пример : std: : set<int> 51, 52; std: : set<int>: : const iterator i; sl.insert (1); sl.insert (2); sl.insert(sl.begin(I,31; for (i=sl.begin( 1; i'=sl. end (1 ++il std::cout « *i « rr rr; // 1 2 3 std::cout « std: :endl; s2.insert(++sl.begin(l, sl.end(ll; for (i=s2 .begin (1; i' =s2. end (1 ++il std::cout « *i « rr rr; // 2 3 -+ swap (1  меняет элементы двух контейнеров ме стами. Прототип метода: void swap(set &Right); Пример: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  58  1712.10 std: : set<int> 51, 52; std: : set<int>: : const iterator i; sl.insert (1); sl.insert (2); 52 . ins er t (3 ); 52. ins er t (4) ; s2 .swap (sll; for (i=sl.begin( 1; i'=sl. end (1 ++il std::cout « *i « rr rr; // 3 4 std::cout « std: :endl; for (i=s2 .begin( 1; i'=s2. end (1 std::cout « *i « rr rr; ++il / / 1 2 УдаЛflШf 'IЛf!llfffrОВ Для удаления элементов предназначены следующие методы: -+ er as е ()  удаляет один элемент или элементы из диапазона. Прототипы метода: 51 ze t ур е е ras е (с onst ke у  type &Ке y-val) iterator erase(const iterator Where); it era t or erase (с ons t i te r at о r F irs t, const i te r at о r Last); Первый прототип уд аляет элемент с указанным значением. Пример: std: : set<int> 5; std: : set<int>: : const iterator i; s. ins е rt (1); s. inse rt (2) ; s. erase (1); for (i=s.begin (1 i '=s. end( 1 ++il std::cout « *i « rr rr; // 2 Второй прототип удаляет элемент на который указывает итератор. При мер: std: : set<int> 5; std: : set<int>: : const iterator i; s. ins е rt (1); s. inse rt (2) ; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  59  1712.10 s.erase(s.end() ); for (i=s. begin (1 i '=s. end( 1 ++il std::cout « * « rr rr; / / 1 Третий прототип уд аляет элементы из диапазона, оrpаниченноrо итераторами F irst и Last. Пример: typedef struct std::pair<std::string, int> PAIR; std: : set<std: : string, int> т; std: : set<std: : string, int>:: const iterator i; m.insert(PAIR(rrorr, m.insert(PAIR(rr2 rr , m.erase(m.begin(), for (i=m. begin (1 1)); m.insert (PAIR( rrl rr , 3)); m.insеrt(РАIR(rrз rr , m.end(1 1; 211 411 i'=m.end(1 ++il std::cout « i>first « rr > rr « i>second « rr; ". , { / / 3 > 4; -+ clear (1  удаляет все элементы. Пр ототип метода: void clear () ; -+ empt у ()  возвращает значение t rue, если контейнер не содержит элементов, и false  в противном случае. Прототип метода: bool empty () const; -+ si ze ()  возвращает количество элементов в контейнере. Прототип метода: Slze type Slze () const; Пример использования методов clear ( 1 , етр ty (1 и siz е ( 1 : std: : set<int> s; std: : set<int>: : const iterator i; s. ins е rt (1); s. inse rt (2) ; std: : cout « s. size () « std:: endl; 11 2 s. cle ar ( ) ; if (s.empty(11 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  60  1712.10 std::cout « rrИет элементов,r « std: :endl; std: : cout « s. size () « std:: endl; 11 о -+ тах SlZ е ()  возвращает максимальное количество элементов, которое может содержаться в контейнере. Прототип метода: Slze type тах Slze () const; Доступ к 'IЛf!llfНП1!ll Для доступа к элементам предназначены следующи е методы: -+ со иn t ()  возвращает количество элементов, у которых ключ cooweTCТEJ'!OT значению Ке yval. Прототип метода: 51 ze t ур е с оиn t (с onst ke у  type &Ке y-val) с onst; Пример: std: : set<int> 5; s. ins е rt (1); s. inse rt (2) ; std: : cout « s. count (21 «std:: endl; / / 1 -+ f ind (1  возвращает итератор, установленный на элемент, ключ KOToporo соответствует значению Ке yval. Если элемент не найден, то метод возвращает итератор, ука:зывaIOЩИЙ на ПОЗИЦИЮ после последнеrо элемента. Прототипы метода: lterator flnd (const key type &Key-val); const iterator find(const key type &Keyval) const; Пример: std: : set<int> 5; std::set<int>: :iterator i; s. ins е rt (1); s. inse rt (2) ; i=s.find(ll; if (i ,= s.end(1 1 std: : cout « * i « std:: endl; // 1 i = s. f ind (31 ; if (i == s.end (11 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 ii  61  171 2.10 std::cout « rrNo rr « std: :endl; 11 Мо -+ lowe r Ьо und ()  возвращает итератор, установленный на элемент, ключ KOToporo больше или равен значению Key-val. Если элемент не найден, то метод возвращает итератор, указЫВaIOЩИЙ на ПОЗИЦИЮ после последнеrо элемента. Прототипы метода: it era t or lower  Ь ound (с ons t ke у  type &Keyval); со nst it er а to r lower  Ь ound (с onst ke у  type &Ке y-val) const; Пример: std: : set<int> 5; std::set<int>: :iterator i; s.insert(O); s.insert(l) i = s.lowerbound(2); if (i ,= s.end(1 1 std: : cout « * i « std:: endl; 11 4 s.insert (4); s. insert (5) i = s.lowerbound(l); if (i ,= s.end(1 1 std: : cout « * i « std:: endl; 11 1 -+ ир ре r Ьо und (1  возвращает итератор, установленный на элемент, ключ KOToporo больше значения Keyval. Если элемент не найден, то метод возвращает итератор, ука:зывaIOЩИЙ на ПОЗИЦИЮ после последнеrо элемента. Прототипы метода: it era t or ирр er  Ь ound (с ons t ke у  type &Keyval); const iterator upper bound (const key type &Key-val) const; Пример: std: : set<int> s; std::set<int>: :iterator i; s.insert(O); s.insert(l) i = s.upperbound(l); if (i ,= s.end(1 1 s.insert (4); s. insert (5) Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  62  1712.10 std: : cout « * i « std:: endl; 11 4 -+ equal range (1  возвращает экземпляр класс а р ан Через атрибут f lrs t будет доступен итератор, явля::ющийся результатом выполнения метода lower bound () , а через атрибут sec ond  итератор, явля::ющийся результатом выполнения метода ир per bound (1 Прототипы метода palr<lterator, lterator> equal range(const key type &Keyval); palr<const lterator, const lterator> equalrange (const key type &Keyval) const; Пример: typedef std: :set<int> Set; Set 5; std: : pair<Set: : iterator, Set:: iterator> pr; s.insert(O); s.insert(l); s.insert(4); s.insert(5); pr = s.equalrange(l) ; // Ключ существует if (pr. f irst ,= s. end( 11 { std: : cout « * (pr .firstl « std: : endl; // 1 if (pr.second ,= s.end (11 std: : cout « * (pr. second) «std:: endl; 11 4 pr = s.equalrange(2); if (р r. f irs t ,= s. end ( 11 11 Ключ не существует { std: : cout « * (pr. f irst) « std:: endl; // 4 if (pr.second ,= s.end (11 std: : cout « * (pr. second) «std:: endl; 11 4 -+ Ье gin (1  возвращает итератор, установленный на первый элемент контейнера. Прототипы метода: iterator begin(); Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  63  1712.10 const lterator begln () const; -+ сЬ eg in ()  возвращает кон стантный итератор, установленный на первый элемент контейнера. Прототип метода: со nst lt er а to r сЬе gln () с ons t; -+ rb eg in (1  возвращает обратный итератор, установленный на последний элемент контейнера. Прототипы метода: reverse lterator rbegln(); со nst reve r se it er а to r rbe gin () с ons t; -+ crbegin (1  возвращает константный обратный итератор, установленный на последний элемент контейнера. Прототип метода: const reverse lterator crbegln () const; -+ end (1  возвращает итератор, установленный на позицшо после последнеrо элемента контейнера Прототипы метода: iterator end () ; const iterator end () const; -+ се nd ()  возвращает константный итератор, установленный на позицию после последнеrо элемента контейнера. Прототип метода: const iterator cend () const; -+ re nd (1  возвращает обратный итератор, установленный на позицию перед первым элементом контейнера. Прототипы метода: reverse iterator rend(); со nst reve r se it er а to r rend () со ns t; -+ cr end (1  возвращает константный обратный итератор, установленный на позицию перед первым элементом контейнера. Прототип метода: со nst reve r se it er а to r cre nd () const; KlI:lCC pl'iOl'ity qпепе. Очередь с "рпорптеТ:lI\Ш Класс pr 10 r 1 ty queue реализует очередь с приоритетами на основе последовательноrо контейнера. По умолчанию в качестве контейнера используется кл асс ve cto r . При получении значения возвращается элемент с наивысшим приоритетом (наибольши м значением). По умолч анию для сравнения элементов Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  б4  1712.10 используется функтор les s. Объявление кл асса pr ior it у  que ие выrлядит следYIOЩИМ образом: template <class Т, class Container=vector<T>, class Compare=less<typename Contalner::value type> > class priorityqueue; Прежде чем использовать кл асс необходимо добавить зarоловок: # inc 1 ude <que ие > Создать экземпляр класс а pr 10 r 1 ty queue можно следYIOЩИМИ способами -+ объявить экземпляр класс а без инициализации. Для этоrо перед названием переменной указывается название клас са. После названия класса внутри yrловых скобок задается тип данных. В этом случ ае объект не содержит элементов. Пример объявления без инициализации: std::prlorlty queue<lnt> q; Внутри yrловых скобок после типа Д анных можно дополнительно указ ать тип контейнера и функц ию сравнения. По умолчанию в качестве контейнера используется вектор, а сравнение производится с помощью функтора le ss. Вместо вектора можно использовать класс de que. Пример указ ания класса de que и функтора gre at er: st d: : р r lor 1 ty queue <ln t, st d: : deque <int >, std::greater<int> > q; Внимание Меж ду закрывающими yr лов ыми ско бками пр о б ел до бавлен специально. Если пр о б ел не ДО бавить, т о н еко тор ые ко:r...mлят ор ы считаю т это ОIШIб кой. -+ указать объект класса pr 10 r 1 ty queue внутри круr-лых скобок или после оператора =: std::pr10r1ty queue<lnt> ql; q1.push( 11; q1. push (21; std::pr10r1ty queue<lnt> q2 (ql); std: : cout « q2. top (1 « std:: endl; / / 2 std::pr10r1ty queue<lnt> q3 = ql; std: : cout « q3. top (1 « std:: endl; / / 2 Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  65  1712.10 -+ указать диапазон внутри контейнера с помощью итераторов. В первом параметре передается итератор, ука:зывaIOЩИЙ на начало диапазона, а во втором параметре  итератор, указывающий на кон ец диапазона. Пример: std::vector<nt> v; v.pushback(ll; v.pushback(21; std::prlorlty queue<lnt> q(v.begln(), v.end()); std: : cout « q. top (1 «std:: endl; / / 2 Один объект можно присвоить дрyrому объекту. Пример: std::priorityqueue<int> ql, q2; q1.push (11; q1.push (21 ; q2 = q1; std::cout «q2.top(1 «std::endl; //2 Класс pr 10 r 1 ty que ие содержит следующи е методы -+ push (1  добавляет элемент. Прототип метода: vOld push(const value type &Val); -+ to р (1  возвращает ссылку на элемент с наивысши м приоритетом. Элемент из очереди не удаляется. Прототипы метода: reference top () ; const reference top () const; -+ рор (1  удаляет элемент с наивысшим приоритетом. Прототип метода: void рор (1; -+ swap (1  меняет элементы двух контейнеров ме стами. Прототип метода: vOld swap(prlorlty queue &Rlght); -+ si ze ()  возвращает количество элементов в очереди. Прототип метода: Slze type Slze () const; -+ empt у ()  возвращает значение tr ие, если очередь не содержит элементов, и false  в противном случае. Прототип метода: bool empty () const; Основные операции над 06ъекто м клас са р r io r i t У  que ие показ аны в листинrе 13.8. Листинrи на странице http://unicros s.narod.ru/cpp/ 
@ Прохоре'ю/С НА, 2010 '.  бб  1712.10 I .1IИСТIПП 13.8. Кrmcc Рliol'it)'qпепе #include <iostream> # inc 1 ude <que ие > int main(1 std: : pr ior ity  queue<lnt> q1, q2; q1.push (11 ; q1.push (21 ; q2 .push (З 1 ; q2 .push(41; std: : cout « q1.top (1 « std: : endl; // 2 std: : cout « q2 .top (1 « std: : endl; // 4 q1.swap (q21 ; std: : cout « q1.top (1 « std: : endl; // 4 std: : cout « q2 .top (1 « std: : endl; // 2 q1. рор (1 ; std: : cout « q1.top (1 « std: : endl; // З if (q1. empty (11 { std: : cout « rrИет элементов,r « std:: endl; else { std::cout «q1.size(1 «std::endl; // 1 std: : cin. get (1 ; return о; KlIacc qпепе. Очередь Класс queue реализует очередь на основе последовательноrо контейнера. По умолчанию в качестве контейнера используется класс deque. При получении значения возвращается элемент, который был добавлен раньше друrих элементов. Объявление кл асса queue выrлядит следYIOЩИМ образом: template <class Т, class Container = deque<T> > class queue; Прежде чем использовать кл асс необходимо добавить зarоловок: # inc 1 ude < queue > Создать экземпляр класс а queue можно следYIOЩИМИ способами: Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  б7  1712.10 -+ объявить экземпляр класс а без инициализации. Для этоrо перед названием переменной указывается название клас са. После названия класса внутри yrловых скобок задается тип данных. В этом случ ае объект не содержит элементов. Пример объявления без инициализации: std::queue<nt> q; Внутри yrловых скобок после типа Д анных можно дополнительно указ ать тип контейнера. По умолчанию в кач естве контейнера используется класс deque. Вместо клас са de que МОЖНО использовать класс lis t. Вектор в этом случае использовать нельзя, так как у Hero нет метода для удаления элемента из начала контейнера. Пример указ ания клас са list: std::queue<int, std: :list<int> > q; -+ указать объект класс а queue внутри круrлых скобок или после оператора =: std: : queue<int> ql; q1.push( 11; q1. push (21; std::queue<int> q2 (q11; std: : cout « q2. front (1 «std:: endl; / / 1 std: : queue<int> q3 = ql; std: : cout « q3. front (1 «std:: endl; / / 1 Над двумя объектами кл асса queue определены операции ==, 1=, <, <=, > и >=. Кроме Toro, один объект можно присвоить дрyrому объекту. Пример: std::queue<int> ql, q2; q1.push (11; q1.push (21 ; q2 = q1; std::cout «q2.front(1 «std::endl; // 1 Класс queue содержит следующие методы: -+ push (1  добавляет элемент в конец очереди. Прототип метода: vOld push(const value type &Val); -+ fr оп t (1  возвращает ссылку на первый элемент в очереди. Элемент из очереди не удаляется. Прототипы метода: reference front () ; const reference front () const; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  68  1712.10 -+ back (1  возвращает ссылку на последний элемент в очереди. Элемент из очереди не удаляется. Прототипы метода: reference back(); со nst re fe r еnс е back () const; -+ ро р (1  уд аляет первый элемент из очереди. Прототип метода: void рор (1; -+ swap (1  меняет элементы двух контейнеров ме стами. Прототип метода: void swap(queue &Right); -+ si ze ()  возвращает количество элементов в очереди. Прототип метода: Slze type Slze () const; -+ empt у ()  возвращает значение tr ие, если очередь не содержит элементов, и false  в противном случае. Прототип метода: bool empty () const; Основные операции над объектом класса queue показаны в листинrе 13.9. I .1IИСТIПП 13.9. кrm се q нене #include <iostream> # inc 1 ude <que ие > int main (1 std::queue<int> ql, q2; q1.push (11; q1.push (21 ; q2.push(31; q2.push(41; std::cout «ql.front() «std::endl; std::cout «q2.front() «std::endl; q1.swap (q21 ; std::cout «ql.front() «std::endl; std::cout «q2.front() «std::endl; // 1 // 3 // 3 // 1 q1. рор (1 ; std: : cout « q1. front (1 «std:: endl; / / 4 if (q1. empty (11 { std: : cout « rrИет элементов,r « std:: endl; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА, 2010 '.  69  1712.10 else std::cout «ql.size() «std::endl; // 1 std: : cin. get () ; return о; KlIacc stack. Стек Класс st ас k реализует стек на основе последовательноrо контейнера. По умолч анию в кач естве контейнера используется класс deque. При получении значения возвращается элемент, который был добавлен позже друrих элементов. Объявление класса stack выrлядит следующим образом: template <class Т, class Container=deque<T> > class stack; Прежде чем использовать кл асс необходимо добавить зarоловок: # include <stack> Создать экземпляр класс а st ас k можно следYIOЩИМИ способами: -+ объявить экземпляр класс а без инициализации. Для этоrо перед названием переменной указывается название клас са. После названия класса внутри yrловых скобок задается тип данных. В этом случ ае объект не содержит элементов. Пример объявления без инициализации: std::stack<int> 5; Внутри yrловых скобок после типа Д анных можно дополнительно указ ать тип контейнера. По умолчанию в кач естве контейнера используется класс deque. Вместо клас са deque можно использовать классы li5 t и ve cto r. Пример указ ания класса li5t: 5td::5tack<int, 5td: :li5t<int> > 5; -+ указать объект класс а st ас k внутри круrлых скобок или после оператора =: 5td::5tack<int> 51; sl.push(l); sl.push(2); 5td::5tack<int> 52 (51); std: : cout « s2. top () « std:: endl; / / 2 5td::5tack<int> 53 = 51; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА., 2010 '.  70  171210 std: : cout « s3. top (1 « std:: endl; / / 2 Над двумя объектами кл асса st ас k опредепены операции ==, 1=, <, <=, > и >=. Кроме Toro, один объект можно присвоитъ дрyrому объекту. Пример: std::stack<int> 51, 52; sl.push(ll; sl.push(21; 52 = s 1; std::cout «s2.top(1 «std::endl; //2 Кпасс st ас k содержит спедующие методы: -+ push (1  добавпяет элемент в стек Прототип метода: vOld push(const value type &Val); -+ to р (1  возвращает ссылку на элемент, располож енный на вершине стека. Элемент из стека не удаляется. Прототипы метода: reference top () ; const reference top () const; -+ ро р (1  уд аляет элемент, расположенный на вершине стека. Прототип метода: void рор (1; -+ swap (1  меняет элементы двух стеков местами. Прототип метода: void swap(stack &Right); -+ si ze ()  возвращает количество элементов в стеке. Прототип метода: Slze type Slze () const; -+ empt у ()  возвращает значение t rue, если стек не сод ержит элементов, и false  в противном случае. Прототип метода: bool empty () const; О сновные операции над объекто м клас са s tac k показаны в листинrе 13.10. I .1IИСТIПП 13 .10. КJшсс s tack #include <io5tream> # inc 1 ude <5 tac k> int main (1 5td::5tack<int> 51, 52; Листинrи на странице http://unicros s.narod.ru/cpp/ 
@Прохоре,ю/С НА., 2010 '.  71  1712.10 sl.push(ll; sl.push(21; s2 .рush(ЗI; s2 .push(41; std::cout «sl.top(1 « std::cout «s2.top(1 « std: : endl; std: : endl; // 2 // 4 sl.swap (s21 ; std::cout «sl.top() «std::endl; std::cout «s2.top() «std::endl; // 4 // 2 sl.pop(l; std: :cout «sl.top(1 «std: :endl; // з if (sl.empty(11 { std: : cout « rrИет элементов,r « std:: endl; else { std::cout «sl.size(1 «std::endl; // 1 std: : cin. get (1 ; return о; Листинrи на странице http://unicros s.narod.ru!cpp!