C++课程设计 通讯录管理系统 原码及解析
设计题目:通信录管理系统
用C++设计出模拟手机通信录管理系统,实现对手机中的通信录进行管理。
(一)功能要求
- 查看功能:选择此功能时,列出下列三类选择。
A 办公类B 个人类C 商务类,当选中某类时,显示出此类所有数据中的姓名和电话号码)- 增加功能: 能录入新数据(一个结点包括:姓名、电话号码、分类(可选项有:A 办公类B 个
人类C 商务类)、电子邮件)。例如
杨春13589664454 商务类chuny@126.com
当录入了重复的姓名和电话号码时,则提示数据录入重复并取消录入;当通信录中超过15 条信息时,存储空间已满,不能再录入新数据;录入的新数据能按递增的顺序自动进行条目编号。- 拔号功能: 能显示出通信录中所有人的姓名,当选中某个姓名时,屏幕上模拟
打字机
的效果依次显示
出此人的电话号码中的各个数字,并伴随相应的拔号声音
。- 修改功能: 选中某个人的姓名时,可对此人的相应数据进行修改
+删除功能: 选中某个人的姓名时,可对此人的相应数据进行删除,并自动调整后续条目的编号。
(二)其它要求:- 只能使用C++语言,源程序要有适当的注释,使程序容易阅读
- 至少采用文本菜单界面(如果能采用图形菜单界面更好)
- 建议使用结构和链表等数据结构
- 学生可自动增加新功能模块(视情况可另外加分)
1.功能介绍
V0[通讯录管理系统]–>V(int main)
V –>A(选择0至6)
A –>B[1.查看联系人]
A –>D[2.添加联系人]
A –>E[3.拨号]
A –>F[4.修改]
A –>G[5.删除]
A –>H[6.history通话记录]
A –>I[0.退出]
B –>1(void Show_Link)
D –>D1(void Add_Link)
E –>E1(void Call_Link)
F –>F2(void Edi_Link)
G –>G1(void Del_Link)
H –>H1(void history)
I –>I1(void Log_Out)
D1 –>a(姓名 手机号 邮箱)
D1 –>c(选择0至3分类)
D1 –>d2{是否继续添加?}
d2 –>|yes|d21(void Add_Link)
d2 –>|no|d22(int main)
c –>c1(1.个人类)
c –>c2(2.办公类)
c –>c3(3.商务类)
c –>c0(0.返回)
F2 –>F1(选择0至4)
F1 –>f1(1.修改姓名)
F1 –>f2(2.修改手机号)
F1 –>f3(3.修改分类)
F1 –>f4(4.修改邮箱)
F1 –>f0(0.返回)
- 提示:退出时务必按 0.退出 否则操作数据不会保存到txt
2.关键功能实现原理
打字机效果
把字符串赋值给字符数组,字符逐一输出。在两个字符输出中间用Sleep()
函数延迟时间。
示例:
#include<iostream>
#include<windows.h>
using namespace std;
int main()
{
string ch = {\'H\',\'U\',\'G\',\'B\',\'O\',\'Y\'};
for(int i = 0; i < ch.length() ; i++)
{
cout<<ch[i];
Sleep(500);//毫秒
}
return 0;
}
拨号音效
调用Beep()
系统函数发声,可以修改频率HZ和延时。
~~网上搜到有人用这个写了一首《天空之城》https://www.cnblogs.com/zhcs/p/6832228.html?utm_source=itdadao&utm_medium=referral ~~
示例:
#include<stdio.h>
#include<windows.h>
int main()
{
float time_s[13]={261.6,293.7,349.2,493.9,392,440,392,293.7,329.6,392,293.7,261.6,0};//持续时间
int hz[13]={500,500,500,700,500,500,500,500,500,500,500,500,1000};//赫兹频率
int i=0;
while(1)
{
while(time_s[i]!=0)
{
// Beep函数是系统函数,驱动PC-Speaker发声的。
Beep(time_s[i],hz[i]);
i++;
}
i=0;
} return 0;
}
打字机和音效合并-->原码对应函数:
void AddressBook::pout(string str,int t,int music)//str:字符串t:间隔的时间music:是否播放音乐
{
float hz[11]= {261.6,293.7,349.2,493.9,392,440,392,293.7,329.6,392,293.7}; //beep频率
int time_s[11]= {500,500,500,700,500,500,500,500,500,500,500}; //beep延时
for(int i=0; i<str.length(); i++)
{
if( music == 1 )//限定
{
Beep(hz[i],time_s[i]);
}
cout<<str[i];
Sleep(t);
}
return;
}
从TXT文件读数据到链表
在网上搜了很多教程,实现过程比较繁琐。二进制存储什么的,还要考虑字符分割问题。
下面的思路是小编很久才想出来的比较简单直接 可能有投机取巧之嫌但效果是真香,效果很好。
思路:
1.
在主函数`int main()`里
程序运行前:
把txt全部读入链表
程序运行后:
以 覆盖 的方式重新写入txt---这样在调用需要读取txt的函数时就不用来回读写了,也省去了删除和修改功能无法在txt实现的尴尬
2.
用`getline()`函数按行读取数据,替代常规的读取。存入变量时,每个变量占一行;
读取时按行读取后赋值给节点里的单个变量
3.原码
C++课程设计 通讯录管理系统
#include <iostream>
#include <cstring>
#include <cassert>//按行读取
#include <fstream>//读写文件
#include <iomanip>
#include <windows.h>//打字机效果
#include <stdlib.h>
using namespace std;
class person
{
protected:
char name[60]; //姓名
char telnb[20]; //电话
char type[60]; //职业类型
char email[60]; //邮箱
int id; //编号
person *Mynext; //指向下一个对象
public:
person(); //初始化变量
person(char pname[],char ptelnb[],char ptype[],char pemail[],int pid);
person(char pname[],char ptelnb[],char ptype[],char pemail[],int pid,person *next);
char *getname();
char *gettelnb();
char *gettype();
char *getemail();
int getid();
person *getnext();
void setnext(person *next);
void updatid();//id自减
};
person::person()
{
strcpy(name,"");
strcpy(telnb,"");
strcpy(type,"");
strcpy(email,"");
Mynext = NULL;
id = 0;
}
person::person(char pname[],char ptelnb[],char ptype[],char pemail[],int pid)
{
strcpy(name,pname);
strcpy(telnb,ptelnb);
strcpy(type,ptype);
strcpy(email,pemail);
Mynext = NULL;
id = pid;
}
person::person(char pname[],char ptelnb[],char ptype[],char pemail[],int pid,person *next)
{
strcpy(name,pname);
strcpy(telnb,ptelnb);
strcpy(type,ptype);
strcpy(email,pemail);
Mynext = next;
id = pid;
}
char *person::getname()
{
return name;
}
char *person::gettelnb()
{
return telnb;
}
char *person::gettype()
{
return type;
}
char *person::getemail()
{
return email;
}
person *person::getnext()
{
return Mynext;
}
void person::setnext(person *next)
{
Mynext = next;
}
int person::getid()
{
return id;
}
void person::updatid()
{
//cout<<"自减函数已经被调用!"<<endl;
//cout<<id<<endl;
id = id - 1;
//cout<<id<<endl;
}
class AddressBook
{
private:
person *myfirst;
public:
AddressBook();//初始化
AddressBook(char npname[],char nptelnb[],char nptype[],char npemail[],int npid);//创建对象
~AddressBook();
void Show_Link();//查看
void Add_Link();//添加
void Call_Link();//拨号
void Edi_Link();//修改
void Del_Link();//删除
void Log_Out();//退出
void output(char seltype[60]);//按类打印
//void pout(string str,int t);//打字机效果
void pout(string str,int t,int music);//打字机效果
void outall();//打印当前所有数据
void history();//查看通话记录
void read_txt();//从txt文件读入数据
void write_txt();//把数据写回txt文件
};
AddressBook::AddressBook()
{
myfirst = NULL;
}
AddressBook::AddressBook(char npname[],char nptelnb[],char nptype[],char npemail[],int npid)
{
myfirst = new person(npname,nptelnb,nptype,npemail,npid);
}
AddressBook::~AddressBook()
{
person *next = myfirst,*temp;
while(next != NULL)
{
temp = next;
next = next->getnext();
delete temp;
}
myfirst = NULL;
}
void AddressBook::read_txt()//从txt文件读入数据
{
int i = 0;
int rid = 0;//ID
char rname[60],rtelnb[20],rtype[60],remail[60];
ifstream read("AddressBook_data.txt");
string line;
while(getline(read,line))
{
i++;
if(i % 4 == 1)//第一行为姓名
{
strcpy(rname,line.c_str());//string类型不能直接赋值给char,要用c_str()转换一下
}
if(i % 4 == 2)//第二行为手机号
{
strcpy(rtelnb,line.c_str());
}
if(i % 4 == 3)//第三行为分类
{
strcpy(rtype,line.c_str());
}
if(i % 4 == 0)//第四行为E-mail
{
rid++;
strcpy(remail,line.c_str());
//读到完整的一组数据,开始赋值给链表
person *p = myfirst;
if(p == NULL)
{
myfirst = new person(rname,rtelnb,rtype,remail,rid);
}
else
{
while(p->getnext() != NULL)
{
p = p->getnext();
}
p -> setnext(new person(rname,rtelnb,rtype,remail,rid,p->getnext())) ;
}
}
}
}
void AddressBook::outall()
{
int i=0;
person *head = myfirst;
if(head == NULL)
{
cout<<"[目前暂无数据]"<<endl;
cout<<endl;
return;
}
cout<<setw(10)<<"ID"<<setw(20)<<"姓名"<<setw(20)<<"电话"<<setw(20)<<"分类"<<setw(20)<<"E-mail"<<endl;
cout<<"______________________________________________________________________________"<<endl;
while(head)
{
i++;
cout<<setw(10)<<head->getid()<<setw(20)<<head->getname()<<setw(20)<<head->gettelnb()<<setw(20)<<head->gettype()<<setw(20)<<head->getemail()<<endl;
head = head -> getnext();
}
cout<<"____________"<<endl;
cout<<"总计"<<"-"<<i<<"-"<<"人"<<endl;
cout<<endl;
return;
}
void AddressBook::Add_Link()
{
outall();//输出所有数据
int adid,tpcode;
char adname[60],adtelnb[20],adtype[60],ademail[60],flag[5];
strcpy(flag,"y\0");
while(strcmp(flag,"y\0") == 0)
{
//统计数据,给新添加数据编排序的ID
int i = 0;
ifstream in("AddressBook_data.txt");
string aline;
while(getline(in,aline))
{
i++;
if(i == 60)//四行数据为一个人
{
cout<<"储存空间已满!"<<endl;
return;
}
}
//开始添加
person *p = myfirst;
person *rpeat = myfirst;//判断录入是否重复
cout<<"联系人姓名:"<<endl;
cin>>adname;
cout<<"电话:"<<endl;
cin>>adtelnb;
while(rpeat)
{
if(strcmp(adname,rpeat->getname()) == 0 || strcmp(adtelnb,rpeat->gettelnb()) == 0)
{
cout<<"联系人Name:"<<adname<<"/Tel:"<<adtelnb<<"已存在!"<<endl;
return;
}
rpeat = rpeat -> getnext();
}
while(1)
{
cout<<"选择分类[1]办公类[2]个人类[3]商务类:"<<endl;
cin>>tpcode;
if(tpcode > 3 || tpcode < 1)
{
cout<<"输入错误!重新输入..."<<endl;
continue;
}
switch(tpcode)
{
case 1:
strcpy(adtype,"办公类");
break;
case 2:
strcpy(adtype,"个人类");
break;
case 3:
strcpy(adtype,"商务类");
break;
}
break;
}
cout<<"E-mail:"<<endl;
cin>>ademail;
adid = i/4 + 1;
if(p == NULL)
{
myfirst = new person(adname,adtelnb,adtype,ademail,adid);
}
else
{
while(p->getnext() != NULL)
{
p = p->getnext();
}
p -> setnext(new person(adname,adtelnb,adtype,ademail,adid,p->getnext())) ;
}
//保存
//person *psave = myfirst;
std::ofstream fout("AddressBook_data.txt",ios::app);//在文件末尾追加
fout<<adname<<"\n"<<adtelnb<<"\n"<<adtype<<"\n"<<ademail<<"\n";
//psave = psave->getnext();
/*while(psave)
{
fout<<psave->getname()<<"\n"<<psave->gettelnb()<<"\n"<<psave->gettype()<<"\n"<<psave->getemail()<<"\n";
psave = psave->getnext();
}*/
fout.close();
cout<<"保存成功!"<<endl;
cout<<"是【y】否【n】继续添加联系人?"<<endl;
cin>>flag;
}
}
void AddressBook::output(char seltype[60])
{
person *head;
head = myfirst;
int i = 0;
cout<<setw(10)<<"ID"<<setw(20)<<"姓名"<<setw(20)<<"电话"<<setw(20)<<"分类"<<setw(20)<<"E-mail"<<endl;
cout<<"______________________________________________________________________________"<<endl;
cout<<endl;
while(head)
{
if(strcmp(head->gettype(), seltype)==0)
{
cout<<setw(10)<<head->getid()<<setw(20)<<head->getname()<<setw(20)<<head->gettelnb()<<setw(20)<<head->gettype()<<setw(20)<<head->getemail()<<endl;
//cout<<head->getid()<<head->getname()<<head->gettelnb()<<head->gettype()<<head->getemail()<<endl;
i = i+1;
}
head = head -> getnext();
}
if(i == 0)
{
cout<<seltype<<"暂无数据!"<<endl;
}
else
{
cout<<"__________"<<endl;
cout<<seltype<<"-"<<i<<"-"<<"人"<<endl;
}
}
void AddressBook::Show_Link()
{
while(1)
{
//分类菜单
cout<<" +-----------------------------------+"<<endl;
cout<<" | [菜单] |"<<endl;
cout<<" | |"<<endl;
cout<<" | - 1.办公类 |"<<endl;
cout<<" | - 2.个人类 |"<<endl;
cout<<" | - 3.商务类 |"<<endl;
cout<<" | - 0.退出 |"<<endl;
cout<<" +-----------------------------------+"<<endl;
int i;
char stype[60];
cout<<".";
cin>>i;
switch(i)
{
case 1:
strcpy(stype,"办公类");
output(stype);
break;
case 2:
strcpy(stype,"个人类");
output(stype);
break;
case 3:
strcpy(stype,"商务类");
output(stype);
break;
case(0):
return;
default:
cout<<"输入有误!请重新输入..."<<endl;
continue;
}
}
}
void AddressBook::pout(string str,int t,int music)//str:字符串t:间隔的时间music:是否播放音乐
{
float hz[11]= {261.6,293.7,349.2,493.9,392,440,392,293.7,329.6,392,293.7}; //beep频率
int time_s[11]= {500,500,500,700,500,500,500,500,500,500,500}; //beep延时
for(int i=0; i<str.length(); i++)
{
if( music == 1 )//限定
{
Beep(hz[i],time_s[i]);
}
cout<<str[i];
Sleep(t);
}
return;
}
void AddressBook::Call_Link()
{
outall();//显示所有联系人及编号
int cid;
cout<<"请输入ID:"<<endl;
cin>>cid;
if(cid>15||cid<1)
{
cout<<"输入错误!"<<endl;
return;
}
person *head;
head = myfirst;
while(head)
{
if(head->getid() == cid)
{
char nb[20],w1[200],w2[200];
//system("cls");
system("color 1F");
strcpy(nb,head->gettelnb());//获得ID对应的号码
strcpy(w1,"您所拨打的电话正在通话中,请稍后在拨...");
strcpy(w2,"Sorry! The number you dialed is busy now,please redial later...");
cout<<"已选择联系人"<<head->getname()<<endl;
cout<<"正在拨号..."<<endl;
pout(nb,500,1);
//system("cls");
cout<<endl;
pout(w1,50,0);
cout<<endl;
pout(w2,50,0);
cout<<endl;
//system("cls");
system("color 0F");
//获取当前时间
time_t t = time(0);
char tim[64];
strftime( tim, sizeof(tim), "%Y年-%m月-%d日 %X ",localtime(&t) );
//puts( tim );
//写入通话记录
std::ofstream fout("CallLog.txt",ios::app);//在文件末尾追加
fout<<tim<<"呼叫"<<head->gettelnb()<<"("<<head->getname()<<")"<< "\n";
fout.close();
break;
}
head = head -> getnext();
}
return;
}
void AddressBook::Edi_Link()
{
char ename[60];
outall();//输出所有联系人
cout<<"请输入要编辑的联系人的姓名:"<<endl;
cin>>ename;
person *head = myfirst;
int flag = 0;
while(head)
{
if(flag == 2)//修改完成已无需再遍历
{
break;
}
if(strcmp(head->getname(), ename)==0)
{
cout<<"Old-Data:"<<endl;
cout<<setw(10)<<head->getid()<<setw(20)<<head->getname()<<setw(20)<<head->gettelnb()<<setw(20)<<head->gettype()<<setw(20)<<head->getemail()<<endl;
while(1)
{
int i;
char enew[60];
cout<<" +-----------------------------------+"<<endl;
cout<<" | [请选择您要修改的内容/退出] |"<<endl;
cout<<" | |"<<endl;
cout<<" | - 1.姓名 |"<<endl;
cout<<" | - 2.手机号 |"<<endl;
cout<<" | - 3.分类 |"<<endl;
cout<<" | - 4.E-mail |"<<endl;
cout<<" | - 0.退出 |"<<endl;
cout<<" +-----------------------------------+"<<endl;
cout<<".";
cin>>i;
if(i > 4 || i < 0)
{
cout<<"输入错误!重新输入..."<<endl;
continue;
}
if(i == 0)
{
break;
}
switch(i)
{
case 1:
cout<<"姓名修改为:"<<endl;
cin>>enew;
strcpy(head->getname(),enew);
break;
case 2:
cout<<"新手机号:"<<endl;
cin>>enew;
strcpy(head->gettelnb(),enew);
break;
case 3:
cout<<"新分类:"<<endl;
cin>>enew;
strcpy(head->gettype(),enew);
break;
case 4:
cout<<"新E-mail:"<<endl;
cin>>enew;
strcpy(head->getemail(),enew);
break;
}
//当修改的为第一个人时
if(flag == 0)
{
myfirst = head;
}
flag = 2;//此状态代表修改操作完成
}
}
else
{
flag = 1;//代表head已经不是第一个节点了
head = head -> getnext();
}
}
if(flag != 2)
{
cout<<"你还未添加该联系人!"<<endl;
}
else
{
cout<<"New-Data:"<<endl;
cout<<setw(10)<<head->getid()<<setw(20)<<head->getname()<<setw(20)<<head->gettelnb()<<setw(20)<<head->gettype()<<setw(20)<<head->getemail()<<endl;
cout<<"__________"<<endl;
cout<<ename<<"修改成功!"<<endl;
}
return;
}
void AddressBook::history()//查看通话记录
{
int i;
ifstream in("CallLog.txt");
string line;
cout<<"______________________|通话记录|______________________"<<endl;
while(getline(in,line))
{
i++;
cout<<line<<endl;
}
cout<<"____________"<<endl;
cout<<"总计"<<"-"<<i<<"-"<<"条通话记录。"<<endl;
cout<<endl;
}
void AddressBook::Del_Link()
{
char dname[60];
outall();//输出所有联系人
cout<<"请输入要拉黑的联系人的姓名:"<<endl;
cin>>dname;
person *head = myfirst;
person *fhead = myfirst;//fhead用于一会指代head的前一个
int flag = 0;
while(head)
{
if(strcmp(head->getname(), dname)==0)
{
cout<<setw(10)<<head->getid()<<setw(20)<<head->getname()<<setw(20)<<head->gettelnb()<<setw(20)<<head->gettype()<<setw(20)<<head->getemail()<<endl;
fhead->setnext(head->getnext());//让head的前一个节点指向head的后一个节点;
head = NULL;
fhead = fhead->getnext();//从fhead开始ID自减一
while(fhead)
{
//cout<<"进入循环-自减"<<endl;
fhead->updatid();
fhead = fhead->getnext();
}
//当删除的为第一个联系人时
if(flag == 0)
{
myfirst = myfirst -> getnext();
cout<<"__________"<<endl;
cout<<dname<<"已被拉黑!"<<endl;
return;
}
}
else
{
flag = 1;
fhead = head;
head = head -> getnext();
}
}
if(flag == 0)
{
cout<<"暂无数据!"<<endl;
}
else
{
cout<<"__________"<<endl;
cout<<dname<<"已被拉黑!"<<endl;
}
return;
}
void AddressBook::write_txt()
{
person *p = myfirst;
std::ofstream write("AddressBook_data.txt");//以覆盖写的方式
while(p)
{
write<<p->getname()<<"\n"<<p->gettelnb()<<"\n"<<p->gettype()<<"\n"<<p->getemail()<<"\n";
p = p->getnext();
}
write.close();
//cout<<"保存成功!"<<endl;
}
int main()
{
AddressBook call;
cout<<setiosflags(ios::left);//输出左对齐
call.read_txt();//从文件读入数据
while(1)
{
//主菜单
cout<<" +--------------------------------------------------+"<<endl;
cout<<" | [通讯录管理系统] |"<<endl;
cout<<" | |"<<endl;
cout<<" | * 1.查看联系人 |"<<endl;
cout<<" | * 2.添加联系人 |"<<endl;
cout<<" | * 3.拨号 |"<<endl;
cout<<" | * 4.修改 |"<<endl;
cout<<" | * 5.删除 |"<<endl;
cout<<" | * 6.history |"<<endl;
cout<<" | * 0.退出 |"<<endl;
cout<<" +--------------------------------------------------+"<<endl;
int i;
cout<<".";
cin>>i;
switch(i)
{
case(1):
call.Show_Link();
break;
case(2):
call.Add_Link();
break;
case(3):
call.Call_Link();
break;
case(4):
call.Edi_Link();
break;
case(5):
call.Del_Link();
break;
case(6):
call.history();
break;
case(0):
//保存数据
call.write_txt();
return 0;
default:
cout<<"输入有误!请重新输入..."<<endl;
continue;
}
}
return 0;
}