C语言 任务八 综合项目设计.docx
《C语言 任务八 综合项目设计.docx》由会员分享,可在线阅读,更多相关《C语言 任务八 综合项目设计.docx(49页珍藏版)》请在冰豆网上搜索。
C语言任务八综合项目设计
任务七综合项目设计
7.1教学目标
1.熟练掌握利用C语言的三种流程结构、结构体和函数来完成目标任务
2.掌握和利用C语言来编写大型实用程序的技巧和方法
3.掌握名片管理系统的程序设计过程
7.2工作任务
利用所学过的知识,进行综合项目设计,设计一个名片管理程序,能够进行名片添加、名片修改、名片查找、名片删除、名片浏览、名片输出备份。
7.3相关实践知识
7.3.1总体设计
根据工作任务要求,将该任务用模块图描述总体设计如图7-1所示。
图7-1名片管理系统模块图
算法分析:
用户可以根据需要选择不同的功能来对名片进行操作,所以,需要用一个永真循环结合switch….case结构来实现让用户选择的菜单功能。
7.3.2数据初始化模块的设计与实现:
(1)数据结构
在C语言中用结构体来表示一个对象的多个数据项,名片信息我们采用结构体来描述。
除了我们需要使用的联系信息外,为了区分每个名片,同时方便定位名片,我们给每个名片分配一个唯一的编号。
名片编号分配给某一个名片后,该编号就不再分配给任何其它名片,即使改名片被删除,也不再重新分配,这样做的好处是不需要管理编号,只要逐个递增就可以了。
名片信息具体的数据结构如下:
structcard{
intno;/*编号*/
intgroup;/*分组号*/
charname[20];/*姓名*/
charcphone[20];/*手机号*/
charphone[20];/*电话*/
charaddress[100];/*地址*/
charemail[50];/*电子邮件地址*/
charnote[100];/*备注*/
}card;/*声明结构体的同时定义了一个全局变量*/
(2)变量的定义
为了数据能在所有模块中使用,部分变量定义为全局变量,在C语言中全局变量必须放置在main函数以及其它所有函数之外,而且位于main函数代码之前。
在本项目中,定义了如下4个全局变量。
structcard{
intno;
intgroup;
charname[20];
charcphone[20];
charphone[20];
charaddress[100];
charemail[50];
charnote[100];
}card;/*用来临时存放用户输入的一个名片信息*/
FILE*f1p,*f2p,*fdp;/*三个指向存储文件的文件指针*/
(3)数据初始化设计与实现
名片信息是用户从键盘输入,在计算机关机后也能保存名片信息。
所以,用文件来存放所有的名片和名片输出备份,这我们采用txt文本文件存放。
因为名片存放在文件中,不能像在内存中那样用链表来管理。
因此,在编辑名片和删除名片的时候,我们不能在同一个文件中挪动名片。
我们采用两个文件来回“倒”的方式来解决这个问题。
例如,假设现在所有的名片都存储在1.txt中,我们要删除其中的一个名片,那么,我们可以使用一个文件2.txt,然后把1.txt中的名片逐个复制到2.txt中,当遇到要删除的那个名片的时候,跳过该名片,继续复制之后的名片。
然后,我们把2.txt标志为当前正在用的名片存储文件。
(1.txt和2.txt需要我们在系统初始化的时候建立好)
这样的话,会带来另外一个问题,那就是程序用什么来记住1.txt还是2.txt是当前有效文件,用全局变量可以吗?
答案是不行。
为什么不行?
因为当你这一次使用完系统退出后,全局变量也会消亡,那么下一次你重新使用系统的时候就会不知道你的名片库是存放在1.txt还是2.txt中。
所以,我们使用另外建立一个文本文件来保存的解决方案。
我们用direct.txt(系统初始化的时候建立)来保存当前有效文件标识(1或2)和当前最大名片编号。
/*系统初始化*/
if(fdp=fopen("direct.txt","r")==NULL)/*如果direct.txt不存在*/
{if((fdp=fopen("direct.txt","w"))==NULL)/*创建direct.txt*/
{printf("fliecreaterror!
");exit(0);}
else
{fprintf(fdp,"%d\n",1);/*有效文件标识为1*/
fprintf(fdp,"%d\n",0);}/*当前名片编号为0*/
}
fclose(fdp);
if(f1p=fopen("1.txt","r")==NULL)/*如果1.txt不存在*/
{if((f1p=fopen("1.txt","w"))==NULL)/*创建1.txt*/
{printf("fliecreaterror!
");exit(0);}
}
fclose(f1p);
if(f2p=fopen("2.txt","r")==NULL)/*如果2.txt不存在*/
{if((f1p=fopen("2.txt","w"))==NULL)/*创建2.txt*/
{printf("fliecreaterror!
");exit(0);}
}
fclose(f2p);
/*初始化结束*/
7.3.3系统菜单显示模块的设计与实现
(1)画出菜单显示模块流程图
流程图如图7-2所示。
图7-2系统菜单显示流程图
(2)根据流程图编写源码
main()
{
intoption;
charo='y';
/*系统初始化*/
/*初始化结束*/
while(o!
='q'&&o!
='Q')
{
printf("\n\n\n\t**************************************************\n");
printf("\t*欢迎使用名片管理系统!
*\n");
printf("\t**\n");
printf("\t*1.添加新名片*\n");
printf("\t*2.编辑名片*\n");
printf("\t*3.查询名片*\n");
printf("\t*4.删除名片*\n");
printf("\t*5.浏览名片簿*\n");
printf("\t*6.名片输出备份*\n");
printf("\t*7.使用帮助*\n");
printf("\t**************************************************\n\n\n\n");
printf("请输入1-7选择相应的功能选项\n");
scanf("%d",&option);
switch(option)
{
case1:
add_compact();break;/*调用名片添加模块*/
case2:
edit_compact();break;/*调用名片编辑模块*/
case3:
search_compact(0);break;/*调用名片查询模块*/
case4:
delete_compact();break;/*调用名片删除模块*/
case5:
load();break;/*调用名片浏览模块*/
case6:
transfer_compact();break;/*调用名片输出备份模块*/
case7:
introduction_compact();break;/*调用帮助模块*/
}
printf("\t退出请按Q\n");
printf("\t继续请按任意键\n");
o=getchar();
while(o=='\n')
o=getchar();
printf("\n");
}
}
(3)菜单模块运行结果图
模块运行结果如图7-3所示。
图7-3系统菜单模块运行结果图
算法设计:
本程序将设计许多可以重用的函数,例如保存一张名片、打印一张名片、输出一张名片等等。
这些函数可能会被多个功能模块所调用,例如,添加名片需要用到输入名片函数接收一张名片的输入、然后用打印名片函数把刚才输入的结果作为名片的形式输出给用户看,经过用户确认后再用保存名片函数保存结果。
所以,在主函数中,我们可以设计如下一些模块函数,例如:
voidadd_compact(void);完成名片添加任务
voidedit_compact(void);完成名片修改任务
voidsearch_compact(int);完成名片查找任务
voiddelete_compact(void);完成名片删除任务
voidload_compact(void);完成名片浏览任务
voidtransfer_compact(void);完成名片输出备份任务
然后,我们再根据每个模块函数的需要,设计一些具体的功能函数,供他们调用。
这些功能函数可以被多个模块函数调用,提高里代码的重用率。
名片添加任务需要用到的功能:
得到名片输入信息、打印名片供用户确认、保存确认后的名片信息、修改名片总数。
名片修改任务需要用到的功能:
查找用户想要修改的名片、打印名片供用户确认、接收用户编辑的名片信息、在文件中执行名片编辑。
名片查找任务需要用到的功能:
确定当前有效的名片存储文件、查找用户指定条件的名片、打印查找结果名片。
名片删除任务需要用到的功能:
查找用户指定条件待删除的名片、打印查找匹配结果名片、删除名片
名片浏览任务需要用到的功能函数:
确定当前有效的名片存储文件、打印名片
名片输出备份任务需要用到的功能:
确定当前有效的名片存储文件、查找用户指定的备份项目并输出到备份文件。
7.3.4名片添加模块的设计与实现
(1)画出名片添加模块流程图
流程图如图7-4所示。
图7-4名片添加模块流程图
(2)根据流程图编写源码
voidadd_compact(void)
{
chard;
printf("Pleaseinputinformation...\n");
getcard();
/*接收用户从键盘输入的名片信息,并保存在内存中的结构体中*/
printcard(card,1);
/*把内存中的结构体中的信息按照名片的形式输出到屏幕上*/
printf("save?
(Y/N)");
d=getchar();
if(d=='y'||d=='Y')
{
save(filedirectory(),numdirectory());
/*filedirectory()当前有效文件标识存放在direct.txt文件中,该函数会返回
1or2代表当前有效文件是1.txt或者2.txt;numdirectory()代表名片总数的编
号也存放在direct.txt中,该函数返回最后一个名片的编号.*/
directoryedit(filedirectory(),1);
/*directoryedit(int,int)该函数改写direct.txt以改变当前有效文件编号*/
}
}
(3)模块运行结果图
模块运行结果如图7-5所示。
图7-5名片添加模块运行结果图
7.3.5名片修改模块的设计与实现
(1)画出名片修改模块流程图
流程图如图7-6所示。
图7-6名片修改模块流程图
(2)跟据流程图编写源码
voidedit_compact(void)
{
chard=0;
search_compact
(1);
/*调用查找模块,根据用户的要求,查找待编辑名片查找到的时候,该名片也
已经保存于card全局变量中*/
printf("编辑?
(Y/N)\n");
while(d!
='y'&&d!
='Y'&&d!
='n'&&d!
='N')
d=getchar();
if(d=='Y'||d=='y')
{
getcard();/*接收用户编辑后的名片信息*/
printcard(card,1);/*输出编辑后的名片供用户确认*/
printf("确认保存编辑结果?
(Y/N)\n");
d=0;
while(d!
='y'&&d!
='Y'&&d!
='n'&&d!
='N')
d=getchar();
if(d=='Y'||d=='y')
editcard(card.no);/*保存编辑结果到存储文件中*/
}
}
(3)模块运行结果图
模块运行结果如图7-7所示。
图7-7名片修改模块运行结果图
7.3.6名片查询模块的设计与实现
(1)画出名片查询模块流程图
流程图如图7-8所示。
图7-8名片查询模块流程图
(2)根据流程图编写源码
voidsearch_compact(into)
{
intd;
intp,i;
charflag,ch,a,c;
charword[20],word1[20],cellph[20],cellph1[20],telph[20],telph1[20];
intgrp;
printf("请选择查找关键字?
\n");
if(o==0)/*名片查找模式*/
{
printf("N代表name\n");
printf("G代表group\n");
printf("C代表cellphone\n");
printf("P代表phone\n");
printf("请输入您的选择:
(N/G/C/P)\n");
}
elseif(o==1)/*名片编辑模式不包含群组匹配*/
{
printf("N代表name\n");
printf("C代表cellphone\n");
printf("P代表phone\n");
printf("请输入您的选择:
(N/C/P)\n");
}while(a!
='N'&&!
='n'&&a!
='C'&&a!
='c'&&a!
='g'&&a!
='G'&&a!
='p'&&a!
='P')
a=getchar();
d=filedirectory();
if(d==1)
f1p=fopen("1.txt","r");
elseif(d==2)
f1p=fopen("2.txt","r");
if(a=='N'||a=='n')
{
if(f1p!
=NULL)
{
printf("名字:
");//下面接收名字
getchar();
for(i=0;(c=getchar())!
='\n';i++)
word1[i]=c;
word1[i]='\0';
for(i=0;(word[i]=word1[i])!
='\0';i++);
/*空语句,因为赋值操作已经在for的语句2中执行*/
word[i++]='\n';
word[i]='\0';
p=0;
while((ch=fgetc(f1p))!
=EOF)
if(namesearch(word))
/*在当前文件中的名片的name成员中查找和当前字符串有否匹配,有则
return1,并且把该名片存放在全局变量card中,否则,return0*/
{
p++;
printcard(card,0);/*打印找到的名片*/
break;
}
}
elseif(f1p==NULL)
printf("文件不能被打开\n");
if(p==0)
printf("%s不在名片簿中\n",word);
fclose(f1p);
}
elseif(a=='G'||a=='g')
{
if(f1p!
=NULL)
{
printf("1.家庭2.商务3.朋友4.用户\n");
printf("群组:
");
scanf("%d",&grp);
p=0;
while((ch=fgetc(f1p))!
=EOF)
if(groupsearch(grp))//类似上面的namesearch,匹配群组
{
p++;
printcard(card,0);
}
}
elseif(f1p==NULL)
printf("文件打不开\n");
if(p==0)
printf("群组是空的\n");
fclose(f1p);
}
elseif(a=='C'||a=='c')
{
if(f1p!
=NULL)
{
printf("手机号码:
");
getchar();
for(i=0;(c=getchar())!
='\n';i++)
cellph1[i]=c;
cellph1[i]='\0';
for(i=0;(cellph[i]=cellph1[i])!
='\0';i++)
;
cellph[i++]='\n';
cellph[i]='\0';
p=0;
while((ch=fgetc(f1p))!
=EOF)
if(cellsearch(cellph))//类似上面的namesearch,匹配手机号码
{
p++;
printcard(card,0);
break;
}
}
elseif(f1p==NULL)
printf("文件打不开\n");
if(p==0)
printf("%s不在名片簿中\n",cellph);
fclose(f1p);
}
elseif(a=='P'||a=='p')
{
if(f1p!
=NULL)
{
printf("电话号码:
");
getchar();
for(i=0;(c=getchar())!
='\n';i++)
telph1[i]=c;
telph1[i]='\0';
for(i=0;(telph[i]=telph1[i])!
='\0';i++)
;
telph[i++]='\n';
telph[i]='\0';
p=0;
while((ch=fgetc(f1p))!
=EOF)
if(telsearch(telph))//类似上面的namesearch,匹配电话号码
{
p++;
printcard(card,0);
break;
}
}
elseif(f1p==NULL)
printf("文件打不开\n");
if(p==0)
printf("%s不在名片簿中\n",card.phone);
fclose(f1p);
}
}
(3)模块运行结果图
模块运行结果如图7-9所示。
图7-9名片查询模块运行结果图
7.3.7名片删除模块的设计与实现
(1)画出名片删除模块流程图
流程图如图7-10所示。
图7-10名片删除模块流程图
(2)根据流程图编写源码
voiddelete_compact(void)
{
chard=0;
search_compact
(1);
/调用查找模块,根据用户的要求,查找待删除名片
//查找到的时候,该名片也已经保存于card全局变量中
printf("删除?
(Y/N)\n");
while(d!
='y'&&d!
='Y'&&d!
='n'&&d!
='N')
d=getchar();
if(d=='Y'||d=='y')
deletecard(card.no);
//根据查找到的名片编号,删除该名片
}
voiddeletecard(intn)
{
structcardtempcard;
intd;
chartest[50];
if(filedirectory()==1)//判断当前有效文件
{
f1p=fopen("1.txt","r");//当前有效文件只读
f2p=fopen("2.txt","w");//备份文件只写
d=2;
}
elseif(filedirectory()==2)
{
f2p=fopen("1.txt","w");//当前有效文件只读
f1p=fopen("2.txt","r");//备份文件只写
d=1;
}
while(fgets(test,100,f1p)!
=NULL)//当还有名片
{
fscanf(f1p,"%d",&tempcard.no);
fscanf(f1p,"%d",&tempcard.group);
fgetc(f1p);
fgets(tempcard.name,100,f1p);
fgets(tempcard.cphone,100,f1p);
fgets(tempcard.phone,100,f1p);
fgets(tempcard.address,100,f1p);
fgets(tempcard.email,100,f1p);
fgets(tempcard.note,100,f1p);
//读一个名片到tempcard结构体变量中
if(tempcard.no!
=n)//比较编号,是否待删除名片
{//如果不是,则拷贝到备份文件中
fprintf(f2p,"\n");
fprintf(f2p,"%d\n",tempcard.no);
fprintf(f2p,"%d\n",tempcard.group);
fprintf(f2p,"%s",tempcard.name);
fprintf(f2p,"%s",tempcard.cphone);
fprintf(f2p,"%s",tempcard.phone);
fprintf(f2p,"%s",tempcard.address);
fprintf(f2p,"%s",tempcard.email);
fprintf(f2p,"%s",tempcard.note);
}
}
fclose(f1p);
fclose(f2p);
directoryedit(d,0);//改变有效文件标识
}
(3)模块运行结果图
模块运行结果如图7-11所示。
图7-11名片删除模块运行结果图
7.3.8名片浏览模块的设计与实现
(1)画出名片浏览模块流程图
流程图如图7-12所示。
图7-12名片浏览模块流程图
(2)根据流程图编写源码
voidload(void)
{
inti,count,d;
structcardtempcard;
chartest[100];
d=filedirectory();
if(d==1)
f1p=fopen("1.txt","r");
elseif(d==2)
f1p=fopen("2.txt","r");
if(f1p==NULL)
{
printf("文件打不开或者不存在!
\n");
return;
}
while(fgets(test,100,f1p)!
=NULL)//当还有名片
{//从当前有效文件中读取一个名片
fscanf(f1p