抽空帮别人写了个C语言的课程设计,一个简单的通讯录,要求如下:
题目一 简单的数据库管理
建立一个通讯录系统,系统中保存着各人员的姓名、电话、住址、邮编等信息,通过该系统的界面可以浏览这些信息,也可以插入、添加及删除某个人员的信息。
数据结构:
1.
Person
Name,phone,address,postcode
2.
Card
Person, *prev, *next
3.
Book
Count,*head,*last,*curcard
操作:
1.
双链表的建立,插入,添加及删除
2.
文件的读写
3.
键盘响应
参考界面:
-------------------------------------------------------------------------------------------------------------------------
/*
* 本程序在tc2.0及tc3.0下调试通过。
*
*/
/******头文件(.h)***********/
#include "stdio.h" /*I/O函数*/
#include "bios.h" /*ROM基本输入输出函数*/
#include "dos.h" /*dos接口函数*/
#include "conio.h" /*屏幕操作函数*/
#include "stdlib.h" /*其它说明*/
#include "string.h" /*字符串函数*/
#include "mem.h" /*内存操作函数*/
#include "ctype.h" /*字符操作函数*/
#include "alloc.h" /*动态地址分配函数*/
/****变量定义*******/
#define Enter 13
#define upkey 72
#define dnkey 80
struct person /*定义数据结构*/
{
char name[20]; /*姓名*/
char phone[20]; /*电话*/
char address[128]; /*地址*/
char postcode[20]; /*邮编*/
};
struct card
{
struct person p;
struct card *prior;/*前驱指针*/
struct card *next;/*后继指针*/
};
struct book
{
struct card *first;
struct card *last;
struct card *curcard;
};
struct book b; /*通讯录*/
int iLastMenu = 0; /*记住本次操作之前上一次选择的菜单项*/
char cErrMsg[200]; /*记录最后操作的结果信息*/
/******函数原型*********/
void init(); /*初始化*/
void delete(); /*删除*/
void search(); /*查找*/
void save(); /*保存文件*/
void load(); /*读取文件*/
void insert(); /*插入*/
void append(); /*追加*/
int menu_select(); /*主菜单*/
void DisplayFirstPage();/*显示第一页*/
void DisplayPriorPage();/*显示上一页*/
void DisplayNextPage();/*显示下一页*/
void DisplayLastPage();/*显示最后页*/
void PrintErrMsg(char *sFmtMsg);/*打印结果信息*/
void inputs(char *s, int count,char *sInputTip);/*字符串输入和验证函数*/
void Quit();/*退出整个程序*/
/*******主函数开始**********/
main()
{
init();
clrscr();
for(;;)
{
switch(menu_select()) /*调用菜单函数返回一个整数值*/
{
case 0:DisplayFirstPage();break; /*显示第一条记录*/
case 1:DisplayPriorPage();break; /*显示上一条记录*/
case 2:DisplayNextPage();break; /*显示下一条记录*/
case 3:DisplayLastPage();break; /*显示最后一条记录*/
case 4:append();break; /*添加记录*/
case 5:insert();break; /*插入记录*/
case 6:delete();break; /*删除记录*/
case 7:search();break; /*按名字检索记录*/
case 8:load();break; /*导入文件中记录*/
case 9:save();break; /*保存文件*/
case 10:Quit(); /*退出*/
}
}
}
/*菜单函数,函数返回值为整型,代表所选的菜单项*/
menu_select()
{
char *f[]= { /*定义菜单字符串数组*/
/*"**************MENU*************",*/ /*菜单的标题行*/
" 0. FirstPage 第一页", /*显示第一条记录*/
" 1. PriorPage 上一页", /*显示上一条记录*/
" 2. NextPage 下一页", /*显示下一条记录*/
" 3. LastPage 最后页", /*显示最后一条记录*/
" 4. Append 添 加", /*添加记录*/
" 5. Insert 插 入", /*插入记录*/
" 6. Delete 删 除", /*删除记录*/
" 7. SearchName检 索", /*按名字检索记录*/
" 8. LoadFile 导 入", /*导入文件中记录*/
" 9. SaveFile 保 存", /*保存至文件中*/
" 10. Quit 退 出", /*退出*/
};
char s[80];
int i;
int key=0; /*记录所压键值*/
int c=0;
textbackground(BLACK); /*设置背景颜色为黑色*/
window(1,1,80,25); /*恢复原窗口大小*/
clrscr(); /*清屏*/
textcolor(YELLOW); /*设置文本颜色为黄色*/
textbackground(BLUE); /*设置背景颜色为兰色*/
/*画右边结果显示窗口*/
gotoxy(32,2);
putch(0xda); /*输出左上角边框┏*/
for(i=1;i<47;i++)
putch(0xc4); /*输出上边框水平线*/
putch(0xbf); /*输出右上角边框 ┓*/
for(i=3;i<19;i++)/*输出左右两边的垂直线*/
{
gotoxy(32,i);putch(0xb3);
gotoxy(79,i);putch(0xb3);
}
gotoxy(32,18);putch(0xc0); /*输出左上角边框┗*/
for(i=1;i<47;i++)
putch(0xc4); /*输出下边框水平线*/
putch(0xd9); /*输出右下角边框┛*/
window(33,3,78,17); /* 制作右边结果显示窗口*/
clrscr(); /*清屏*/
gotoxy(2,2);
cprintf("%s %s","Name 姓名:",(b.curcard != NULL)?b.curcard->p.name:""); /*输出通讯录中的当前项*/
gotoxy(2,4);
cprintf("%s %s","Phone 电话:",(b.curcard != NULL)?b.curcard->p.phone:""); /*输出通讯录中的当前项*/
gotoxy(2,6);
cprintf("%s %s","Address 地址:",(b.curcard != NULL)?b.curcard->p.address:""); /*输出通讯录中的当前项*/
gotoxy(2,8);
cprintf("%s %s","Postcode邮编:",(b.curcard != NULL)?b.curcard->p.postcode:""); /*输出通讯录中的当前项*/
window(1,1,80,25); /*恢复原窗口大小*/
textcolor(YELLOW); /*设置文本颜色为黄色*/
textbackground(BLUE); /*设置背景颜色为兰色*/
/*画最下面输入窗口*/
gotoxy(2,20);
putch(0xda); /*输出左上角边框┏*/
for(i=1;i<77;i++)
putch(0xc4); /*输出上边框水平线*/
putch(0xbf); /*输出右上角边框 ┓*/
for(i=21;i<25;i++)/*输出左右两边的垂直线*/
{
gotoxy(2,i);putch(0xb3);
gotoxy(79,i);putch(0xb3);
}
gotoxy(2,24);putch(0xc0); /*输出左上角边框┗*/
for(i=1;i<77;i++)
putch(0xc4); /*输出下边框水平线*/
putch(0xd9); /*输出右下角边框┛*/
window(3,21,78,23); /* 制作输入数据的窗口*/
textcolor(WHITE); /*设置文本颜色为白色*/
clrscr(); /*清屏*/
gotoxy(2,1);
cprintf("%s",cErrMsg); /*输出结果信息*/
window(1,1,80,25); /*恢复原窗口大小*/
textcolor(YELLOW); /*设置文本颜色为黄色*/
textbackground(BLUE); /*设置背景颜色为兰色*/
/*画左边主菜单窗口*/
gotoxy(2,2);
putch(0xda); /*输出左上角边框┏*/
for(i=1;i<28;i++)
putch(0xc4); /*输出上边框水平线*/
putch(0xbf); /*输出右上角边框 ┓*/
for(i=3;i<18;i++)/*输出左右两边的垂直线*/
{
gotoxy(2,i);putch(0xb3);
gotoxy(30,i);putch(0xb3);
}
gotoxy(2,18);putch(0xc0); /*输出左上角边框┗*/
for(i=1;i<28;i++)
putch(0xc4); /*输出下边框水平线*/
putch(0xd9); /*输出右下角边框┛*/
window(3,3,29,17); /* 制作显示菜单的窗口,大小根据菜单条数设计*/
clrscr(); /*清屏*/
for(i=0;i<11;i++)
{
gotoxy(3,i+1);
cprintf("%s",f[i]); /*输出菜单项数组*/
}
i = iLastMenu;
gotoxy(3,i + 1); /*设置默认选项在上一次操作的项目上*/
textbackground(LIGHTGREEN);/*设置背景颜色为浅绿*/
cprintf("%s",f[iLastMenu]); /*输出菜单项,表示选中*/
while(key != Enter) /*所压键不是回车键时*/
{
while(bioskey(1)==0); /*查询是否压下了一个键*/
key=bioskey(0); /*返回下一个在键盘压下的键*/
key=key&0xff?key&0xff:key>>8; /*对所压的键进行判断*/
gotoxy(3,i+1);
textbackground(BLUE);/*设置背景颜色为蓝色*/
cprintf("%s",f[i]); /*输出菜单项*/
if(key==upkey) i=i==0?10:i-1; /*如压向上光标键↑,i减1,如已到第一行再上移,则到最后一行*/
if(key==dnkey)i=i==10?0:i+1; /*如压向下光标键↓,i加1,如已到最后一行再下移,则到第一行*/
gotoxy(3,i+1); /*光标移动i的下一项*/
textbackground(LIGHTGREEN); /*将背景颜色设为浅绿*/
cprintf("%s",f[i]); /*输出菜单项*/
c=i; /*给代表菜单选项的整数赋值*/
}
textbackground(BLACK); /*设置背景颜色为黑色*/
window(1,1,80,25); /*恢复原窗口大小*/
iLastMenu = c;
return c; /*返回代表菜单选项的整数值*/
}
/*初始化函数*/
void init()
{
b.first = NULL;
b.last = NULL;
b.curcard = NULL;
memset(cErrMsg,0,200);
}
/*字符串输入和验证函数*/
void inputs(char *s, int count,char *sInputTip)
{
char p[255];
do{
clrscr();
gotoxy(2,1);
cprintf("%s/n",sInputTip); /**/
memset(p,0,255);
scanf("%s",p);/*输入字符串*/
gotoxy(2,2);
if(strlen(p)>count)
{
cprintf("too long! Press Any Key and Retry!");/*进行长度校验,超过count值重输入*/
getch();
}
else
if(strlen(p) < 1)
{
cprintf("too short! Press Any Key and Retry!");
getch();
}
clreol();
}while((strlen(p)>count)||(strlen(p) < 1));
strcpy(s,p); /*将输入的字符串拷贝到字符串s中*/
}
void PrintErrMsg(char *sFmtMsg)
{
textcolor(WHITE); /*设置文本颜色为白色*/
textbackground(BLUE); /*设置背景颜色为兰色*/
window(3,21,78,23); /* 制作输入数据的窗口*/
clrscr(); /*清屏*/
gotoxy(2,1);
cprintf("%s",sFmtMsg); /*输出结果信息*/
strcpy(cErrMsg,sFmtMsg);/*将本次结果信息拷贝至系统全局结果信息数组中*/
}
/*显示第一页*/
void DisplayFirstPage()
{
b.curcard = b.first;
if(b.curcard == NULL)
PrintErrMsg("There is no record now!");
else
PrintErrMsg("First record is found!");
}
/*显示上一页*/
void DisplayPriorPage()
{
if(b.curcard != NULL)
{
if(b.curcard->prior != NULL)
{
b.curcard = b.curcard->prior;
PrintErrMsg("Prior record is found!");
}
else
PrintErrMsg("Has Reached the first record!");
}
else
{
PrintErrMsg("Current card is empty,no prior record!");
}
}
/*显示下一页*/
void DisplayNextPage()
{
if(b.curcard != NULL)
{
if(b.curcard->next != NULL)
{
b.curcard = b.curcard->next;
PrintErrMsg("Next record is found!");
}
else
PrintErrMsg("Has Reached the Last record!");
}
else
{
PrintErrMsg("Current card is empty,no next record!");
}
}
/*显示最后页*/
void DisplayLastPage()
{
b.curcard = b.last;
if(b.curcard == NULL)
PrintErrMsg("There is no record now!");
else
PrintErrMsg("Last record is found!");
}
/*删除结点*/
void delete()
{
char cFmtMsg[100];
struct card *p; /*定义临时变量,p指向要删除的结点p*/
p = b.curcard;
if (!p)
{
PrintErrMsg("Current card is empty, nothing deleted!");
return;
}
if(p != NULL) /*调用查找函数,如果找到做下面的处理*/
{
if(b.first == p) /*如果是第一个结点*/
{
b.first = p->next; /*将头指针指向其后继结点*/
if(b.first) /*如头指针不为空*/
{
b.first->prior=NULL; /*将头结点的前驱设为空*/
b.curcard = b.first;
}
else
{
b.last = NULL; /*否则头为空,尾也为空*/
b.curcard = NULL;
}
}
else /*删除的不是第一个结点*/
{
p->prior->next = p->next; /*p的前驱的后继指向p原来的后继*/
if(p != b.last) /*如果p不是最后个结点*/
{
p->next->prior = p->prior; /*p后继的前驱指向p原来的前驱*/
b.curcard = p->next;
}
else
{
b.last = p->prior;/*如p是最后一个结点,修改尾指针为p的前驱*/
b.curcard = b.last;
}
}
sprintf(cFmtMsg,"have deleted %s CARD/n%s",p->p.name,"Don't forget save");
PrintErrMsg(cFmtMsg);
free(p); /*删除结点后,不要忘记释放空间*/
}
}
/*按姓名查找结点*/
void search()
{
struct card *p; /*移动指针*/
char s[15]; /*保存姓名*/
char cFmtMsg[100];
textcolor(WHITE); /*设置文本颜色为白色*/
textbackground(BLUE); /*设置背景颜色为兰色*/
window(3,21,78,23); /* 制作输入数据的窗口*/
inputs(s,15,"please enter name for search:");
p = b.first; /*移动指针从头指针开始*/
if (!p)
{
PrintErrMsg("Book is empty!"); /*显示没找到信息*/
return;
}
while(strcmp(p->p.name,s)&&p!=NULL) /*做比较判断*/
p=p->next; /*没找到,指针后移继续查找*/
if(p == NULL) /*指针为空,说明没有找到*/
{
sprintf(cFmtMsg,"nlist no %s CARD",s);
PrintErrMsg(cFmtMsg); /*显示没找到信息*/
}
else
{
sprintf(cFmtMsg,"nlist FOUND %s CARD",s);
PrintErrMsg(cFmtMsg); /*显示没找到信息*/
b.curcard = p;
}
}
/*插入结点*/
void insert()
{
char cFmtMsg[100];
struct card *p,*info; /* info为新结点,p为新结点的后继*/
textcolor(WHITE); /*设置文本颜色为白色*/
textbackground(BLUE); /*设置背景颜色为兰色*/
window(3,21,78,23); /* 制作输入数据的窗口*/
clrscr(); /*清屏*/
info = (struct card *)malloc(sizeof(struct card)); /*申请空间*/
memset(info,0,sizeof(struct card));
if(!info)
{
PrintErrMsg("/nout of memory"); /*如没有得到空间,内存溢出*/
exit(0); /*退出程序*/
}
info->next=NULL; /*新结点的后继为空*/
info->prior=NULL; /*新结点的前驱为空*/
inputs(info->p.name,20,"Please input NAME:"); /*输入新结点的姓名,并校验*/
inputs(info->p.phone,20,"Please input Phone:"); /*输入新结点的电话,并校验*/
inputs(info->p.address,128,"Please input Address:"); /*输入新结点的地址,并校验*/
inputs(info->p.postcode,20,"Please input Postcode:"); /*输入新结点的邮编,并校验*/
p = b.curcard; /*移动指针从当前指针开始*/
b.curcard = info;/*更新当前指针*/
if(p==NULL) /*如p为空*/
if(p == b.first) /*如p为头指针,说明链表为空*/
{
b.first = info; /*新结点为头指针*/
b.first->prior = NULL; /*头结点的前驱为空*/
b.last = b.first; /*唯一结点,尾指针等于头指针*/
}
else /*新结点插在尾部*/
{
b.last->next = info;
info->prior = b.last;
b.last = info; /*尾指针指向新结点*/
}
else
if(p == b.first) /*p不为空,但p为头指针,新结点插在第一个结点位置*/
{
info->prior = NULL; /*新结点的前驱为空*/
info->next = p; /*新结点的后继为p*/
p->prior = info; /*p的前驱是新结点*/
b.first = info; /*修改头指针指向新结点*/
}
else /*新结点插入在中间某一个位置p之前*/
{
info->next = p; /*新结点的后继是p*/
info->prior = p->prior; /*新结点的前驱是p的前驱*/
p->prior->next = info; /*p的前驱的后继是新结点*/
p->prior = info; /*p的前驱是新结点*/
}
sprintf(cFmtMsg," ----have inserted %s CARD----/n%s",info->p.name,"---Don't forget save---");
PrintErrMsg(cFmtMsg);
}
/*保存文件*/
void save()
{
FILE *fp; /*定义指向文件的指针*/
struct card *p; /*定义移动指针*/
char outfile[100]; /*保存输出文件名*/
textcolor(WHITE); /*设置文本颜色为白色*/
textbackground(BLUE); /*设置背景颜色为兰色*/
window(3,21,78,23); /* 制作输入数据的窗口*/
clrscr(); /*清屏*/
inputs(outfile,100,"Enter outfile name,for example c://test//test.txt:");
if((fp=fopen(outfile,"wb"))==NULL) /*为输出打开一个二进制文件*/
{
PrintErrMsg("can not open file");
return; /*返回*/
}
PrintErrMsg("Saving file......");
p = b.first; /*移动指针从头指针开始*/
while(p != NULL) /*如p不为空*/
{
fwrite(p,sizeof(struct card),1,fp); /*写入一条记录*/
p=p->next; /*指针后移,处理下一条记录*/
}
fclose(fp); /*关闭文件*/
PrintErrMsg("-----save success!!-----");/*显示保存成功*/
}
/*读文件*/
void load()
{
struct card *p,*q=NULL; /*定义记录指针变量*/
FILE *fp; /* 定义指向文件的指针*/
char infile[100]; /*保存文件名*/
long pos, pos2; /*保存文件指针的位置*/
textcolor(WHITE); /*设置文本颜色为白色*/
textbackground(BLUE); /*设置背景颜色为兰色*/
window(3,21,78,23); /* 制作输入数据的窗口*/
clrscr(); /*清屏*/
inputs(infile,100,"Enter infile name,for example c://test//test.txt:");
if((fp=fopen(infile,"rb"))==NULL) /*打开一个二进制文件,为读方式*/
{
PrintErrMsg("can not open file/n"); /*如不能打开,则结束程序*/
return; /*返回*/
}
if(fseek(fp, 0L, SEEK_SET)) /*将文件指针指到开始位置*/
{
PrintErrMsg( "fseek to beginning failed" );
return;
}
if((pos = ftell(fp)) == -1L) /*获取开始指针位置,以便结合结束位置指针判断文件长度*/
{
PrintErrMsg( "ftell failed" );
return;
}
if(fseek( fp, 0L, SEEK_END)) /*将文件指针指到结束位置*/
{
PrintErrMsg( "fseek to end failed" );
return;
}
if((pos2 = ftell(fp)) == -1L) /*获取结束指针位置,以便结合开始位置指针判断文件长度*/
{
PrintErrMsg( "ftell failed" );
return;
}
if((pos2 - pos) < sizeof(struct card)) /*文件中记录数不足一个或为空*/
{
PrintErrMsg("The infile has no records,please check!");
return;
}
if(fseek( fp, 0L, SEEK_SET))/*将文件指针重新指到开始位置,*/
{
PrintErrMsg( "fseek to beginning failed" );
return;
}
while(b.first) /*当表不为空时,清空链表*/
{
p=b.first; /*从头指针开始*/
b.first=b.first->next; /*删除头结点*/
free(p); /*释放空间*/
}
PrintErrMsg(" -----Loading file!-----"); /*显示正在读文件*/
b.first =(struct card *)malloc(sizeof(struct card)); /*为头指针申请空间*/
if(!b.first) /*如果没有得到空间 显示内存溢出*/
{
PrintErrMsg("out of memory!");
return; /*返回*/
}
p = b.first; /*将头指针赋值给p*/
while(!feof(fp)) /*当文件不空时*/
{
if(1!=fread(p,sizeof(struct card),1,fp))break; /*将记录读到p所指的结点*/
p->next=(struct card *)malloc(sizeof(struct card));/*为p的后继申请空间*/
if(!p->next) /*如果没有得到空间显示内存溢出*/
{
PrintErrMsg("out of memory!");
return; /*返回*/
}
p->prior=q; /*得到空间,则链接指针关系p的前驱为q*/
q=p; /*保存p做为新的p结点的前驱*/
p=p->next; /*p指针后移*/
}
q->next=NULL; /*q的后继为空*/
b.last = q; /*尾指针为q*/
b.first->prior=NULL; /*头指针的前驱为空*/
b.curcard = b.first;
PrintErrMsg("---You have success read data from file!!!---"); /*显示成功读入记录*/
fclose(fp); /*关闭文件*/
}
/*追加记录*/
void append()
{
char cFmtMsg[200];
struct card *info; /* info为新结点*/
textcolor(WHITE); /*设置文本颜色为白色*/
textbackground(BLUE); /*设置背景颜色为兰色*/
window(3,21,78,23); /* 制作输入数据的窗口*/
clrscr(); /*清屏*/
info = (struct card *)malloc(sizeof(struct card)); /*申请空间*/
memset(info,0,sizeof(struct card));
if(!info)
{
PrintErrMsg("out of memory"); /*如没有得到空间,内存溢出*/
exit(0); /*退出程序*/
}
info->next=NULL; /*新结点的后继为空*/
info->prior=NULL; /*新结点的前驱为空*/
inputs(info->p.name,20,"Please input NAME:"); /*输入新结点的姓名,并校验*/
inputs(info->p.phone,20,"Please input Phone:"); /*输入新结点的电话,并校验*/
inputs(info->p.address,128,"Please input Address:"); /*输入新结点的地址,并校验*/
inputs(info->p.postcode,20,"Please input Postcode:"); /*输入新结点的邮编,并校验*/
if(b.last == NULL) /*说明链表为空*/
{
b.last = info; /*新结点为头指针*/
b.last->prior = NULL; /*头结点的前驱为空*/
b.first = b.last; /*唯一结点,尾指针等于头指针*/
}
else
{
b.last->next = info;
info->prior = b.last;
info->next = NULL;
b.last = info;
}
b.curcard = info;/*更新当前指针*/
sprintf(cFmtMsg,"have appended %s CARD/n%s",info->p.name,"Don't forget save");
PrintErrMsg(cFmtMsg);
}
/*退出整个程序*/
void Quit()
{
clrscr();
exit(0);
}