Отчёт к работе по курсу "Системное программирование"
Разработал: Чепасов И.А.
Пензенский Государственный Технический Университет, Кафедра: "Информационно-вычислительные системы"
1998
Разработать программу на алгоритмическом языке программирования С++ , реализующую учебную систему управления базой данных (СУБД).
Основанием для разработки служит задание по дисциплине "Системное программирование", выданное на кафедре ИВС ПГТУ.
2.2.1 Требования к функциональным характеистикам
Программа должна выполнять операции ввода , хранения , редактирования , удаления и поиска информации о студентах , хранящейся в базе данных.
Информация о студентах должна содержать следующие данные:
ФИО
Год рождения:
Адрес
Учебная группа.
Входными данными программы являеются: исходная база данных , которая хранится на диске под именем base_o.dat и данные , вводимые или изменяемые пользователем в процессе работы программы.
Выходными данными в программе является база данных , которая записывается на диск под именем base_o.dat по завершении работы программы.
2.2.2 Требования к составу и параметрам технических средств
Программа должна работать на стандартном комплексе технических средств из состава персональных компьютеров IBM PC с процессором i386 или выше.
2.2.3 Требования к программной и информационной совместимости
Программа должна работать с операционной системой MS-DOS 6.0 или выше.
Программа должна быть написана на языке программирования С++l v.3.1.
Для контроля правильности работы программы должны быть разработаны тестовые примеры , которые могут использоваться и для приёмки работы. В тестовых примерах должны быть учтены все возможные сочетания исходных данных , отражающие работу всех частей программы. В ходе приёмки необходимо проверить правильность функционирования программы путём выполнения тестовых примеров. В ходе приёмки программа должна функционировать верно.
Проектирование производится отдельно для части программы, организующей работу с базой данных, и для интерфейсной части программы, поскольку каждая из этих частей может быть использована отдельно. Фактически каждая часть программы строится на основе разных объектов. Основой интерфейса является абстрактный класс wind, потомками которого являются собственно элементы интерфейса, а база данных основана на классе One_Record, выполняющем основные функции работы с базами данных.
Интерфейсная часть программы основана на абстрактном классе wind, содержащем общие для всех окон данные, такие как расположение, размер и цвет окон, и виртуальные методы, такие как перерисовка, активизация. На основе этого класса создаются все остальные классы, перекрывающие виртуальные методы конкретно для данного типа визуальных объектов. Создается цепочка окон, адресуемая через её первый элемент. При запуске метода redr первого элемента он должен обеспечить перерисовку вех последующих путем вызова того же метода всех остальных объектов, поскольку в цепочку могут быть соединены любые классы на основе wind. При нажатии TAB активным становится следующий в цепочке элемент.
Конкретно кажждый класс содержит следующие поля и методы:
Класс wind - абстрактный класс, при использовании выдает рамку
Поля:
x,y,dx,dy - расположение и размеры окна
pap,ink,apap - цвета окна
ts - возможность активизации
next - указатель на следующее окно.
Методы:
add - добавление нового окна в список.
Класс ed_win - класс строк редактирования, при ts=0 используется как строка вывода без возможности редактирования.
Собственные поля:
capt - содержимое
pcapt - старое содержимое
maxlen - максимальная длина строки.
Виртуальные методы:
redr, active.
Класс bt_win - класс кнопок
Собственные поля:
fun - указатель на вызываемую при активизации функцию
capt - содержимое кнопки.
Виртуальные методы:
redr, active.
Класс sc_win - класс скроллеров, зависит от конкретного применения
Собственные поля:
m_fio, m_addr, m_yy, m_grp - маски полей класса One_Record
pnt - первый элемент списка.
Виртуальные методы:
redr, active.
База данных представлена классом One_Record, содержащим все необходимые поля данных и методы. Для организации базы используются указатели на начальный и на текущий элементы базы.
Поля класса:
fio, yy, addr, grp - данные о студенте
next - следующий элемент
last - предыдущий элемент.
Методы класса:
save - запись в файл текущего и всех последующих элементов
FindUp - поиск вверх по списку
FindDown - поиск вниз по списку.
Эти методы возвращают указатель на найденый элемент списка:
add - добавление элемента в список.
Для уничтожения элемента используется деструктор, причем этот деструктор уничтожает все последующие элементы. Для инициализации существует два вида конструкторов - инициализация загрузкой из файла и непосредственным указанием всех полей нового элемента. Второй способ используется только при пустой базе данных и используется функцией add внутри класса.
При проектировании программы создаются два списка окон - один для главного меню, другой для подменю ввода и редактирования. Все основное меню состоит из объектов класса кнопок, для каждой из которых пишется своя функция - обработчик события. Организуется цикл перерисовка -> активизация -> проверка флага выхода.
4 Анализ результатов тестирования
В ходе испытаний программы была проверена правильность её работы при вводе , редактировании , удалении и поиске определённых элементов базы данных по отдельным значениям полей.
В ходе проведения тестирования выяснилось , что программа полностью работоспособна.
Заключение
В процессе работы была определена структура данных программы , разработан алгоритм решения задачи , была разработана структура программы.
Реализация программы была проведена на алгоритмическом языке С++l v.3.10.
Результаты тестирования показали , что программа работает правильно.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <graphics.h>
#include <string.h>
#include <dos.h>
#include <sysstat.h>
#include <io.h>
#include <fcntl.h>
// ОПИСАНИЯ КЛАССОВ -------------------------------------------
// Класс, определяющий один элемент базы данных
class One_Record {
public:
char fio[60]
// ФИО
char yy[5]
// Год рождения
char addr[60]
// Адрес
char grp[10]
// Группа
One_Record * next
// Следующий
One_Record * last
// Предыдущий
One_Record(int,One_Record *)
// Конструктор - читает элемент из файла
// Конструктор - создает новый элемент
One_Record(char * m_fio,char * m_yy,char * m_addr,char * m_grp)
// Деструктор
~One_Record(){}
// Запись в файл
void save(int)
// Поиск вперед
One_Record * FindUp(char * m_fio,char * m_yy,char * m_addr,char * m_grp)
// Поиск назад
One_Record * FindDown(char * m_fio,char * m_yy,char * m_addr,char * m_grp)
// Добавление
void add(One_Record * )
}
// Класс окон
class wind {
public:
int x,y,dx,dy
// Координаты и размеры окна
int pap,ink,apap
// Цвета окна
char ts
// Активизируется или нет при нажатии TAB
wind * next
// Следующее
wind(int,int,int,int)
// Конструктор
~wind(){}
// Деструктор
void add(void * p)
// Добавить в список
void setact(char)
// Изменить значение флага TS
virtual void redr()
// Перерисовка
virtual void * active()
// Активизироать - возвращает указатель на
// следующее активное
}
// Потомок класса WIND - строка редактирования
class ed_win:public wind {
public:
char capt[100]
// Содержимое
char pcapt[100]
// Предыдущее содержимое
int maxlen
// Максимальная длинна
public:
// Конструктор
ed_win(int,int,int,int,char *,int)
// Перерисовка
virtual void redr()
// Активизация
virtual void * active()
}
// Потомок WIND - кнопка
class bt_win:public wind {
void (*fun)()
// Вызываемая при нажатии функция
char capt[50]
// Название
public:
// Конструктор
bt_win(int,int,int,int,char *,void (*)())
// Перерисовка
virtual void redr()
// Активизация
virtual void * active()
}
// Скроллер
class sc_win:public wind {
public:
// Маска выбора
char * m_fio
char * m_addr
char * m_yy
char * m_grp
// Начальный элемент
One_Record * pnt
// Конструктор
sc_win(int,int,int,int,One_Record *,char*,char*,char*,char*)
// Перерисовка
virtual void redr()
// Активизация
virtual void * active()
}
// ПРОТОТИПЫ ФУНКЦИЙ КНОПОК -----------------------------------
void fun_add()
void fun_del()
void up()
void down()
void find()
void edit()
void fun_exit()
void about()
// ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ --------------------------------------
// Указатель на активное окно
wind * act
// Флаг, устанавливаемый для выхода
int f_exit=0
// Список окон оснвного меню
wind * stwin
// Список окон меню ввода данных
wind * edwin
// Первый и текущий элементы базы данных
One_Record * ndb=NULL
One_Record * ctb=NULL
// Данные о окнах меню
// Основное меню
bt_win add_w(10,10,60,30," New ",fun_add)
bt_win del_w(80,10,60,30," Del ",fun_del)
bt_win edt_w(150,10,60,30," Edit ",edit)
bt_win fin_w(220,10,60,30," Find ",find)
bt_win ext_w(290,10,60,30," Exit ",fun_exit)
bt_win abt_w(360,10,60,30," About ",about)
bt_win up_w(430,10,30,14," Up ",up)
bt_win down_w(430,26,30,14," Dn ",down)
// Ввод/редактирование данных о студенте/ввод маски поиска
ed_win ifio(100,100,400,30," FIO ",55)
ed_win iyy(100,140,400,30,"Year",4)
ed_win iaddr(100,180,400,30," Addres ",55)
ed_win igrp(100,220,400,30," Group ",9)
// ГЛОБАЛЬНЫЕ ФУНКЦИИ -----------------------------------------
// Функция сравнения строки A с маской B
int stc(char * a,char * b) {
int n
if (strlen(a)<strlen(b)) return 0
for (n=0
n<strlen(b)
n++) if (a[n]!=b[n]) return 0
return 1
}
// ОПИСАНИЯ МЕТОДОВ КЛАССОВ -----------------------------------
// Объект ЗАПИСЬ ------------------------------------------
// Конструктор
One_Record::One_Record(char * m_fio,char * m_yy,char * m_addr,char * m_grp) {
strcpy(fio,m_fio)
strcpy(yy,m_yy)
strcpy(addr,m_addr)
strcpy(grp,m_grp)
next=NULL
last=NULL
}
// Коснтруктор для случая чтения из файла
One_Record::One_Record(int handle,One_Record * lst) {
char rs[140]
// Чтение во временную строку
read(handle,rs,140)
strcpy(fio,rs)
strcpy(yy,rs+60)
strcpy(addr,rs+65)
strcpy(grp,rs+125)
next=NULL
last=lst
if (!eof(handle))
next=new One_Record(handle,this)
}
// Запись данных файл
void One_Record::save(int handle) {
char rs[140]
strcpy(rs,fio)
strcpy(rs+60,yy)
strcpy(rs+65,addr)
strcpy(rs+125,grp)
_write(handle,rs,140)
if (next!=NULL) next->save(handle)
}
// Добавление записи в список
void One_Record::add(One_Record * a) {
// Проверка, дальше ли запись по алфавиту
if (strcmp(a->fio,fio)<0) {
// Вставка перед этим элементом
if (last!=NULL) {
a->last=last
a->next=this
last->next=a
last=a
} else {
a->next=this
a->last=NULL
last=a
}
// Дальше - либо добавление в конец, либо переход к следующему
} else if (next!=NULL) next->add(a)
else {
next=a
a->last=this
a->next=NULL
}
}
// Найти вверх по списку элемент, попадающий под маску
One_Record * One_Record::FindUp(char * m_fio,char * m_yy,char * m_addr,char * m_grp) {
if (stc(fio,m_fio)&&
stc(fio,m_fio)&&
stc(fio,m_fio)&&
stc(fio,m_fio)) return this
if (last!=NULL) return last->FindUp(m_fio,m_yy,m_addr,m_grp)
else return NULL
}
// Найти вниз по списку элемент, попадающий под маску
One_Record * One_Record::FindDown(char * m_fio,char * m_yy,char * m_addr,char * m_grp) {
if (stc(fio,m_fio)&&
stc(yy,m_yy)&&
stc(addr,m_addr)&&
stc(grp,m_grp)) return this
if (next!=NULL) return next->FindDown(m_fio,m_yy,m_addr,m_grp)
else return NULL
}
// Класс окон ---------------------------------------------
// Конструктор
wind::wind(int ix,int iy,int idx,int idy) {
x=ix
y=iy
dx=idx
dy=idy
pap=8
ink=15
apap=1
ts=1
next=NULL
}
// Перерисовка
void wind::redr() {
setfillstyle(1,pap)
setcolor(ink)
bar(x,y,x+dx,y+dy)
rectangle(x+3,y+3,x+dx-3,y+dy-3)
if (next!=NULL) next->redr()
}
// Добавление в список
void wind::add(void * p) {
if (next!=NULL) next->add(p)
else next=(wind *) p
}
// Активизация
void * wind::active() {
// Проверка, активизировать ли
if (ts) {
// Прорисовка активного состояния
setfillstyle(1,apap)
setcolor(ink)
bar(x,y,x+dx,y+dy)
rectangle(x+3,y+3,x+dx-3,y+dy-3)
char c
// Обработка клавиатуры - TAB - следующее, ESC - выход
do {
c=getch()
} while ((c!=9)&&(c!=27))
if (c==27) f_exit=1
return next
} else return next
// Нет - вернуть указатель на следующее
}
// Изменение флага TS
void wind::setact(char a) {
ts=a
}
// Класс строк редактирования -----------------------------
// Конструктор
ed_win::ed_win(int ix,int iy,int idx,int idy,char * p,int mln):
wind(ix,iy,idx,idy) {
maxlen=mln
strcpy(capt,p)
strcpy(pcapt,p)
}
// Перерисовка
void ed_win::redr(){
setfillstyle(1,pap)
setcolor(ink)
bar(x,y,x+dx,y+dy)
rectangle(x+3,y+3,x+dx-3,y+dy-3)
settextjustify(1,1)
outtextxy(x+dx/2,y+dy/2,capt)
if (next!=NULL) next->redr()
}
// Активизация
void * ed_win::active(){
unsigned char c
char ps[200]
if (!ts) return next
// Проверка, активизировать или пропустить
// Перерисовка
setfillstyle(1,apap)
setcolor(ink)
bar(x,y,x+dx,y+dy)
rectangle(x+3,y+3,x+dx-3,y+dy-3)
settextjustify(1,1)
do {
// Вывод строки с символом "_" в качестве курсора
strcpy(ps,capt)
strcat(ps,"_")
bar(x+4,y+4,x+dx-4,y+dy-4)
outtextxy(x+dx/2,y+dy/2,ps)
// Опрос клавиатуры
c=getch()
if (c==0) c=getch()
else {
if (c==8) {
// Удалить - переместить конец строки 0 на единицу левее
if (strlen(capt)>0) capt[strlen(capt)-1]=0
}
if (c==13) strcpy(pcapt,capt)
// ENTER - запомнить содержимое
if (c==27) strcpy(capt,pcapt)
// ESC - восстановить содержимое
if ((c>32)&&(strlen(capt)<maxlen)) {
// Иначе - добавить символ
capt[strlen(capt)+1]=0
capt[strlen(capt)]=c
}
}
} while (c!=9)
return next
}
// Класс кнопок -------------------------------------------
// Конструктор
bt_win::bt_win(int ix,int iy,int idx,int idy,char * p,void (*ifun)()):
wind(ix,iy,idx,idy) {
apap=12
pap=3
strcpy(capt,p)
fun=ifun
}
// Перерисовка
void bt_win::redr(){
setfillstyle(1,pap)
setcolor(ink)
bar(x,y,x+dx,y+dy)
rectangle(x+3,y+3,x+dx-3,y+dy-3)
settextjustify(1,1)
outtextxy(x+dx/2,y+dy/2,capt)
if (next!=NULL) next->redr()
}
// Активизация
void * bt_win::active(){
char c
if (ts) {
// Перерисовка активной кнопки
setfillstyle(1,apap)
setcolor(ink)
bar(x,y,x+dx,y+dy)
rectangle(x+3,y+3,x+dx-3,y+dy-3)
settextjustify(1,1)
outtextxy(x+dx/2,y+dy/2,capt)
// Обработка событий
do {
c=getch()
if (c==13) fun()
// ENTER - выполнение функции
} while ((c!=13)&&(c!=9)&&(c!=27)&&(!f_exit))
// Проверка условия завершения
if (c==27) f_exit=1
// Если ESC - выход из программы
}
return next
}
// Класс скроллеров ---------------------------------------
// Конструктор
sc_win::sc_win(int ix,int iy,int idx,int idy,One_Record * ipnt,char * ifio,char * iyy,char * iaddr,char * igrp):
wind(ix,iy,idx,idy) {
apap=1
pap=1
strcpy(m_fio,ifio)
strcpy(m_addr,iaddr)
strcpy(m_yy,iyy)
strcpy(m_grp,igrp)
pnt=ipnt->FindDown(ifio,iyy,iaddr,igrp)
}
// Перерисовка
void sc_win::redr() {
int n
int dlt=dx/5
One_Record * p
// Перерисовка
setfillstyle(1,apap)
setcolor(ink)
bar(x,y,x+dx,y+dy)
rectangle(x+3,y+3,x+dx-3,y+dy-3)
settextjustify(1,1)
// Вывод всех строк таблицы
p=pnt
n=20
while ((p!=NULL)&&(n<dy)) {
outtextxy(x+dlt,y+n,p->fio)
outtextxy(x+dlt*2,y+n,p->yy)
outtextxy(x+dlt*3,y+n,p->addr)
outtextxy(x+dlt*4,y+n,p->grp)
// Попытка найти следующий элемент
if (p->next!=NULL) p=p->next->FindDown(m_fio,m_yy,m_addr,m_grp)
else p=NULL
n+=20
}
}
// Активизация
void * sc_win::active() {
char c
One_Record * p
do {
redr()
c=getch()
if (!c) c=getch()
if (c==72) if (pnt!=NULL) {
// Вверх
p=pnt->FindUp(m_fio,m_yy,m_addr,m_grp)
if (p!=NULL) pnt=p
}
if (c==80) if (pnt!=NULL) {
// Вниз
p=pnt->FindDown(m_fio,m_yy,m_addr,m_grp)
if (p!=NULL) pnt=p
}
} while (c!=27)
setfillstyle(3,4)
bar(0,0,639,479)
return next
}
// ТЕЛА ФУНКЦИЙ КНОПОК ----------------------------------------
// Выход - просто установка флага
void fun_exit() {
f_exit=2
}
// Вверх - перемещение указателя и перерисовка полей редактирования
void up() {
if (ctb!=NULL) if (ctb->next!=NULL) {
ctb=ctb->next
strcpy(ifio.capt,ctb->fio)
strcpy(iyy.capt,ctb->yy)
strcpy(iaddr.capt,ctb->addr)
strcpy(igrp.capt,ctb->grp)
edwin->redr()
}
}
// Вниз - перемещение указателя и перерисовка полей редактирования
void down() {
if (ctb!=NULL) if (ctb->last!=NULL) {
ctb=ctb->last
strcpy(ifio.capt,ctb->fio)
strcpy(iyy.capt,ctb->yy)
strcpy(iaddr.capt,ctb->addr)
strcpy(igrp.capt,ctb->grp)
edwin->redr()
}
}
// Удаление
void fun_del() {
if (ctb!=NULL) {
if (ctb->last==NULL) {
ndb=ctb->next
ctb->next->last=NULL
delete ctb
ctb=NULL
if (ndb==NULL) setfillstyle(3,4)
bar(0,0,639,479)
} else {
ctb->last->next=ctb->next
ctb->next->last=ctb->last
delete ctb
ctb=NULL
}
}
}
// Добавление
void fun_add() {
wind * act
act=edwin
One_Record * a
do {
edwin->redr()
act=(wind *) act->active()
if (act==NULL) act=edwin
} while (!f_exit)
if (f_exit==2) {
a=new One_Record(ifio.capt,iyy.capt,iaddr.capt,igrp.capt)
if (ndb==NULL) ndb=a
else {
ndb->add(a)
if (ndb->last!=NULL) ndb=ndb->last
}
}
f_exit=0
}
// Поиск
void find() {
act=edwin
if (ctb==NULL) return
do {
edwin->redr()
act=(wind *) act->active()
if (act==NULL) act=edwin
} while (!f_exit)
if (f_exit==2) {
sc_win a(10,100,500,300,ndb,ifio.capt,iyy.capt,iaddr.capt,igrp.capt)
a.active()
}
f_exit=0
}
// Редактирование
void edit() {
act=edwin
if (ctb==NULL) return
do {
edwin->redr()
act=(wind *) act->active()
if (act==NULL) act=edwin
} while (!f_exit)
if (f_exit==2) {
strcpy(ctb->fio,ifio.capt)
strcpy(ctb->yy,iyy.capt)
strcpy(ctb->addr,iaddr.capt)
strcpy(ctb->grp,igrp.capt)
}
f_exit=0
}
void about() {
cleardevice()
setfillstyle(6,5)
bar(0,0,639,479)
setfillstyle(1,0)
bar(100,100,539,379)
rectangle(100,100,539,379)
outtextxy(320,130," О ПРОГРАММЕ ")
getch()
setfillstyle(3,4)
bar(0,0,639,479)
}
// Основная программа
void main() {
int drv,mode
int handle
drv=DETECT
initgraph(&drv,&mode,"")
setfillstyle(3,4)
bar(0,0,639,479)
ed_win hlp(10,440,620,40,
" Выбор пункта - TAB, Активизация - ENTER, Выход - ESC ",0)
hlp.setact(0)
// попытка считать базу данных
handle=open("base_o.dat",O_RDONLY|O_BINARY)
if (handle>=0) {
ndb=new One_Record(handle,NULL)
}
// Добавление в списки соответствующих окон
wind * stwin
stwin=(wind *) new ed_win(10,50,590,20," Student database ",5)
stwin->setact(0)
stwin->add(&hlp)
stwin->add(&add_w)
stwin->add(&del_w)
stwin->add(&edt_w)
stwin->add(&fin_w)
stwin->add(&ext_w)
stwin->add(&abt_w)
stwin->add(&up_w)
stwin->add(&down_w)
act=stwin
edwin=(wind *) new bt_win(250,300,100,20," OK ",fun_exit)
edwin->add(&ifio)
edwin->add(&iyy)
edwin->add(&iaddr)
edwin->add(&igrp)
// Обработка событий
do {
// Проверка, чтобы указатель на текущий при непустом списке всегда
// показывал на один из элементов
if (ctb==NULL) ctb=ndb
if (ctb!=NULL) {
strcpy(ifio.capt,ctb->fio)
strcpy(iyy.capt,ctb->yy)
strcpy(iaddr.capt,ctb->addr)
strcpy(igrp.capt,ctb->grp)
edwin->redr()
}
// Перерисовка
stwin->redr()
// Активизация очередного окна
act=(wind *) act->active()
if (act==NULL) act=stwin
} while (!f_exit)
closegraph()
// Запись в файл или его удаление при пустой базе
if (ndb!=NULL) {
handle=open("base_o.dat",O_WRONLY|O_TRUNC|O_CREAT|O_BINARY)
if (handle>=0) {
while (ndb->last!=NULL) ndb=ndb->last
ndb->save(handle)
} else perror(" Error: ")
} else {
remove("base_o.dat")
}
close(handle)
}
Для подготовки данной работы были использованы материалы с сайта http://kurslab.chat.ru/