C++语言程序设计
课程设计
简单通讯录管理
041010402
刘璐瑶
C++语言程序设计 课程设计
041010402 刘璐瑶 - 2 -
一. 程序功能简介
通讯录是一个简单的数据库库表,每一个记录(结点)包含一个人的所有通讯信息,
详见后面 Node 类的定义。
程序执行过程为:显示主菜单,用户在 Choice:输入选项(按照功能列表输入 1~9
中的一个数字),按回车后,执行相应的功能。
主菜单如右图所示,各菜单功能如下:
1. 添加联系人信息:提示输入个字段。一次输入一个人的数据。新记录加入后,通讯录
按指定的排序顺序排序;选择菜单“8.将通讯录排序:”后可修改排序顺序为按“办
公电话”排序。指定一种排序方法后,就一直保持次排序方法,直到重新指定。
2. 删除联系人记录:输入待删除记录的姓名,显示该姓名下的所有信息,让用户确认是
否要删除。
3. 显示所有记录:按顺序显示所有记录,每显示 10 条记录,暂停,用户按<enter>键继
续。
4. 查询联系人记录:按姓名查找并显示一条联系人记录。
5. 修改联系人记录:按姓名修改一条联系人记录。
用户输入姓名,系统显示该姓名下的所有信息,同时显示子菜单,用户按子菜单提示,
指定修改哪一个数据项。
子菜单如下:
1. 修改姓名
2. 修改办公室电话
3. 修改住宅电话
4. 修改手机号码
5. 修改 email 地址
选择(1~5):
【注意:若修改的是当前排序字段(“姓名”或“办公电话”),程序内部应调用排
序程序重新排序。
6. 从正文文件添加数据到通讯录:从正文文件中添加数据到库表中。用户可事前建立一
个正文文件,存放待加入的数据,然后从该文件中一次性导入多个人员的数据。程序
运行时,用户需输入正文文件的文件名。
7. 从通讯录导出数据到正文文件:将库表中的数据写入一个正文文件中。程序运行时,
用户需输入正文文件的文件名。
8. 将通讯录排序:系统按默认“姓名”排序。当执行主菜单“将通讯录排序”命令时,
系统显示当前排序关键字。用户可选择是否修改排序关键字。
9. 退出:退出管理系统。
二. 课程设计中遇到的问题及解决办法
1. Node 类和 addrlist 的结合
将 addrlist 说明为 Node 的友元类,使 addrlist 中的所有成员都成为 Node 类中的友
元函数
2.文件的读入读出
此次课设中,涉及了许多有关文件的写入写出的程序,是我在做课设之前还没有学习
的,在通过一天的自学和查阅资料后,终于对相关文件的代码有了基本的了解,和具备
了一定的应用能力,并在之后大二学姐的帮助下,终于解决了这一难题。
3.子菜单的实现
用两个 displaymenu 函数加上 switch 循环实现
4.程序的运行与调试
不断改进,耐心调试,永不放弃
三. 课程设计心得体会
刚拿到这个课设的时候,其实是一点头绪都没有的,便去翻阅了一些资料,查了很多和
通讯相似的源程序,以及参考了上一届的学长的课设,才终于找到了一点思路。于是,就这样
一个小函数一个小函数编了下去。到后面看到成有五六百行之长的时候,心里十分喜悦。但痛
苦的其实还在后面。
在此次课设过程中,最令我感到困难的就是最后有关程序的调试,熟话说,“三分编程,
七分调试”,因而调试一个相当繁琐的过程,在辛苦调试数小时后,最后竟还是会出现程序没
有错误,但是无法运行的情况。曾经有想过放弃,但是,想到自己辛苦了那么长的时间不能白
费,于是在学长的鼓励和帮助下,还是找的了程序运行不出的根源。这正应了那一句“山重水
复疑无路,柳暗花明又一春”的古语。
通过设计一个《通讯录管理系统》,使我进一步熟悉了C++中类的概念;并加强了有关链
表的基本知识和应用能力;掌握了面向对象程序设计的基本思路和方法,利用所学的基本知识
和技能解决简单的面向对象的程序设计问题。了解系统开发的需求分析、类层次设计、模块分
C++语言程序设计 课程设计
041010402 刘璐瑶 - 3 -
解、编码测试、模块组装与整体调试的全过程,加深对C++的理解与Visual C++环境的使用,
逐步熟悉程序设计的方法,养成了良好的编程习惯。
学校提供给我们这次宝贵的课程设计实践机会,让我们可以动手动脑,大大提高了个人
的能力和素质。一个程序,只有经过自己的不断探索,和不断完善之后,才能找到最优的解决
方案,这也使得我充分体会到了程序编制的整个过程,为以后的学习和工作打下了良好的基础。
同时,从这点小事,我发现,仅仅只依靠老师所讲的和课本上的知识是完全不够的,只
有通过实践,加上自己在课堂之后额外的探索发现,才能使我们真正掌握某些能力;同时,做
任何事都不要轻易放弃,任何困难总会找到它的解决办法。
四. 设计及其分析(程序源代码)
#include<iostream.h>
#include<fstream.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
#include<iomanip.h>
/*===============引用性说明============*/
class AddrList;
int Total=0;//联系人记录个数,方便文件的读写
/*===============定义一个结点类==================*/
class Node
{
char Name[10]; //姓名
int OfficePhone; //办公室电话
int HomePhone; //住宅电话
char MobilePhone[15]; //手机号码
char EMail[20]; //email 地址
Node *Next; //下一结点指针
public:
Node(char *n=NULL,int o=0,int h=0,char *m= NULL,char *e= NULL)//构造函数,各参
数均有缺省值
{
strcpy(Name,n); //注意字符串的赋值
OfficePhone=o;
HomePhone=h;
strcpy(MobilePhone,m);
strcpy(EMail,e);
}
void Show() //显示结点数据
{
cout<<setw(10)<<Name<<setw(11)<<OfficePhone<<setw(11)<<HomePhone<<setw(14)<<M
obilePhone<<setw(20)<<EMail<<'\n';
}
void SetName(char *); //修改姓名
void SetOfficePhone(int &); //修改办公室电话
void SetHomePhone(int &); //修改住宅电话
void SetMobilePhone(char *); //修改手机号码
void SetEMail(char *); //修改 email 地址
//void SetNext()
//{Next=NULL;}
friend class AddrList; //将 AddrList 类说明为友元类
};
void Node::SetName(char *n) //类外定义函数,修改姓名
{ strcpy(Name,n);}
void Node::SetOfficePhone(int &o) //类外定义函数,修改办公室电话
{ OfficePhone=o;}
void Node::SetHomePhone(int &h) //类外定义函数,修改住宅电话
{ HomePhone=h;}
C++语言程序设计 课程设计
041010402 刘璐瑶 - 4 -
void Node::SetMobilePhone(char *m) //类外定义函数,修改手机号码
{ strcpy(MobilePhone,m);}
void Node::SetEMail(char *e) //类外定义函数,修改 email 地址
{ strcpy(EMail,e);}
/*========================================定义一个链表类
=====================================*/
class AddrList
{
Node *HeadPtr; //链表首指针
Node *TailPtr; //链表尾指针
int Tag; //排序状态标志,当 tag=1,表示按姓名排序;
默认按姓名排序
// 当 tag=2,表示按办公室电话
排序
public:
AddrList() //构造函数,创建空链表,将 tag 的值置为 1
{
HeadPtr=NULL;
TailPtr=NULL;
Tag=1;
}
void AddTail(Node *p); //将 p 指向的结点加入到链表尾部
void AddSort(Node *p); //将 p指向的结点按 Tag 指定的顺序插入到链表
中
Node *LookUp(char *name); //按姓名查找结点,返回该结点指针
void Delete(char *name); //删除指定姓名的结点
void Sort(int tag); //按 tag 指定的关键字重新排序
void ShowAll(); //显示全部结点,每 10 个显示一屏
void SetTag(int & t) //置 tag 值
{ Tag=t;}
int GetTag() //取 tag 值
{ return Tag;}
Node *GetHeadPtr() //取首指针
{ return HeadPtr;}
~AddrList() //释放链表空间
{
if(HeadPtr) delete [] HeadPtr;
if(TailPtr) delete [] TailPtr;
}
void CreateList(char *filename); //从二进制文件中读入数据,构造链表
void WriteToFile(char *filename); //将链表中数据写入指定的二进制文件
void Fromtxt(); //从正文文件中导入数据到库表中
void Totxt(); //将数据从库表导入到正文文件中
};
void AddrList::AddTail(Node *p) //将 p 指向的结点加入到链表尾部
{
TailPtr=p;
p->Next=NULL;
}
void AddrList::AddSort(Node *p) //将 p 指向的结点按 Tag 指定的顺序插入到链表
中
{
if(Tag==1) //按姓名排序
{
Node *p1,*p2;
if(HeadPtr==NULL) //如果插入前原始链表是空链表
{
HeadPtr=TailPtr=p;
p->Next=NULL;
C++语言程序设计 课程设计
041010402 刘璐瑶 - 5 -
}
else if(strcmp(HeadPtr->Name,p->Name)>=0)//插在链表首部
{
p->Next=HeadPtr;
HeadPtr=p;
}
else //插在链表中间或尾部
{
p2=p1=HeadPtr;
while(p2->Next&&strcmp(p2->Name,p->Name)<0) //查找待插入位置
{
p1=p2;
p2=p2->Next;//指向后一个结点,p1 指向的结点在 p2 之前
}
if(strcmp(p2->Name,p->Name)<0) //插在链表尾部
{
p2->Next=p;
p->Next=NULL;
TailPtr=p;
}
else //插在链表中间,p2 之前
{
p->Next=p2;
p1->Next=p;
}
}
}
if (Tag==2) //按办公室电话号码排序
{
Node *p1,*p2;
if(HeadPtr==NULL) //如果插入前原始链表为空链表
{
HeadPtr=p;
p->Next=NULL;
}
else if(HeadPtr->OfficePhone>=p->OfficePhone) //插在链表首部
{
p->Next=HeadPtr;
HeadPtr=p;
}
else //插在链表中间或尾部
{
p2=p1=HeadPtr;
while(p2->Next&&(p2->OfficePhone<p->OfficePhone)) //查找待插入位置
{
p1=p2;
p2=p2->Next;
}
if(p2->OfficePhone<p->OfficePhone) //插在链表尾部
{
p2->Next=p;
p->Next=NULL;
}
else // 插在链表中间,p2 之前
{
p->Next=p2;
p1->Next=p;
}
}
}
}