- •Предисловие
- •Глава 1. Основные понятия
- •1.1. Элементы языка программирования
- •1.2. Процесс создания программы
- •1.3. Первая программа
- •1.4. Состав программы
- •Глава 2. Средства разработки на C++
- •2.1. Системы Turbo C++ 3.0/Borland C++ 3.1
- •2.2. Система C++ Builder
- •Глава 3. Работа с числовыми данными
- •3.1. Целые типы
- •3.2. Числа с плавающей точкой
- •3.3. Ввод и вывод чисел
- •3.4. Логический тип и логические операции
- •3.5. Математические функции
- •Глава 4. Операторы. Ключевые слова
- •4.1. Операторы
- •4.2. Приоритеты операторов
- •4.3. Ключевые слова
- •4.4. Структура программы
- •4.5. Константы
- •Задачи - . Простейшие вычисления
- •Глава 5. Управление и циклы
- •5.1. Условный оператор
- •5.2. Операторы цикла
- •5.3. Переключатель
- •5.4. Операторы break и continue
- •Задачи -. Выбор и циклы
- •Глава 6. Массивы
- •6.1. Одномерные массивы
- •6.2. Двумерные массивы
- •Задачи -. Одно- и двумерные массивы
- •Глава 7. Функции
- •7.1. Определение функции
- •7.2. Формальные параметры и фактические аргументы
- •7.3. Автоматические и статические переменные
- •7.4. Прототипы функций
- •7.5. Массивы как аргументы функций
- •7.6. Внешние переменные
- •7.7. Рекурсия
- •7.8. Перегруженные имена функций
- •7.9. Аргументы функций по умолчанию
- •Задачи -. Функции
- •Глава 8. Символы и строки
- •8.1. Символы
- •8.2. Строки символов
- •Задачи -. Символы и строки
- •Глава 9. Препроцессор
- •9.1. Директивы препроцессора
- •9.2. Макросы
- •Задачи -. Макросы
- •Глава 10. Указатели и ссылки
- •10.1. Указатели и адреса
- •10.2. Указатели и массивы
- •10.3. Адресная арифметика
- •10.4. Символьные указатели
- •10.5. Массивы указателей
- •10.6. Указатели на функции
- •10.7. Ссылки
- •10.8. Операторы new и delete
- •Задачи -. Указатели и ссылки
- •Глава 11. О файлах и командной строке
- •11.1. Знакомство с файлами
- •11.2. Командная строка
- •11.3. Перенаправление стандартного ввода и вывода на файл
- •11.4. Аргументы командной строки
- •Задачи -. Файлы и командная строка
- •Глава 12. Работа с экраном дисплея
- •12.1. Текстовый режим
- •12.2. Графический режим
- •Задачи -. Работа с экраном
- •Глава 13. Внутреннее представление чисел
- •13.1. Двоичная система счисления
- •13.2. Беззнаковые целые
- •13.3. Двоичный дополнительный код
- •13.4. Двоичный код с избытком
- •13.5. Побитовые операторы
- •13.6. Дробные числа в двоичной системе
- •13.7. Внутреннее представление плавающих типов
- •13.8. Преобразование типов
- •Задачи -. Побитовые операторы
- •Глава 14. Структуры, перечисления, объединения
- •14.1. Объявление структур
- •14.2. Структуры и функции
- •14.3. Указатели на структуры
- •14.4. Массивы структур
- •14.5. Перечисления
- •14.6. Объединения
- •14.7. Битовые поля
- •14.8. О бинарных файлах
- •Задачи -. Структуры
- •Глава 15. Классы
- •15.1. Структуры в C++. Инкапсуляция
- •15.2. Встроенные функции
- •15.3. Классы. Скрытие данных
- •15.4. Конструкторы
- •15.5. Статические члены класса
- •15.6. Друзья класса
- •15.7. Копирование объектов класса
- •15.8. Управление доступом
- •15.9. Ссылка на себя
- •15.10. Деструкторы
- •Задачи -. Работа с классами
- •Глава 16. Программы из нескольких файлов
- •16.1. Работа с проектами
- •16.2. Область действия имен
- •16.3. Заголовочные файлы
- •16.4. Пространства имен
- •Задачи -. Работа со стеком
- •Глава 17. Перегрузка операторов
- •17.1. Правила перегрузки операторов
- •Задачи -. Перегрузка операторов
- •Глава 18. Конструктор копирования и оператор присваивания
- •18.1. Проблемы при копировании
- •Задачи -. Конструктор копирования
- •Глава 19. Ввод и вывод
- •19.1. Вывод
- •19.2. Ввод
- •19.3. Ввод и вывод определяемых пользователем типов
- •19.4. Работа с файлами
- •Глава 20. Взаимоотношения классов
- •20.1. Объекты как члены класса
- •20.2. Конструкторы встроенных типов
- •20.3. Наследование
- •20.4. Виртуальные функции
- •20.5. Абстрактные классы
- •20.6. Совместимость типов
- •20.7. Множественное наследование
- •Задачи -. Наследование классов
- •Глава 21. Шаблоны, исключения
- •21.1. Шаблоны
- •21.2. Шаблоны функций
- •21.3. Классы и шаблоны
- •21.4. Обработка исключений
- •21.5. Стандартная библиотека шаблонов
- •Литература
- •Предметный указатель
264
Глава 19. Ввод и вывод
Язык C++ не содержит встроенных средств ввода и вывода. Ввод и вывод обеспечивается стандартной библиотекой с заголовочным файлом iostream.h или iostream. При использовании iostream нужно использовать пространство имен std. В C++ можно применять все средства ввода и вывода языка Си, которые становятся доступными после включения в программу заголовочного файла stdio.h.
Средства ввода и вывода языка C++ реализованы в виде иерархии потоковых классов. Поток – это последовательность байтов. С точки зрения программы поток не зависит от тех конкретных устройств, с которыми ведется обмен данными. Поток может быть связан со стандартным устройством ввода (клавиатурой), стандартным устройством вывода (дисплеем), с файлом на диске или с массивом в оперативной памяти. Потоки бывают входными, выходными и двунаправленными, допускающими как чтение, так и запись. В составе библиотеки ввода и вывода предусмотрены средства для включения данных в поток и извлечения данных из потока.
Все потоковые классы имеют в качестве базового класс ios. Для непосредственной организации ввода и вывода используются классы:
istream |
– |
класс входных потоков; |
ostream |
– |
класс выходных потоков. |
iostream |
– |
класс двунаправленных потоков. |
19.1.Вывод
Вклассе ostream есть функции-операторы << для вывода стандартных типов. В качестве результата данные функции возвращают ссылку на объект, для которого вызываются. Ниже приводится фрагмент объявления класса ostream.
class ostream: public ios |
|
{ |
|
... |
|
public: |
|
ostream& operator<<(char*); |
// Вывод строки |
ostream& operator<< (int); |
// Вывод целого |
ostream& operator<< (long); |
// Вывод длинного целого |
ostream& operator<< (double); |
// Вывод double |
ostream& operator<< (long double);// Вывод long double |
|
ostream& put(char); |
// Вывод символа |
Ввод и вывод 265
…
};
Реализация некоторых простых функций вывода выполнена непосредственно в классе, например, функция вывода целого int:
inline ostream& ostream::operator<< (int _i) { return *this << (long) _i; }
Видно, что int преобразуется к типу long, затем используется оператор для вывода long и возвращается поток *this, в который произведен вывод. Реализация оператора вывода long в классе не приводится, она содержится в заранее откомпилированной библиотеке.
В файле iostream объявлен объект cout класса ostream, связанный по умолчанию со стандартным выходным устройством (дисплеем), – стандартный выходной поток. Как уже говорилось, его можно перенаправить на файл средствами операционной системы.
Для ускорения выполнения операций ввода и вывода могут создаваться буфера в оперативной памяти, в которые предварительно помещаются выводимые или вводимые данные. В частности, поток cout имеет буфер.
Для вывода сообщений об ошибках определен объект cerr, всегда связанный со стандартным выходным устройством. Он не имеет буфера, то есть сообщение, направленное в cerr, немедленно появится на экране.
Благодаря тому, что функция operator << возвращает ссылку на поток, можно писать цепочки вызовов вида:
double x=3.14;
cout << "\nx=" << x;
Последняя инструкции является сокращенной записью инструкции: cout.operator<<("\nx=").operator<<(x);
Первым вычисляется выражение cout.operator<<("\nx="). При его вычислении выводится строка "\nx=", значением этого выражения является cout. Затем в cout выводится x.
19.2.Ввод
Вклассе входных потоков istream определены функции-операторы
>>для ввода стандартных типов. Их объявления похожи на приведенные выше объявления функций вывода <<, только аргументы передаются в эти функции по ссылке, чтобы аргументам можно было присвоить значение внутри функции. Оператор >> ("взять из…") при чтении сначала пропускает все ведущие пробелы, затем извлекает
266 19
символы для вводимого значения до тех пока не встретит разделитель или недопустимый для вводимой величины символ. Разделителями данных при вводе являются пробелы.
Для организации ввода со стандартного входного устройства в iostream.h (iostream) объявлен объект cin класса istream, связанный по умолчанию с клавиатурой.
Функция-оператор >> возвращает ссылку на поток, для которого вызывается. Это позволяет строить цепочки вида:
cin >> i >> j >> k;
При наборе на клавиатуре 1 2 3 и нажатии клавиши Enter, переменные i, j, k получат соответствующие значения.
19.3. Ввод и вывод определяемых пользователем типов
Операторы вывода << и ввода >> можно переопределять для пользовательских типов. Эти операторы являются бинарными и требуют двух операндов. В стандартной библиотеке ввода и вывода предусмотрено, что их первым операндом является поток, поэтому, чтобы сохранить привычный способ их применения для пользовательских типов (классов), нужно при их перегрузке в качестве первого операнда также указывать поток, но в таком случае эти операторы не могут быть членами класса.
Программа 56. Перегрузка операторов ввода/вывода
// Файл UserIO.cpp #include <iostream.h>
class Point3{ |
// Точка в трехмерном пространстве |
|
float x, y, z; |
// Три координаты |
|
friend ostream& operator<<(ostream&, Point3&); |
// Оператор вывода |
|
friend istream& |
operator>>(istream& , Point3&); |
// Оператор ввода |
}; |
|
|
В простом классе Point3 функции-операторы >> и << объявлены как друзья, чтобы они имели доступ к закрытым членам этого класса. Далее следуют определения функций-операторов ввода и вывода.
// Оператор вывода для Point3
ostream& operator<<(ostream& outs, Point3& d)
{
// Вывод данных в поток outs
outs << "(" << d.x << ", " << d.y << ", " << d.z << ")";
|
Ввод и вывод 267 |
return outs; |
// Возвращение потока |
}
// Оператор ввода для Point3
istream& operator>>(istream& ins, Point3& d)
{
// Чтение данных из потока и возвращение потока return ins >> d.x >> d.y >> d.z;
}
Здесь использовано то, что стандартный оператор ввода >> возвращает поток, для которого вызывается, то есть ins. После того, как из этого потока будет произведено чтение, он возвращается из функции.
Теперь вводить и выводить данные типа Point3 можно так же, как данные стандартных типов:
void main() |
|
{ |
|
Point3 F, G; |
// Две точки с неопределенными координатами |
cout << "\n Координаты точек после их создания:\nF = " << F << "\nG = " << G << endl;
cout << "Введите координаты двух точек: "; cin >> F >> G;
cout<<"Теперь координаты точек: F= " << F << ", G = " << G << endl;
}
Так как в классе Point3 нет конструктора, объекты F и G после создания будут иметь неопределенное значение. Программа выдает:
Координаты точек после их создания:
F= (9.455121e-41, 2.865269e-33, 1.023487e-16) G = (-1.370785e-29, 2.196764e-34, 0.000301) Введите координаты двух точек: 3 4 5 2 3 4
Теперь координаты точек: F= (3, 4, 5), G = (2, 3, 4)
19.4. Работа с файлами
Для работы с файлами в программу следует включить файл fstream.h или fstream, в котором объявлены три следующих потоковых класса, обеспечивающие работу с файлами:
ofstream – класс выходных файловых потоков; ifstream – класс входных файловых потоков;
fstream – класс двунаправленных файловых потоков.
Чтение из файла и запись в файл производятся с помощью объектов файловых потоковых классов (потоков), которые должны быть связаны с конкретными файлами на диске. Связь потока с файлом можно
268 19
установить с помощью функции-члена open, или с помощью конструктора, аргументами которых должно быть имя файла. Функция open и конструкторы потоковых классов могут иметь по два аргумента. Первым аргументом является имя открываемого файла, а второй аргумент задает режим работы с файлом. Для указания режима работы с файлом можно использовать константы, определенные в базовом классе
ios:
ios::out – файл используется для вывода; ios::in – файл используется для ввода; ios::app – добавления в конец файла.
Программа 57. Сравнение текстового и бинарного файлов
Впрограмме создаются два выходных файловых потока: текстовый
ибинарный. Потоки связываются с файлами конструктором, которому в качестве аргумента передаются имена файлов. В файлы записываются случайные числа соответственно в текстовом и бинарном виде. Созданные файлы закрываются и открываются вновь как бинарные, для передачи функции FileSize, определяющей их размеры. Чтобы прочитать содержимое файла, хранящего текстовое представление чисел, он сначала закрывается как бинарный, а затем открывается на ввод как текстовый. Файл с бинарным представлением чисел подготавливается к чтению перемещением текущего указателя к началу файла. Содержимое файлов выводится на экран.
// Файл CmpTxtBn.cpp #include <stdlib> #include <fstream> #include <iostream> #include <windows> #include <time.h> #include <conio>
const int lenname = 13; |
// Длина имени файла |
using namespace std; |
// Открываем стандартное пространство имен |
char Buff[500]; |
// Буфер для преобразованной строки |
char* Rus(char* in) |
// Функция для преобразования русских букв |
{ |
|
CharToOem(in, Buff); |
// Функция CharToOem преобразует строку in |
return Buff; |
// в строку Buff, используя кодировку DOS |
} |
|
long FileSize(istream& f) |
// Возвращает размер файла в байтах |
{ |
// f – ссылка на поток |
long k; |
// Счетчик |
|
Ввод и вывод 269 |
for (k = 0; !f.eof(); k++) |
// Пока не достигнут конец файла, |
f.get(); |
// читаем из него символ |
f.clear(); |
// Сброс флагов ошибок потока |
return k - 1; |
|
}
В функции FileSize производится посимвольное чтение из файла, пока не будет достигнут его конец. Состояние «конец файла» не возникает после прочтения последнего символа, оно возникает после первой неудачной попытки прочитать из файла символ, поэтому возвращается не общее число k вызовов функции get, а значение k - 1, равное числу прочитанных из файла символов.
void main() |
|
{ |
|
char* tf = "TxtFile.txt"; |
// Имя текстового файла |
char* bf = "BinFile.bin"; |
// Имя бинарного файла |
const int N =20; |
// Количество чисел |
ofstream tout(tf, ios::out); |
// Создаем выходной текстовый поток |
if(!tout){ |
// Проверяем открытие файла |
cout<<Rus("\nНе могу создать файл") << tf; |
|
cin.get(); |
|
exit(1); |
|
}
ofstream bout(bf, ios::out | ios::binary);// Выходной бинарный поток
if(!bout){ |
|
// Проверка |
cout<<Rus("\nНе могу создать файл") << bf; |
||
cin.get(); |
|
|
exit(1); |
|
|
} |
|
|
int i, n; |
|
|
randomize(); |
// Инициализация датчика случайных чисел |
|
for(i = 0; i < N; i++){ |
|
|
n = rand(); |
|
// Генерируем числа |
tout << ' ' << n; |
|
// и заносим в текстовый |
bout.write((char*)&n, sizeof(int)); |
// и бинарный файлы |
|
} |
|
|
tout.close(); |
|
// Закрываем |
bout.close(); |
|
// потоки |
ifstream tin(tf, ios::binary); |
// Открываем оба файла на чтение |
|
ifstream bin(bf, ios::binary); |
// как бинарные |
|
cout << Rus("\nРазмер текстового файла ") << tf |
||
<< " = " << FileSize(tin); |
|
|
cout << Rus("\nРазмер биарного файла ") << bf |
||
<< " = " << |
FileSize(bin); |
|
270 |
19 |
|
tin.close(); |
// Закрываем файл с текстовым представление |
|
чисел, |
|
|
tin.open(tf); |
// окрываем снова как текстовый |
|
if(!tin){ |
|
cout<<Rus("\nНе могу открыть файл ") << tf; cin.get();
exit(1);
}
// Вывод чисел из обоих файлов
cout << Rus("\nЧисла из файла ") << tf << endl;
while(tin.good()){ |
// Пока в потоке нет ошибок, |
tin >> n; |
// читаем число из файла |
cout << n << ' '; |
// и выводим на экран |
if(wherex() > 60) // Если использовали более 60 позиций экрана, |
|
cout << endl; |
// переходим на новую строку |
} |
|
bin.seekg(0, ios::beg); |
// Перемещаем текущий указатель файла |
// к его началу cout << Rus("\nЧисла из файла ") << bf << endl; while(bin.good()){
bin.read((char*)&n, sizeof(int)); // Читаем байты числа
if(!bin.eof()) |
// Если после чтения не достигнут конец файла |
cout << n << ' '; |
// выводим число |
if(wherex() > 60) |
|
cout << endl; |
|
} |
|
tin.close(); |
// Закрываем |
bin.close(); |
// потоки |
cin.get(); |
|
} |
|
Для проверки возможности чтения из потока использована функция bool good() const;
которая возвращает истину, если из потока возможно чтение. Эта функция более надежна, чем eof.
Функция int wherex();
возвращает текущую горизонтальную координату курсора. Курсор переводится на новую строку экрана, если текущая координата курсора больше 60.
Для записи в текстовый файл и чтения из него использованы обычные операторы вывода << и ввода >>. Для записи в бинарный файл
Ввод и вывод 271
использована функция write, для чтения – read. Подробнее о них см. §14.8.
Далее приводятся результаты, выводимые программой. В тестовом файле числа хранятся в виде последовательностей десятичных цифр, разделенных пробелами. Если открыть файл TxtFile.txt, то увидим в нем числа в виде одной длинной строки. Если открыть бинарный файл в текстовом редакторе, то увидим непрерывную последовательность непонятных значков.
Размер бинарного файла равен 80 байт, так как в него записано 20 целых чисел, каждое их которых занимает 4 байта. Размер тестового файла оказался больше, так как многие числа пятизначные, кроме того между числами ставятся пробелы.
Размер текстового файла TxtFile.txt = 117 Размер бинарного файла BinFile.bin = 81
Числа из файла TxtFile.txt
5100 5643 23190 21957 16631 26794 23086 2043 29278 17418 25104
17502 3733 13662 20114 25132 14391 11375 31451 27970
Числа из файла BinFile.bin
5100 5643 23190 21957 16631 26794 23086 2043 29278 17418 25104
17502 3733 13662 20114 25132 14391 11375 31451 27970
Задачи 19.4-19.4. Ввод и вывод
199.Для комплексных чисел (программа 54) перегрузите операторы ввода и вывода. Используйте эти операторы для ввода коэффициентов уравнения из файла и записи решения уравнения в файл.
200.Перегрузите операторы ввода и вывода для структуры Time (программа 41).
201.Для класса Date (программы 42-48) перегрузите операторы ввода и вывода.
202.В классе Polinom (задача ) перегрузите операторы ввода и вывода. Используйте их для ввода коэффициентов полинома из файла и записи результатов действий над полиномами в файл.