Препроцессорная обработка. Ввод-вывод
Выбери формат для чтения
Загружаем конспект в формате pdf
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
Лекция 7. Препроцессорная обработка
Ввод-вывод
План лекции:
• Препроцессорная обработка
• Ввод-вывод
• Стандартные потоки ввода-вывода
• Файловые потоки ввода-вывода
• Текстовые (строковые) потоки ввода-вывода
Заголовочные файлы
• Файлы .cpp не являются единственными файлами в проектах. Есть ещё
один тип файлов — заголовочные файлы. Целью заголовочных файлов
является удобное хранение набора объявлений объектов для их
последующего использования в других программах.
• Например, cout мы не определяем. Как компилятор знает, что это такое?
Дело в том, что cout объявлен в заголовочном файле iostream. Когда мы
пишем #include , мы делаем запрос, чтобы всё содержимое
заголовочного файла iostream было скопировано в наш файл. Таким
образом, всё содержимое библиотеки iostream становится доступным
для использования.
• Как правило, в заголовочных файлах записываются только объявления,
без определений. Определяется cout в Стандартной библиотеке С++,
которая автоматически подключается к вашему проекту на этапе
редактирования связей (линкинга).
Технологический процесс
подготовки и выполнения программ
Заголовочные файлы
Используя угловые скобки, мы сообщаем компилятору, что
подключаемый заголовочный файл написан не нами (он является
«системным», т.е. предоставляется Стандартной библиотекой
С++), так что искать этот заголовочный файл следует в системных
директориях.
Двойные кавычки сообщают компилятору, что мы подключаем
наш собственный заголовочный файл, который мы написали
самостоятельно, поэтому искать его следует в текущей директории
нашего проекта. Если файла там не окажется, то компилятор
начнёт проверять другие пути, в том числе и системные
директории.
Правило: Используйте угловые скобки для подключения
системных заголовочных файлов и двойные кавычки для ваших
заголовочных файлов.
Заголовочные файлы
Когда C++ только создавался, все файлы библиотеки Runtime имели
окончание .h. Оригинальные версии cout и cin объявлены в iostream.h.
При стандартизации языка С++ комитетом ANSI решили перенести все
функции из библиотеки Runtime в пространство имён std, дабы
предотвратить возможность возникновения конфликтов имён с
пользовательскими идентификаторами. Тем не менее, возникла
проблема: если все функции переместить в пространство имён std, то
старые программы переставали работать!
Для обеспечения обратной совместимости ввели новый набор
заголовочных файлов с теми же именами, но без окончания «.h». Весь
их функционал находится в пространстве имён std. Таким образом,
старые программы с #include не нужно было
переписывать, а новые программы уже могли использовать #include
.
Заголовочные файлы
Кроме того, многие библиотеки, унаследованные от языка
Cи, которые до сих пор используются в C++, также были
продублированы с добавлением префикса ’c’ (например,
stdlib.h стал cstdlib). Функционал этих библиотек также
перенесли в пространство имён std, дабы избежать
возможность возникновения конфликтов имён с
пользовательскими идентификаторами.
Правило: При подключении заголовочных файлов из
Стандартной библиотеки С++, используйте версию без «.h»
(если она существует). Пользовательские заголовочные
файлы должны иметь окончание «.h».
Препроцессорная обработка
• Язык Си был разработан как язык для программистовпрактиков. Одной из его мощных особенностей, которая
нравится всем Си-программистам, является наличие
препроцессора.
• Препроцессор просматривает программу до компилятора
и заменяет символические аббревиатуры в программе на
текст из соответствующих макроопределений. Он
отыскивает другие файлы, подключает их, а также может
изменять условия компиляции. Диалог программиста с
препроцессором осуществляется с помощью директив.
17:29
Директива define
Все директивы препроцессора начинаются с символа # в самой левой
позиции.
Директива препроцессора define имеет вид
#define имя значение_подстановки
Например,
#define max 100
#define rmax (max-1)
Имя, указанное в define, в области его видимости заменяется в тексте
программы значением подстановки. Вместо имени max после
препроцессорной обработки в тесте программы появится 100, а вместо
rmax – (100-1).
Директива #define может появиться в любом месте исходного файла, а
даваемое ею определение имеет силу от места появления до конца
файла.
17:29
Препроцессорная обработка
Рассмотрим пример
17:29
17:29
Препроцессорная обработка
В общем виде строку #define можно представить
следующим образом:
директива макроопределение строка_замещения
Все три части разделены между собой пробелами (по
меньшей мере одним).
Макроопределение не должно содержать внутри себя
пробелы.
Когда препроцессор находит в программе
макроопределение, он заменяет его строкой замещения.
17:29
Препроцессорная обработка
Процесс прохождения от макроопределения до строки
замещения называется макрорасширением.
Макроопределение может представлять собой любую
строку, даже целое выражение на языке С/С++. При этом
надо иметь ввиду, что препроцессор не выполняет
никаких вычислений; он только очень точно делает
предложенные подстановки.
Единственным исключением из этого является
макроопределение, находящееся внутри двойных
кавычек. Поэтому printf(”TWO: MSG”); печатает буквально
TWO: MSG.
17:29
Препроцессорная обработка
Макроопределение с аргументами
носит название макрофункции
17:29
Препроцессорная обработка
При обработке препроцессором макрофункции, она заменяется
строкой замещения.
Например, SQUARE(x) заменяется на x*x. Но в данном случае могут
свободно применяться аргументы, отличные от x.
SQUARE(2) заменяется на 2*2. Таким образом, x действует как
аргумент.
Однако аргумент макрофункции работает отлично от аргумента
обычной функции, ввиду того, что препроцессор не делает
вычислений, а только замещает строку. Например:
SQUARE(x+2) воспринимается не как 6*6, а как x+2*x+2.
SQUARE(100/SQUARE(2)) воспринимается как 100/2*2
(SQUARE(++x)) воспринимается как ++x*++ x
17:29
#define и const
Две следующие строки не эквивалентны:
const int y = 17;
#define y 17
В первой строке определяется константная
переменная, занимающая некоторую область
памяти,
а во второй – макрос.
Препроцессорная обработка
Когда препроцессор распознает директиву #include, то
он ищет следующее за ней имя файла и включает его в
текущий файл для последующей компиляции.
Директива может выдаваться в двух видах:
#include (имя файла в угловых скобках)
#include ”pch.h” (имя файла в двойных кавычках)
Угловые скобки сообщают препроцессору, что файл
следует искать в одном или нескольких стандартных
системных каталогах.
Кавычки говорят о том, что сначала нужно смотреть в
рабочем каталоге пользователя, а затем искать в
стандартных местах.
17:29
Препроцессорная обработка
Существуют и другие директивы препроцессора. Это
директивы #undef, #if, #ifdef, #ifndef, #else, #elif и #endif.
Данные директивы обычно используются при
программировании больших модулей. Они позволяют
приостановить действие более ранних определений и
создать файлы, каждый из которых можно компилировать
по-разному, то есть осуществлять так называемую условную
компиляцию.
Директива #undef отменяет самое последнее определение
макроопределения.
17:29
Препроцессорная обработка
#define BIG 3
#define HUGE 5
#undef BIG
/* BIG не определен */
#define HUGE 10
/* HUGE
перераспределен как 10*/
#undef HUGE
/* HUGE
снова 5*/
#undef HUGE
/* HUGE теперь не определен */
//Остальные директивы выполняют условную компиляцию:
#ifdef MAVIS
#include "hofse.h"
/*выполняется, если MAVIS определен */
#define STAB 5
#else
#include "cow.h"
#define STAB 15
#endif
17:29
/*выполняется, если MAVIS не определен */
Препроцессорная обработка
Такая структура напоминает конструкцию if — else языка Си.
Основная разница заключается в том, что препроцессор не
распознает фигурные скобки {}, отмечающие блок, а
использует директивы #else и #endif для отметки блоков
директив.
Директивы #ifdef #else #endif могут быть вложенными.
Если это имеет место, то каждый #endif, #else
ассоциируется с ближайшим #if или #elif
Директивы #ifndef и #if могут быть использованы с #else и
#endif аналогичным образом.
Директива #ifndef проверяет, является ли последний
идентификатор неопределенным, то есть она
противоположна #ifdef.
17:29
Препроцессорная обработка
Директива #if похожа на обычный оператор if языка Си. За ней
следует константное выражение, которое считается истинным,
если оно не равно нулю:
#if SYS == "WINDOWS"
#include "windows.h"
#endif
Макроопределения бывают полезны и при задании границ
статических массивов, например:
#define TABLE_SIZE 100
int table1[TABLE_SIZE];
int table2[TABLE_SIZE];
Это эквивалентно
int table1[100];
int table2[100];
17:29
Препроцессорная обработка
В макрофункциях возможно использование двух операторов (# и
##) для подстановок значений. Если оператор # используется
перед аргументом, он заменяется его строковым значением в
кавычках. Например:
#define str(x) #x
cout << str(test);
После препроцессорной обработки будет выглядеть так
cout << "test";
17:29
Препроцессорная обработка
Оператор ## объединяет два аргумента, не оставляя между
ними пробелов
#define glue(a,b) a ## b
glue(c,out) << "test";
В результате c и out будут объединены в cout и в итоге
получится
cout << "test";
17:29
Препроцессорная обработка
Макроопределение #error позволяет прервать компиляцию с
выдачей сообщения при определенных условиях
#ifndef __cplusplus
#error A C++ compiler is required!
#endif
Макроопределение __cplusplus генерируется комприлятором C++,
если программа компилируется компилятором Си, то будет
выведено сообщение об ошибке.
Одной из целей “условной компиляции” является стремление
сделать программу более мобильной. Изменяя несколько
ключевых определений в начале файла, можно устанавливать
различные значения и включать различные файлы для разных
операционных систем.
17:29
Примеры
#if МАХ>100
#if SERIAL_VERSION int port = 198;
#elif
// вложенный if
//относится ко второму if
int port = 200;
#endif
#else
// конец вложенного if
//относится к первому if
char out_buffer[100] ;
#endif
17:29
//конец первого if
Ввод-вывод
• В языке Си для ввода-вывода использовались две
основные библиотеки stdio.h и conio.h. Синтаксис языка
С++, наряду с библиотеками языка Си, позволяет
использовать специально организованные потоковые
классы.
• Поток в целом можно воспринять как абстрактное
понятие, относящееся к любому переносу данных от
источника к приемнику. Поток определяется как
последовательность байтов и не зависит от конкретного
устройства, с которым производится обмен.
17:29
Ввод-вывод
• Обмен с потоком для увеличения скорости передачи
данных производится, как правило, через
специальную область оперативной памяти - буфер.
• Фактическая передача данных выполняется при
выводе после заполнения буфера, а при вводе - если
буфер исчерпан.
• По направлению обмена потоки можно разделить на
входные (данные вводятся в память), выходные
(данные выводятся из памяти) и двунаправленные
(допускающие как извлечение, так и включение).
• По виду устройств, с которыми работает поток, можно
разделить потоки на стандартные, файловые и
строковые.
17:29
Ввод-вывод
• Стандартные потоки предназначены для передачи
данных от клавиатуры и на экран дисплея, файловые
потоки - для обмена информацией с файлами на
внешних носителях данных, а строковые потоки для работы с массивами символов в оперативной
памяти.
• Для поддержки потоков библиотека С++ содержит
иерархию классов, построенную на основе двух
базовых классов - ios и streambuf.
• Класс ios содержит общие для ввода и вывода поля и
методы, класс streambuf обеспечивает буферизацию
потоков и их взаимодействие с физическими
устройствами.
17:29
Ввод-вывод
Описания потоковых классов находятся в следующих
заголовочных файлах:
•
- базовый класс потоков ввода/вывода;
• - предварительные объявления средств
ввода/вывода;
• - шаблон потока ввода;
• - шаблон потока вывода;
• - стандартные объекты и операции с
потоками ввода/вывода;
• - потоки ввода/вывода в файлы:
• - потоки ввода вывода в строки:
• - буферизация потоков ввода/вывода.
17:29
Ввод-вывод
ios - абстрактный базовый класс потоков.
istream - класс входных потоков. Является
производным от базового класса iostream и
наследует его члены. В свою очередь является
базовым для классов ifstream и istrstream. Для
использования функций класса istream в текст
программы необходимо включить заголовочный
файл istream.h:
#include
17:29
Ввод-вывод
ostream - класс выходных потоков. Является
производным от базового класса iostream и
наследует его члены. В свою очередь является
базовым для классов ofstream и ostrstream. Для
использования функций класса ostream в текст
программы необходимо включить заголовочный
файл ostream.h:
#include
17:29
Ввод-вывод
iostream - класс двунаправленных потоков. Является
производным от абстрактного базового класса ios и
наследует все его члены. В свою очередь является
базовым для классов istream и ostream. Для
использования функций класса iostream в текст
программы необходимо включить заголовочный
файл iostream.h:
#include
17:29
Ввод-вывод
fstream - класс двунаправленных файловых потоков.
Поддерживает потоки с возможностью как ввода,
так и вывода информации. Является базовым для
классов ifstream и ofstream. Для использования
функций класса fstream в текст программы
необходимо включить заголовочный файл fstream.h:
#include
17:29
Ввод-вывод
cin - объект, предоставляющий последовательный
доступ к стандартному устройству ввода
информации. Обычно поток связан с клавиатурой. В
операционных системах типа UNIX. DOS или
WINDOWS предусмотрена возможность
перенаправлять чтение информации с клавиатуры
на чтение из файла. Объект cin является членом
класса istream
17:29
Ввод-вывод
cout - объект, предоставляющий последовательный
строковый доступ к устройству стандартного
вывода. В операционных системах типа UNIX, DOS
или WINDOWS предусмотрена возможность
перенаправлять запись информации в файл. В
данном случае объект cout функционирует как
файл. Объект cout является членом класса ostream
17:29
Ввод-вывод
cerr - объект (консоль ошибок), предоставляющий
последовательный доступ к стандартному
устройству вывода ошибок. Данный поток связан с
монитором и обычно идентичен стандартному
потоку cout. Основное различие заключается в том,
что даже если стандартный вывод направлен в
файл, то все, что направлено в поток cerr,
появляется на экране монитора. Объект cerr
является членом класса ostream
17:29
Стандартные потоки ввода-вывода
Для вывода используется переопределенная операция <<
Описание:
операнд1 << операнд2;
где операнд1 - объект класса ostream,
операнд 2 - выводимое значение.
Например:
cout << "Hello!\n"; // запись текста с переводом строки
17:29
Стандартные потоки ввода-вывода
Операция << автоматически переопределяется в
зависимости от типа выводимого значения и возвращает
ссылку на объект класса ostream, с которым она оперирует.
Это позволяет использовать каскадные последовательности
выводов.
Например:
cout <<"i=" << i << ", d=" << d << "\n";
17:29
Стандартные потоки ввода-вывода
По умолчанию поддерживается вывод объектов следующих типов:
char (signed, unsigned), short (signed, unsigned), int (signed,
unsigned), long (signed, unsigned), char*, float, double, long double и
void*.
Для вывода используются правила-умолчания из функции printf
языка С (это может быть изменено установкой различных флагов в
ios).
Например, если есть описания:
int i; long l;
то следующие операторы эквивалентны:
cout << i << l; // потоки языка С++
printf("%d %ld", i, l); // стандартная функция языка Си
Вещественные значения выводятся по аналогии со спецификацией
%g, указатели - как шестнадцатеричные значения.
17:29
Стандартные потоки ввода-вывода
Для ввода используется переопределяемая операция >>
Описание:
операнд1 >> операнд2;
где операнд1 - объект класса istream,
операнд 2 - вводимое значение.
Например:
cin >> d;
17:29
Стандартные потоки ввода-вывода
Операция >> автоматически переопределяется в
зависимости от типа выводимого значения и
возвращает ссылку на объект класса istream, с
которым она оперирует. Все правила,
перечисленные для потоков вывода соответствуют и
вводу.
17:29
Стандартные потоки ввода-вывода
Для вставки и извлечения невозможно изменить
приоритеты, поэтому в необходимых случаях
используются скобки:
cout << i + j;
Скобки не требуются - приоритет сложения больше,
чем <<
cout << (i < j);
Скобки необходимы - приоритет операции
отношения меньше, чем <<
17:29
Стандартные потоки ввода-вывода
Величины при вводе должны разделяться
пробельными символами (пробелами, знаками
табуляции или перевода строки). Извлечение
прекращается, если очередной символ оказался
недопустимым.
Поскольку ввод буферизован, помещение в буфер
ввода происходит после нажатия клавиши перевода
строки, после чего из буфера выполняется операция
извлечения из потока. Это дает возможность
исправлять введенные символы до того, как нажата
клавиша Enter.
17:29
Стандартные потоки ввода-вывода
Для управления форматированием используются
следующие функции
17:29
Стандартные потоки ввода-вывода
Пример
#include
int main()
{
int i= 123;
cout.width(7);
cout.fill('*');
cout << i;
}
Результат: ****123
17:29
Стандартные потоки ввода-вывода
По умолчанию заполнение происходит символом .
(точка) и выравнивание по правому краю.
При помощи функций setf и unsetf можно изменить
флаг форматирования
cout.setf(ios::left,ios::adjusifield);
17:29
Стандартные потоки ввода-вывода
Простой способ установки форматных переменных
состоит в использовании манипуляторов.
Манипуляторами называются функции, которые можно
включать в цепочку операций помещения и извлечения
для форматирования данных.
Пользоваться манипуляторами более удобно, чем
методами установки флагов форматирования.
Манипуляторы делятся на простые, не требующие
указания аргументов, и параметризованные.
Манипулятор получает ссылку на поток в качестве
аргумента, и возвращают ссылку на тот же поток. Это
позволяет использовать манипуляторы в каскадах.
17:29
Стандартные потоки ввода-вывода
Например:
cout << setw(4) << i << setw(6)
<< j;
эквивалентно:
cout.width(4); cout << i; cout.width (6); cout << j;
В данном примере setw() есть параметризованный
манипулятор, описанный в .
17:29
Стандартные манипуляторы
17:29
Стандартные потоки ввода-вывода
В потоковых классах наряду с операциями
извлечения >> и включения << определены методы
для неформатированного чтения и записи в поток
(при этом преобразования данных не выполняются).
17:29
17:29
Функции неформатированной
записи
17:29
Файловые потоки ввода-вывода
Для программиста открытый файл представляется как
последовательность считываемых или записываемых данных. При
открытии файла с ним связывается поток ввода-вывода. Выводимая
информация записывается в поток, вводимая информация считывается
из потока.
Для работы с файлами необходимо подключить заголовочный
файл . В нем определены несколько классов и подключены
заголовочные файлы
— файловый ввод ;
— файловый вывод.
Файловый ввод-вывод аналогичен стандартному вводу-выводу,
единственное отличие – это то, что ввод-вывод выполнятся не на экран, а
в файл.
17:29
Файловые потоки ввода-вывода
Как было указано ранее, существуют специальные классы.
описанные в fstream.h, позволяющие производить ввод-вывод
информации в файл: ifstream - класс входных файловых
потоков, ofstream - класс выходных файловых потоков, fstream класс двунаправленных файловых потоков.
Эти классы являются производными от классов istream, ostream
и iostream, соответственно, поэтому они наследуют
перегруженные операции << и >>, флаги форматирования,
манипуляторы, методы, состояние потоков и т. д.
17:29
Файловые потоки ввода-вывода
Использование файлов в программе предполагает
следующие операции:
создание потока;
открытие потока и связывание его с файлом;
обмен (ввод/вывод);
уничтожение потока;
закрытие файла.
Каждый класс файловых потоков содержит конструкторы, с
помощью которых можно создавать объекты этих классов
различными способами. Конструктор представляет функцию,
которая может принимать параметры и которая должна
называться по имени класса. Конструкторы позволяют
инициализировать объект класса.
17:29
Работа с файлом
При работе с файлом можно выделить следующие этапы:
•создать объект класса fstream (возможно, ofstream или ifstream);
•связать объект класса fstream с файлом, который будет
использоваться для операций ввода-вывода;
•осуществить операции ввода-вывода в файл;
•закрыть файл.
17:29
Файловые потоки ввода-вывода
Конструкторы без параметров создают объект
соответствующего класса, не связывая его с файлом:
ifstream(); ofstream(); fstream();
Конструкторы с параметрами создают объект
соответствующего класса, открывают файл с
указанным именем и связывают файл с объектом:
ifstream(const char *name, int mode = ios::in);
ofstream(const char *name. int mode = ios::out | ios::trunc);
fstream(const char *name. int mode = ios::in | ios::out);
17:29
Файловые потоки ввода-вывода
Вторым параметром конструктора является режим открытия
файла. Если установленное по умолчанию значение не
устраивает программиста, можно указать другое, составив
его из битовых масок, определенных в классе ios:
enum openmode {
in = 0x01, // Открыть для чтения
out = 0x02, // Открыть для записи
ate = 0x04, // Установить указатель на конец файла
арр = 0x08, // Открыть для добавления в конец
trunc = 0x10, // Если файл существует, удалить
nocreate = 0x20, // Если файл не существует, выдать ошибку
noreplace = 0x40. // Если файл существует, выдать ошибку
binary= 0x80. // Открыть в двоичном режиме
};
17:29
Файловые потоки ввода-вывода
Открыть файл в программе можно с использованием либо
конструкторов, либо метода open, имеющего такие же
параметры, как и в соответствующем конструкторе,
например:
ifstream def ("input.txt"); // Использование конструктора
if (!def) {
cout<< "Невозможно открыть файл для чтения";
return 1;
}
ostream cef:
cef.open ("output, txt", ios::out);// Использование метода open
if(!cef) {
cout << "Невозможно открыть файл для записи";
return 1;
}
17:29
Режимы открытия файлов
Режимы открытия файлов можно устанавливать
непосредственно при создании объекта или при вызове
метода open().
ofstream fout("file.txt", ios::app);
fout.open("file.txt", ios::app);
Режимы открытия файлов можно комбинировать с помощью
поразрядной логической операции ИЛИ |, например:
ios::out | ios::in - открытие файла для записи и чтения.
17:29
Файловые потоки ввода-вывода
Чтение и запись выполняются либо с помощью операции
чтения и извлечения, аналогичных потоковым классам, либо
с помощью методов классов. Для примера рассмотрим
программу, которая выводит на экран содержимое файла.
17:29
#include
int main()
{
char text[81], buf[81];
cout <<"Введите имя файла:";
cin >> text;
ifstream cef(text);
if (!cef)
{
cout << "Ошибка открытия файла";
return 1;
}
while (!cef.eof())
{
f.getline(buf, 81);
cout << buf << endl;
}
return 0:
}
17:29
Файловые потоки ввода-вывода
Для закрытия потока определен метод close(). но поскольку
он неявно выполняется деструктором, явный вызов данного
метода необходим только тогда, когда требуется закрыть
поток раньше конца его области видимости.
17:29
Произвольный доступ к файлу
Система ввода-вывода С++ позволяет осуществлять произвольный
доступ с использованием методов seekg() и seekp().
ifstream &seekg(Смещение, Позиция);
ofstream &seekp(Смещение, Позиция);
Смещение определяет область значений в пределах файла (long
int).
Система ввода-вывода С++ обрабатывает два указателя,
ассоциированные с каждым файлом:
get pointer g - определяет, где именно в файле будет
производиться следующая операция ввода;
put pointer p - определяет, где именно в файле будет
производиться следующая операция вывода.
17:29
Строковые потоки ввода-вывода
Существуют специальные классы, описанные в strstream.h,
позволяющие производить ввод-вывод информации в файл:
iststream - входные строковые потоки;
ostrstream - выходные строковые потоки;
strstream - двунаправленные строковые потоки.
Эти классы являются производными от классов istream,
ostream и iostream соответственно, поэтому они наследуют
перегруженные операции << и >>, флаги форматирования,
манипуляторы, методы, состояние потоков и т. д.
17:29
Строковые потоки ввода-вывода
Участки памяти, с которыми выполняются операции чтения и
извлечения, по стандарту определяются как строки C++
(класс string). Строковые потоки создаются и связываются с
этими участками памяти с помощью конструкторов:
explicit istrstream(int mode = ios::in);
explicit istrstream(const strings name, int mode = ios::in);
explicit ostrstream(int mode = ios::out);
explicit ostrstream(const strings name, int mode = ios::out);
explicit strstream(int mode = ios::in | ios::out);
explicit strstream(const strings name, int mode = ios::in |ios: :out);
Ключевое слово explicit сообщает компилятору, что указанное
преобразование нельзя использовать для выполнения неявных
преобразований.
17:29
Строковые потоки ввода-вывода
Строковые потоки являются некоторым аналогом функций
sscanf и sprintf библиотеки С и могут применяться для
преобразования данных, когда они заносятся в некоторый
участок памяти, а затем считываются в величины требуемых
типов. Эти потоки могут применяться также для обмена
информацией между модулями программы.
В строковых потоках описан метод str, возвращающий копию
строки или устанавливающий ее значение:
string str() const;
void str(const string & s);
17:29
Запись в файл
17:29
Дозаписать текст в конец файла
для открытия файла нужно использовать
режим ios::app
17:29
Чтение из файла
17:29
Также для чтения данных из файла для объектов ifstream и fstream может
применяться оператор >> (также как и при чтении с консоли):
17:29
17:29
Ошибочные состояния потоков
ввода-вывода
Можно проверять ошибки в потоках, используя логические
выражения:
if (cin >> x) // ввод успешный
{
…
}
if (!cout)
cerr<<"Ошибка!";
17:29
Вопросы для самопроверки
1. Перечислите заголовочные файлы, в которых содержатся
потоковые классы.
2. Какие операции используются для ввода и вывода?
3. Что такое манипуляторы и для чего они нужны?
4. Какие методы для неформатированного чтения и записи
в поток вы запомнили?
5. Какие классы относятся к файловым потокам вводавывода?
6. Какие классы относятся к строковым потокам вводавывода?
17:29
Задание на работу с файлами
• Напишите программу, в которой с клавиатуры вводится
предложение, разбивается на слова, затем слова
выводятся на экран каждое в отдельной строке
• Переделать предыдущее задание так, чтобы строка
вводилась из файла, а выделяемые из строки слова
выводились в другой файл.
17:29
Задание на работу с динамическими
структурами данных
Оператор мобильной связи организовал базу
данных абонентов, содержащую сведения о телефонах, их
владельцах и используемых тарифах, в виде бинарного
дерева. Составьте программу, которая:
• обеспечивает начальное формирование базы данных в
виде бинарного дерева;
• производит вывод всей базы данных;
• производит поиск владельца по номеру телефона;
• выводит наиболее востребованный тариф (по
наибольшему числу абонентов).
Постановка задачи на командное
программирование игры «крестикинолики»
Игра крестики-нолики
// Глобальный массив, который описывает текущее состояние поля
int array[] = {-1, -1, -1,
-1, -1, -1,
-1, -1, -1};
// За кого ходит игрок (значение - 1 или 0)
int choose;
Примеры вывода поля:
// Игра не началась
-|-|-----------|-|-----------|-|// Игра в процессе
1|-|0
-----------|0|1
----------1|0|1
// Выиграл игрок (ходил за 1), победная строчка заменяется на спец. символы
\|-|0
----------0|\|0
-----------|0|\
Общий алгоритм:
Приветствие, выбор за кого ходить (1 или 0).
Компьютер делает случайный ход
Ходит игрок
Проверка победного условия
4.1 Если победа, тогда вывод
4.2 Иначе - повторение 2,3 шага
Основные функции:
Команда_1
void hello(); // функция приветствия, сохранение имени игрока и выбора за какую
сторону он будет играть
Команда_2
void AI_move(); // ходит компьютер
Команда_3
void player_move(); // ходит игрок
Команда_4
int check_field(); // проверка поля на наличие победных условий
// Возвращает результат проверки: 1 - если победа, 0 - если игра продолжается
Команда_5
void draw_field(); // отрисовка поля (вывод на экран)
Команда_6
void draw_win(a, b, c); // заменяем единички или нули на соотв. символы в нужном
направлении (\, /, -, |)
Команда_7
void print_result(); // выводит соотв. сообщение для игрока о победе или проигрыше и
возможно рисует какую-нибудь приколяху (как в косынке в конце, только не такую
сложную)
17:53