Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Книга C++.doc
Скачиваний:
24
Добавлен:
10.11.2019
Размер:
2.48 Mб
Скачать

Файл 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). Какой существенный недостаток имеет реализация этой функции. Как это можно исправить? Ваши предложения.

Ввод-вывод в языке С++.