C++课程设计学生通讯管理系统.docx
《C++课程设计学生通讯管理系统.docx》由会员分享,可在线阅读,更多相关《C++课程设计学生通讯管理系统.docx(72页珍藏版)》请在冰点文库上搜索。
C++课程设计学生通讯管理系统
课程设计报告
一课程设计目的及要求
学生通讯系统
学生通信录信息包括:
姓名、学号、年龄、性别、家庭住址、联系电话、寝室号等信息。
现要求编写程序来完成如下功能:
●学生通信录信息的输入
●学生的通信录信息删除和修改
●学生的通信录信息查询和统计功能
●学生的通信录信息输出显示。
二课程设计具体实现
1.总体设计
学生通讯管理系统
只修改学号
管理员登陆系统
普通用户登陆系统
删除信息
退出系统
密码校验
增加信息
查找信息
修改信息
修改密码
全部修改
只修改姓名
2.详细设计
在进行系统的各项功能介绍之前,有必要先说一下我所选的课程项设计的主要思路。
这个系统的核心部分就是结构体链表,它贯穿整个程序。
一切数据的增、删、查、改都要以它为支撑。
整个程序其实就是在操作一张很大的链表。
我在15周时就已经开始考虑课程设计题目,当时是想先做一个关于面向过程的课题,立马就考虑的先用结构体链表做为数据的容器。
而且已经做成型了。
后来老师您把题目给改了,要求都用面向对象做,我是考虑过用vector或者是list来做数据的容器的,但想想程序几经初成型,就不改变容器了,就直接把类的对象做为结构体的数据部分,程序当然也有较大改动,但基本框架是没有变的。
先来说链表的构造,在主菜单下选择功能之前,链表就已经认构造完毕,程序按行读取文本文件,每读一行,便对其进行分割。
分割出来的字符串为学生类对象对应的每一项信息。
在分割字符串时,我按字符‘@’进行分割(当然,在数据存储时也是按行存储,且每项信息以‘@’分开),其关键代码如下:
voidread_info(){//读取文件
head=NULL;
Students;//构造学生类对象
ifstreamin("student_info.txt");
stringread;
intno;
while(getline(in,read)){//按行读取
no=0;
inti;
while(read.find_first_of("@")!
=-1){
stringtemp;
i=read.find_first_of("@");
temp=read.substr(0,i);
if(no==0){
s.name=temp;//赋予姓名
}
if(no==1){
s.tel=temp;//赋予电话
}
if(no==2){
s.xuehao=temp;//赋予学号
}
if(no==3){
s.sex=temp;//赋予性别
}
if(no==4){
s.banji=temp;//赋予班级
}
no++;
read=read.substr(i+1);
}
s.dizhi=read;//赋予地址
if(s.name.size()>0&&s.xuehao.size()>0){//判断学号与姓名是否为空
insert_into_list(s);//插入链表
}
}
in.close();
}
voidinsert_into_list(Studentst){
structlist*curr,*ne;
curr=(structlist*)new(structlist);//申请空间
curr->student=st;
ne=head;
if(head==NULL){//如果头指针为空插入第一条数据
head=curr;
curr->next=NULL;
}
else
{while(ne->next!
=NULL)ne=ne->next;//遍历结构体,直到尾
ne->next=curr;
curr->next=NULL;
}
}
Txt文件才的储存形式如下:
所以,能正确的读取所有数据在于字符串的分割,当然用此种方法读到的数据全是字符串,只是本系统为学生通讯系统,并不需要其他类型的数据,如有必要,字符串也可以转化。
就这样,当文件按行读取完毕时,链表中的每个结构体都包含有一个不同的学生类对象,至此,链表已初始化完毕。
在程序接下来的运行过程中,对数据的操作就是直接操作链表的节点。
下面对系统功能进行介绍:
i.
登陆系统:
通过欢迎界面后,将进入登陆方式选择界面,如图:
ii.若选择以普通用户身份登录系统,会出现以下界面:
普通用户的功能包括:
1.增加数据;2.查询数据;3.浏览数据;4.数据统计
1)增加数据功能的界面如下:
用户根据系统提示,对单个学生信息进行逐项输入,按回车键结束输入。
除姓名与学号外,其他信息只要直接按回车键就可以跳过输入,系统将保存为空。
对信息的输入还要有一定的规范性,如学号与电话为纯数字;姓名长度最多只有四个字;性别若有,只能为男或女,系统会自动对输入的信息进行校验,包括规范性校验与数据是否重复校验。
若无法通过校验,数据不会保存。
其关键代码如下:
●规范性校验:
boolStudent:
:
check_tel_xuehao(){//学号与电话检查函数
if(xuehao.size()==0){//如果学号为空,返回false
returnfalse;
}
if(!
check_string(xuehao)||!
check_string(tel)){//如果学号中处在数字以外的字符,返回false
cout<<"学号或电话输入有误!
"<returnfalse;
}
returntrue;
}
boolcheck_string(stringa){//检测字符串中是否只包含数字
charb;
for(inti=0;i{
b=a.at(i);
if(b>'9'||b<'0')returnfalse;
}
returntrue;
}
boolStudent:
:
check_name_other(){//姓名检测函数
if(name.size()==0||name.size()>10){//如果姓名为空或者姓名长度过长
cout<<"姓名输入有误!
"<returnfalse;
}
else
returntrue;
}
boolStudent:
:
check_sex(){//此为性别检测函数,性别可以为空,可以为男,也可以为女,但不可以为其他字符,或者返回false
if(sex.size()>2||(sex.size()>0&&(pare("男")&&pare("女")))){
cout<<"性别输入错误!
"<returnfalse;
}
else
returntrue;
}
●数据是否重复校验代码如下:
structlist*User:
:
check_repeat(stringkey,inttype){//此函数也可用于数据查询,key代表要查询的关键字。
type=1表示按姓名查找,type=2表示按学号查找
structlist*ne;
ne=head;//注意这个head不能空,要初始化
intcom;
while(ne!
=NULL){//遍历列表
com=0;
if((type==1||type==0)&&!
pare(ne->student.name))com++;//对比姓名
if((type==2||type==0)&&!
pare(ne->student.xuehao))com++;//对比学号
if(com>0){//若m>0,证明原有数据中含有被检数据,或者的话,将会返回NULL。
returnne;
}
if(ne->next==NULL)break;
ne=ne->next;
}
cout<returnNULL;
}
2)数据查询功能界面如下:
进行数据查询时,可输入任何字符,只要学生信息中任何一项包含输入的关键字,该信息都会被显示出来,如上图,分别输入了“女”,“B105”,进行查询,结果信息都完整的显示了出来,以下是进行信息查询的关键代码:
voidUser:
:
find_info(){
stringkey;//关键字
structlist*ne;//结构体指针
intfind;//找到的数据量
intcom;
chars;//选择
FIND:
system("cls");
cout<<"请输入要查询的关键字:
";
cin>>key;
ne=head;//注意这个head不能空,要初始化
find=0;
show_table_head();
while(ne!
=NULL){//遍历链表,指针每移一位都要调出指针所指的学生类,然后进行每项数据的对比
com=0;
if(check_string(ne->student.name,key))com++;//如果相关信息内包含关键字,com++,下同
if(check_string(ne->student.banji,key))com++;
if(check_string(ne->student.dizhi,key))com++;
if(check_string(ne->student.sex,key))com++;
if(check_string(ne->student.tel,key))com++;
if(check_string(ne->student.xuehao,key))com++;
if(com>0){//即至少有一项匹配,则横排显示
find++;
ne->student.show_info(find);
}
if(ne->next==NULL)break;//指针指向尾部,退出
ne=ne->next;
}
cout<<'\n'<<"找到"<\n"<cout<<"是否继续查找(y/n)?
";
cin>>s;
if(s=='y')gotoFIND;
}
3)数据浏览功能:
此功能可以显示所有存入的数据,界面如下:
在数据显示时,主要用的技术就是对结构体链表进行遍历,指针指向结构体的学生类对象,然后调用该类的自身数据显示函数,这样就可显示所有数据。
关键代码如下:
voidUser:
:
show_all(){//显示所有信息
system("cls");//清屏
structlist*ne;//链表指针
ne=head;//指向头指针
inti=1;
show_table_head();//显示表头
while(ne!
=NULL)//遍历链表
{
ne->student.show_info(i);//横排显示学生信息
i++;
if(ne->next==NULL)break;//如果到达尾指针,退出
ne=ne->next;//指针指向下一位
}
system("pause");
}
voidStudent:
:
show_info(inti){//横行显示信息
cout<cout<cout<cout<cout<cout<cout<}
4)数据统计功能:
数据可以按照三种方式进行统计,即按性别、按班级,按住址。
计时,对应条目相等的数据会显示在同体列表下,并会显示数据总数。
一下截图是按住址统计的部分结果:
以下是关键代码:
voidUser:
:
tongji_info(){
TONGJI:
system("cls");
chars;
cout<<"选择您可以统计方式:
\n\t1.按性别统计\n\t2.按住址统计\n\t3.按班级统计\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n请选择:
";
cin>>s;
if(s=='1'){
find_info
(1);
}
elseif(s=='2'){
find_info
(2);
}
elseif(s=='3'){
find_info(3);
}
else{
err_show();
}
cout<<"\n继续还是回主菜单[1_or_2]:
";
cin>>s;
if(s=='1')gotoTONGJI;
}
voidUser:
:
find_info(inttype){
tyhead=NULL;
structlist*ne;//结构体list指针
ne=head;//注意这个head不能空,要初始化
while(ne!
=NULL){//遍历链表,指针每移一位都要调出指针所指的学生类,然后进行每项数据的对比
stringkey;
if(type==1){
key=ne->student.sex;
}
elseif(type==2){
key=ne->student.dizhi;
}
else{
key=ne->student.banji;
}
if(!
contain(key)){
add(key);
}
if(ne->next==NULL)break;//指针指向尾部,退出
ne=ne->next;
}
structtypelist*ne2;
ne2=tyhead;
system("cls");
while(ne2!
=NULL){//遍历链表typelist
show_table_head();//表头显示函数
stringkey;
key=ne2->atype;
if(key.size()==0){
key="其他";
cout<"<}
else
{
cout<"<}
if(ne2->next==NULL)break;//指针指向尾部,退出
ne2=ne2->next;
cout<}
}
intsee_list(inttype,stringkey,boolnullinfo){//type条目类型,key表示此条目下的数据,此函数用于返回某项包含相同数据的数目
structlist*ne;//结构体list指针
ne=head;//注意这个head不能空,要初始化
intfind=0;
while(ne!
=NULL){//遍历链表,指针每移一位都要调出指针所指的学生类,然后进行每项数据的对比
inti=0;
if(type==1){
if(!
ne->pare(key)||((ne->student.sex.size())==0&&nullinfo))//检查性别是否匹配
{
find++;
ne->student.show_info(find);
}
}
elseif(type==2){
if(!
ne->pare(key)||((ne->student.dizhi.size()==0)&&nullinfo))//检查地址是否匹配
{
find++;
ne->student.show_info(find);
}
}
else{
if(!
ne->pare(key)||((ne->student.banji.size()==0)&&nullinfo))//检查班级是否匹配
{
find++;
ne->student.show_info(find);
}
}
if(ne->next==NULL)break;//指针指向尾部,退出
ne=ne->next;
}
returnfind;
}
voidadd(stringkey){
structtypelist*curr,*ne;//结构体typelist指针
curr=(structtypelist*)new(structtypelist);//申请空间
curr->atype=key;
ne=tyhead;//ne指向头指针,如果初始化数据时,文件中有数据,此时头指针一定不为空
if(tyhead==NULL){//若链表为空
tyhead=curr;//头指针指向current
curr->next=NULL;//current为第一数据,表头的next指针为空
}
else//如果头指针不为空
{
while(ne->next!
=NULL)//遍历链表,直到ne指针指向尾部
{
ne=ne->next;
}
ne->next=curr;//尾指针的next指针指向current,此时current已插入链表
curr->next=NULL;//current位于链表尾部,其next指针当为NULL
}
}
boolcontain(stringkey){
structtypelist*ne;//结构体指针typelist
ne=tyhead;
while(ne!
=NULL){//遍历链表
if(!
ne->pare(key))returntrue;
if(ne->next==NULL)break;//指针指向尾部,退出
ne=ne->next;
}
returnfalse;
}
iii.若选择以管理员身份登录系统
则会出现管理员界面:
当正确输入用户名与密码后,方可进行功能操作。
其中,增加数据、查询数据、浏览数据与数据统计功能与普通用户的代码实现相同,因为管理员类继承与普通用户类,所以此函数直接继承。
在此不多作描述。
下面介绍删除数据与修改数据功能。
1)数据修改
进行数据修改时,需要先输入正确的学号或姓名,在找到数据后,可按提示进行修改,次系统有一个方便的地放就是若不想修改某项数据,可直接按回车键,如下图。
关键代码实现如下:
voidManager:
:
edit_info(){
stringkey;//关键字
chars;
structlist*xiu;
EDIT:
system("cls");
Studenttemp;//用于做缓存的学生类对象
cout<<"\n请输入要修改的条目关键字:
";
cin.ignore(1024,'\n');
getline(cin,key);
if(((xiu=check_repeat(key,1))!
=NULL)||((xiu=check_repeat(key,2))!
=NULL)){
boolf;
xiu->student.show_info();//以下为数据录入
cout<<"\n请输入新数据,若不必修改,请直接按回车键:
\n";
cout<<"请输入姓名:
";
getline(cin,temp.name);
cout<<"请输入电话:
";
getline(cin,temp.tel);
cout<<"请输入学号:
";
getline(cin,temp.xuehao);
cout<<"请输入性别:
";
getline(cin,temp.sex);
cout<<"请输入班级:
";
getline(cin,temp.banji);
cout<<"请输入住址:
";
getline(cin,temp.dizhi);
//以下为数据检查
if(temp.name.size()>0){//若重输了姓名
if(check_repeat(temp.name,1)!
=NULL)gotoWRONG;//检查未通过
}elsetemp.name=xiu->student.name;
if(temp.xuehao.size()>0){
if(check_repeat(temp.xuehao,1)!
=NULL)gotoWRONG;
}elsetemp.xuehao=xiu->student.xuehao;
if(temp.sex.size()==0){
temp.sex=xiu->student.sex;
}
if(temp.tel.size()==0){
temp.tel=xiu->student.tel;
}
if(temp.banji.size()==0){
temp.banji=xiu->student.banji;
}
if(temp.dizhi.size()==0){
temp.dizhi=xiu->student.dizhi;
}
if(temp.check_name_other()&&(temp.check_sex()&&temp.check_tel_xuehao())){//数据规范性检查
xiu->student=temp;//对指针下数据进行修改
cout<<"\n修改成功!
"<edit_flag=true;
cout<<"\n修改后的数据为:
"<xiu->student.show_info();
gotoASK;
}
elsegotoWRONG;
}
else{
err_show();
cout<<"无效的数据,是否继续(y/n)?
"
cin>>s;
if(s=='y'){
gotoEDIT;
}
gotoASK;
}
WRONG:
err_show();
cout<<"\n错误!
未修改数据!
"<ASK:
cout<<"\n继续还是回主菜单[1_or_2]:
";
cin>>s;
if(s=='1')gotoEDIT;
}
2)数据删除
删除数据需要先输入学号或姓名,数据的删除本质上就是链表节点的删除。
截图如下:
关键代码如下:
intManager:
:
del_info(){//删除信息
stringm;//删除的关键字
structlist*la,*ne;
chars;
DEL:
system("cls");
ne=head;
if(head==NULL){//如果数据为空
err_show();
cout<<"\n空链表!
不可进行下一步操作!
"<gotoASK;
}
cout<<"输入要删除的学号或姓名:
";
cin.ignore(50,'\n');
getline(cin,m);
if(!
pare(head->student.name)||!
pare(head->student.xuehao)){//如果姓名或学号的所对对应的学生对象位于链表头部,则需要改变头指针,头指针指向内容将要删除
head=ne->next;//改变头指针
ne->student.show_info();//显示信息
cout<<"\n确认删除(y/n)?
";
c