Любая программа на С++ содержит обращения к стандартной библиотеке, в которой находятся определения типов, констант, макросов, функций и классов. Чтобы использовать их в программе, требуется с помощью директивы #include включить в исходный текст программы заголовочные файлы, в которых находятся соответствующие объявления. Сами библиотечные функции хранятся в скомпилированном виде и подключаются к программе на этапе компоновки. В программах на С++ могут использоваться функции, унаследованные от библиотеки С.
Функции библиотеки можно разбить на группы по их назначению: ввод/вывод, обработка строк, математические функции, работа с динамической памятью, поиск и сортировка и т. д. Ниже приведен краткий обзор функций ввода/вывода в стиле С, функций работы со строками и символами и математических функций.
Функции ввода/вывода
Ввод/вывод в С++ реализуется либо с помощью функций, унаследованных от библиотеки С, либо с помощью потоков С++. Смешивать эти два способа в одной программе можно только синхронизировав ввод с помощью функции sync_with_stdio(). Каждый способ имеет свои преимущества. Преимущество использования потоков в том, что они легче в использовании в простых случаях ввода/вывода, не требующих форматирования, а, главное, потоковые операции можно переопределить для собственных классов. Ввод/вывод в стиле С удобнее использовать при форматированном выводе в программах, не использующих объектно-ориентированную технику. Кроме того, существуют миллионы строк, написанных на С и перенесенных на С++, с которыми программисту приходится сталкиваться.
|
|
Для использования функций ввода/вывода в стиле С необходимо подключить к программе заголовочный файл <stdio.h> или <cstdio>. При вводе/выводе данные рассматриваются как поток байтов. Физически поток представляет собой файл или устройство (например, клавиатуру или дисплей, рассматривающиеся как частный случай файла).
Открытие потока
Работа с потоком начинается с его открытия. Поток можно открыть для чтения и/или записи в двоичном или текстовом режиме. Функция открытия потока имеет формат:
FILE* fopen(const char * filename, const char * mode);
При успешном открытии потока функция возвращает указатель на предопределенную структуру типа FILE, содержащую всю необходимую для работы с потоком информацию, или NULL в противном случае. Первый параметр — имя открываемого файла в виде С-строки, второй — режим открытия файла:
"r" — файл открывается для чтения;
"w" — открывается пустой файл для записи (если файл существует, он стирается);
"a" — файл открывается для добавления информации в его конец;
|
|
"r+" — файл открывается для чтения и записи (файл должен существовать);
"w+" — открывается пустой файл для чтения и записи (если файл существует, он стирается);
"a+" — файл открывается для чтения и добавления информации в его конец.
Режим открытия может также содержать символы t; (текстовый режим) или b (двоичный режим), отличающиеся обработкой символов перехода на новую строку. По умолчанию файл открывается в текстовом режиме, при котором комбинация символов «возврат каретки» и «перевод строки» (0x13 0x10) при вводе преобразуются в одиночный символ перевода строки (при выводе выполняется обратное преобразование). В двоичном режиме эти преобразования не выполняются.
Пример:
FILE* f = fopen("d:\\cpp\\data", "rb+");
Указатель f используется в дальнейших операциях с потоком. Его передают функциям ввода/вывода в качестве параметра.
При открытии потока с ним связывается область памяти, называемая буфером. При выводе вся информация направляется в буфер и накапливается там до заполнения буфера или до закрытия потока. Чтение осуществляется блоками, равными размеру буфера, и данные читаются из буфера. Буферизация позволяет более быстро и эффективно обмениваться информацией с внешними устройствами. Следует иметь в виду, что при аварийном завершении программы выходной буфер может быть не выгружен, и возможна потеря данных. С помощью функций setbuf и setvbuf можно управлять размерами и наличием буферов.
Существует пять предопределенных потоков, которые открываются в начале работы программы: стандартный ввод stdin, стандартный вывод stdout, стандартный вывод сообщений об ошибках stderr, стандартный дополнительный поток stdaux и стандартная печать stdprn. Первые три потока по умолчанию относятся к консоли. Эти указатели можно использовать в любой функции ввода/вывода там, где требуется указатель потока.
Ввод/вывод в поток
Ввод/вывод в поток можно осуществлять различными способами: в виде последовательности байтов, в виде символов и строк или с использованием форматных преобразований. Для каждого вида операций определен свой набор функций.
Операции ввода/вывода выполняются начиная с текущей позиции потока, определяемой положением указателя потока. Указатель устанавливается при открытии на начало или конец файла (в соответствии с режимом открытия) и изменяется автоматически после каждой операции ввода/вывода. Текущее положение указателя можно получить с помощью функций ftell и fgetpos и задать явным образом с помощью функций fseek и fsetpos. Эти функции нельзя использовать для стандартных потоков. Ниже перечислены основные функции ввода/вывода потока:
· Чтение и запись потока байтов выполняют функции fread и fwrite
· Чтение символа из потока — getc, sgetc, из стандартного потока stdin – getchar.
· Запись символа в поток — putc, fputc, в стандартный поток stdout — putchar.
· Чтение строки из потока — fgetc, из стандартного потока stdin — getc.
· Запись строки в поток — fputc, в стандартный поток stdout: — puts.
· Форматированный ввод из потока — fscanf, из стандартного потока stdin — scanf, из строки — sscanf.
· Форматированный вывод в поток — fprintf, в стандартный поток stdout; — printf, в строку — sprintf.
Закрытие потока
Поток закрывается либо при завершении программы, либо явным образом с помощью функции fclose:
int fclose(FILE*);
Перед закрытием потока информация из связанных с ним буферов выгружается на диск. Рекомендуется всегда явным образом закрывать потоки, открытые для записи, чтобы избежать потери данных.
Обработка ошибок
Функции работы с потоком возвращают значения, которые рекомендуется анализировать в программе и обрабатывать ошибочные ситуации, возникающие, например, при открытии существующих файлов или чтении из потока. При работе с файлами часто используются функции feof и ferror:
|
|
- int feof(FILE*) возвращает не равное нулю значение, если достигнут конец файла, в противном случае 0;
- int ferror(FILE*) возвращает не равное нулю значение, если обнаружена ошибка ввода/вывода, в противном случае 0.