- •Экзамен 374 Предварительные рассуждения Вступительное слово
- •Исторические факты
- •Начнем!
- •Проба пера
- •Открытие сохраненного проекта
- •Вывод данных
- •Типы данных
- •Хороший стиль программирования
- •Переменные и константы
- •Практический пример
- •Ввод данных
- •Например:
- •Пример:
- •Арифметические операции с числами
- •Литералы
- •Некоторые примеры
- •Домашнее задание
- •Напишите программу, которая вводит число из трех цифр, разделяет число на отдельные цифры и печатает их отдельно друг от друга с тремя пробелами между ними. Преобразование типов
- •Перечисляемые типы
- •Типичная ошибка
- •Хороший стиль программирования
- •Типичная ошибка
- •Выражения
- •Оператор if
- •Структура программы
- •Логические операции
- •Структура множественного выбора switch
- •Практический пример
- •Цикл for
- •Практический пример
- •Цикл do-while
- •Домашнее задание
- •Вызов функции
- •Прототипы функций
- •Разбор программы
- •Область видимости
- •Аргументы по умолчанию
- •Встраивание
- •Перегрузка функций
- •Учебный пример перегруженных функций. Иллюстрация перегрузки
- •Результат работы программы
- •Практические примеры
- •Домашнее задание
- •Примеры домашней работы урока 1 Пример №1
- •Как работает программа
- •Пример №2
- •Как работает программа
- •Примеры домашних работ на создание функций Пример №1
- •Как работает программа
- •Пример №2
- •Как работает программа
- •Массивы
- •Объявление массивов
- •Примеры использования массивов
- •Программа 1
- •Программа 2
- •Обратите внимание!
- •Типичная ошибка программирования
- •Типичная ошибка программирования
- •Программа 3
- •Типичная ошибка программирования
- •Замечание по технике программирования
- •Программа 4
- •Программа 5
- •Программа нахождения минимального и максимального элементов массива
- •Сортировка массивов
- •Домашнее задание
- •Что такое указатели?
- •За кулисами...
- •Как работать с указателями?..
- •Зачем нужны указатели?
- •Указатели и Массивы.
- •Примеры задач
- •Пример 1
- •Пример 2
- •Пример 3
- •Указатели - аргументы функций.
- •Ссылочные параметры
- •Примеры решения задач
- •Домашнее задание
- •Операторы свободной памяти new и delete
- •Функции работы со строками из библиотеки обработки строк
- •Пример 1.
- •Пример2
- •Пример 3
- •Пример задачи на новый материал
- •Домашнее задание
- •Двухмерные массивы, как частный случай многомерных массивов
- •Программа.
- •Результаты работы программы.
- •Многомерные динамические массивы
- •Пример на многомерные динамические массивы
- •Домашнее задание
- •Рекурсия
- •Рекурсии или итерации
- •Указатели на функции
- •Пример №1
- •Результат выполнения программы:
- •Пример №2
- •Результат выполнения программы
- •Пример №3
- •Результаты выполнения программы
- •Определения структур
- •Пример #1 на использование структур
- •Пример #2 на использование структур
- •Оператор указателя на структуру
- •Домашнее задание
- •Тест по c Группа ___________________ф. И. О. ______________________
- •Объектно-ориентированное программирование.
- •Наследование (Inheritance).
- •Инкапсуляция (Encapsulation).
- •Определение класса
- •Конструкторы и деструкторы Инициализация объектов класса: конструкторы
- •Основное назначение конструкторов - инициализация объектов.
- •Использование конструкторов с аргументами по умолчанию
- •Если параметры не передаются конструктору, в определении объекта не нужно включать пустые круглые скобки.
- •Использование деструкторов
- •Когда вызываются конструкторы и деструкторы.
- •Домашнее задание
- •Конструктор копирования
- •Синтаксис конструктора копирования
- •Памятка
- •Пример использования конструктора копирования.
- •Перегруженные конструкторы
- •Экскурс в историю
- •Послесловие к примеру
- •Маленькое замечание
- •Домашнее задание
- •Создание класса ''строка''
- •Перегрузка операций.
- •Общие принципы перегрузки операторов.
- •Преобразования, определяемые классом
- •Пример строкового класса с перегруженными операторами
- •Домашнее задание
- •Дружественные функции (Friend Functions)
- •Пример строкового класса с перегруженными операторами и дружественными функциями
- •Перегрузка операторов new и delete
- •Перегрузка оператора индексирования
- •Класс вектор. Часть1.
- •Класс вектор. Часть 2.
- •Класс вектор. Часть 3.
- •Домашнее задание
- •Наследование (Inheritance). Часть 1.
- •Наследование (Inheritance). Часть 2.
- •Множественное наследование (multiple inheritance)
- •Пример множественного наследования
- •Домашнее задание
- •Статические члены данных
- •Раннее и позднее связывание
- •Виртуальные функции
- •Пример.
- •Абстрактные классы
- •Виртуальный базовый класс
- •Практический пример
- •Домашнее задание
- •Потоки ввода-вывода.
- •Iostream.H: stream - поток, "I" - сокр. Input - ввод, "o" - сокр. Output - вывод.
- •Предопределенные потоки.
- •Операции помещения в поток и извлечения из потока.
- •Файловый ввод-вывод с применением потоков.
- •Конструкторы файловых потоков.
- •Функции для открытия и закрытия файлов.
- •Функции для обмена с потоками.
- •Часто применяемые функции потока.
- •Ввод/вывод массива в/из файл(-а).
- •Практический пример: перекодировка файла.
- •Домашнее задание
- •Немного о файлах...
- •И снова файлы...
- •Пример "Телефонная книга"
- •Файл abonent.H
- •Форматирование данных при обменах с потоками.
- •Состояние потока.
- •Использование аргументов командной строки.
- •Ввод/вывод в с.
- •Домашнее задание
- •Определение шаблонов функций
- •Переопределение шаблонов функций
- •Шаблоны классов
- •Шаблонный класс вектор
- •Шаблонный класс вектор
- •Шаблонный класс вектор
- •Введение
- •Обработка исключительных ситуаций
- •Практический пример
- •Программа
- •Домашнее задание
- •Экзамен
Файл abonent.H
#ifndef ABONENT_H // директивы препроцессора, используются, чтобы
#define ABONENT_H // избежать включение в программу заголовочного
// файла abonent.h более одного раза
#include<string.h>
#include<iostream.h>
class Abonent
{
public:
Abonent(); // конструктор по умолчанию
Abonent(char*, char*, char*);
Abonent(const Abonent&); // конструктор копирования
~Abonent();
void Print(); // функция выводит на экран
// содержимое полей класса
friend class PhoneDir; // объявим класс PhoneDir "другом",
// чтобы упростить доступ к полям класса
private:
char *Name, *Address, * Phone; // поля класса: фамилия
// и инициалы абонента, адрес, номер телефона соответственно
};
class PhoneDir
{
public:
explicit PhoneDir(char* baseName);
void AddAbonent(Abonent&); // добавление нового абонента
int DeleteAbonent(Abonent&); // удаление абонента
int ChangeAbonent(Abonent&, char*); // изменение номера
// телефона абонента
Abonent FindByName(char* fio); // поиск абонента по фамилии
~PhoneDir();
private:
char* baseName; // имя файла, в котором хранится
// информация об абонентах
};
#endif
abonent.cpp
void PhoneDir::AddAbonent(Abonent& man)
{
ofstream dBs; // создаем поток для записи в файл
dBs.open(baseName, ios::app); // режим открытия - добавление
// данных в конец файла
if(!dBs)
{
cout << cyr("Ошибка открытия файла ") << baseName << endl;
exit(1); //в случае ошибки открытия файла выходим из программы
}
/* данные в файл выводятся в определенном формате -
30 байт - для фамилии абонента, следующие 60 байт - адрес
абонента и 10 байт - для номера телефона, плюс два байта -
переход на слудующую строчку;
итого длина записи - 102 байта
*/
dBs << setw(30) << man.Name;
dBs << setw(60) << man.Address;
dBs << setw(10) << man.Phone << endl;
dBs.close();
}
Abonent PhoneDir::FindByName(char* fio)
{
ifstream dBs; // объявляем поток для чтения
dBs.open(baseName);
if(!dBs)
{
cout << cyr("Ошибка открытия файла") << baseName << endl;
exit(1);
}
dBs.seekg(0); // смещаемся в начало файла
int k = 0; // переменная хранит номер записи, отвечающей
// критерию поиска
char *buf = new char[100];
bool flag = false;
do
{ // поиск записи, хранящей информацию об искомом абоненте
dBs.seekg(102*k++, ios::beg);
// для каждой записи считываем первые 30 байт (в них хранится
// фамилия текущего абонента)
dBs.getline(buf, 31);
// удляем пробелы в начале строки
buf = ltrim(buf);
// проверяем, совпадает ли фамилия данного абонента с
// фамилией, переданной в качестве параметра,
// если нет, переходим к следующей записи
if (strcmp(buf, fio) != 0) continue;
flag = true;
} while (!flag && !dBs.eof());
if(!flag)
{
cout << cyr("Абонент не найден")<< endl;
exit (1);
}
// если абонент найден, считываем информацию из файла в
// переменную man, которую затем возвращаем
// в качестве результата поиска
Abonent man;
strcpy(man.Name, fio);
dBs.seekg(102*(k-1) + 30, ios::beg);
// считываем адрес
dBs.getline(buf, 61);
buf = ltrim(buf);
strcpy(man.Address, buf);
// считываем номер телефона
dBs.getline(buf, 11);
buf = ltrim(buf);
strcpy(man.Phone, buf);
dBs.close();
delete[] buf;
return man;
}
int PhoneDir::ChangeAbonent(Abonent& man, char* newPhone)
{
// .....
// аналогично пердыдущей функции находим позицию, начиная
// с которой записана информация об абоненте, для котрого
// хотим изменить номер телефона
// если абонент найден, записываем ему новый номер телефона
// для этого:
// открываем файл для записи в указанную позицию
ofstream inDBs(baseName, ios::in);
if(!inDBs)
{
cout << cyr("Ошибка открытия файла") << baseName << endl;
exit(1);
}
// перемещаемся в позицию, в которой записан старый номер телефона
inDBs.seekp(102*(k-1)+90);
// и записываем поверх новый номер
inDBs << setw(10) << newPhone;
inDBs.close();
delete[] buf;
return 1;
}
int PhoneDir::DeleteAbonent(Abonent& man)
{
ifstream dBs;
// ......
// ищем абонента, которого нужного удалить из базы
// если абонент найден, удаляем информацию о нем,
// для этого:
// открываем файл для чтения в бинарном режиме
dBs.open(baseName, ios::binary);
if(!dBs)
{
cout << cyr("Ошибка открытия файла") << baseName << endl;
exit(1);
}
// считываем в буфер первую часть файла, предшествующую
// записи на удаление
char *buf = new char[sz];
dBs.seekg(0);
dBs.read(buf, (k-1)*102);
// пропускаем удаляемую запись
dBs.seekg(102, ios::cur);
// и считываем оставшуюся часть файла
dBs.read(buf + (k-1)*102, sz - k*102);
dBs.close();
// затем открываем поток для записи,
ofstream inDBs(baseName, ios::out|ios::trunc|ios::binary);
if(!inDBs)
{
cout << cyr("Ошибка открытия файла") << baseName << endl;
exit(1);
}
// и записываем в файл содержимое буфера
inDBs.seekp(0);
inDBs.write(buf, sz-102);
inDBs.close();
delete[] fio;
delete[] buf;
return 1;
}
PhoneBook.cpp
// функция выводит на экран меню программы и возвращает
// номер пункта, выбранного пользователем
int OutputMenu();
/* В функции OutputMenu попробуйте сцепить операторы вывода на экран, т.е.
вывести все меню с помощью одного оператора cout. Что у Вас получилось?
Как Вы это объясните? */
void main()
{
bool flag = true;
// Объявляем объект типа PhoneDir и "связываем" его с файлом "Phones.txt"
PhoneDir book("Phones.txt");
while(flag)
{
cout << endl;
switch (OutputMenu()) // выводим меню на экран и
// анализируем выбор пользователя
{
case 1: { // если выбран первый пункт меню,
char buf[2], fio[30], street[120], num[10];
// то запрашиваем у пользователя данные нового абонента
cout << cyr("Введите фамилию абонента: ");
cin.getline(buf,2);
cin.getline(fio, 30);
cout << cyr("Введите адрес абонента: ");
cin.getline(street, 120);
cout << cyr("Введите телефон абонента: ") ;
cin.getline(num, 10);
// и добавляем его в файл
book.AddAbonent(Abonent(fio, street, num));
}
break;
case 2: {
char buf[2], fio[30];
// запрашиваем фамилию искомого абонента
cout << cyr("Введите фамилию абонента: ");
cin.getline(buf,2);
cin.getline(fio, 30);
// и вызываем функцию поиска абонента по фамилии, эта функция
// возвращает объект типа Abonent, выводим его на экран
// с помощью функции Abonent::Print()
book.FindByName(fio).Print();
}
break;
case 3: {
// чтобы изменить телефон, запрашиваем и фамилию и адрес
// сначала вводится фамилия, "enter", затем адрес
char buf[2], fio[30], street[120], num[10];
cout << cyr("Введите фамилию и адрес \
абонента, телефон которого хотите изменить: ");
cin.getline(buf,2);
cin.getline(fio, 30);
cin.getline(street, 120);
cout << cyr("Введите новый номер телефона абонента ");
cin.getline(num, 10);
// вызываем функцию ChangeAbonent и передаем ей
// абонента и новый номер телефона
if (!book.ChangeAbonent(Abonent(fio, street, ""), num))
cout << cyr("Абонент не найден") << endl;
}
break;
case 4: {
char buf[2], fio[30];
cout << cyr("Введите фамилию абонента на удаление: ");
cin.getline(buf,2);
cin.getline(fio, 30);
// чтобы удалить абонента, вызываем функцию DeleteAbonent
if (!book.DeleteAbonent(Abonent(fio, "", "")) )
cout << cyr("Абонент не найден") << endl;
}
break;
case 5:
flag = false; // устанавливаем флаг выхода из цикла
break;
}
}
}
Обратите внимание на функцию cyr (см. файл util.cpp). Какой существенный недостаток имеет реализация этой функции. Как это можно исправить? Ваши предложения.
Ввод-вывод в языке С++.