项目概况
用C语言创建一个“学生成绩管理系统”,供学生、教师、管理员、超级管理员使用,不同身份登陆者具有不同的功能权限,逐级管理。
问题与分析
主要框架的确立
由于该项目由小组成员3人合作完成,需要每个人独立完成一部分任务,因此初期的分工前应该确立main.c的主要框架及各个功能界面之间的判断与切换。
int main()
{
int id=0,i=-1;
char pw[10];
while(1)
{
while(i == -1) //i的条件判定
{
show_menu();
scanf("%d",&id);
printf("请输入密码:");
scanf("%s",pw);
getchar();
i=find_i(id,pw);
}
if(3 == strlen(pw))
{
change_pw(i,id/10000000);
i=-1;
}
else
{
switch(id/10000000)
{
case 1:i=show_stu(i);break;
case 2:i=-1;show_tea();break;
case 3:i=-1;show_admini();break;
case 4:i=-1;show_s_admini();break;
}
}
}
}
由于一开始没有把框架确定,导致与成员的沟通没有统一:原本是想把i作为一个连接起所有功能的参数来传递(student功能就是通过这种想法实现的),但是小组成员倾向于用无参数与返回值的函数,并通过按键进行功能切换,因此导致一部分功能函数无法共用,降低了效率。
因此,在以后的项目中,提前确立大的框架是很有必要的,也有助于成员思路的共鸣。
输入缓冲区的问题
在使用scanf输入时要关注“\n”是否会对后续功能造成影响,如:
system("clear");
printf("**********解锁管理员**********\n");
printf("请输入要解锁的管理员账号:");
scanf("%d",&id);//此处操作后输入缓冲区内有一个\n
getchar();
i=find_id_adm(id);
if(i == -1)
{
printf("该管理员账号不存在!\n");
}
else if(adm[i].flag >= 3)
{
adm[i].flag=0;
printf("解锁成功!\n");
}
else
{
printf("该管理员账号不需要解锁!\n");
}
back_1();
此处末尾的back_1();是一个功能为按任意键返回的函数。在这个功能函数内,若没有getchar()的操作,程序会在执行完该函数跳转back_1();后不需要按键直接返回主界面。
因为此处会把输入缓冲区内的\n读作back1函数中的接收值,从而造成bug。
getchar的存在会将输入缓冲区内的\n替代,从而起到一个清空输入缓冲区的功能。
文件操作
教师、管理员的功能中存在需要批量导入下级信息,因此设置文件读入是必须的,如:
FILE *frp=fopen("学生信息.txt","r");
for(int i=0;i<6;i++)
{
char name2[20]={};
int id2 = 0;
char laji[10];
int la=0;
fscanf(frp,"%d%s%s%d",&id2,name2,laji,&la);
int index=find_id_stu(id2);
fscanf(frp,"%f%f%f",&stu[index].chinese,&stu[index].math,&stu[index].english);
stu[index].sum=(stu[index].chinese+stu[index].math+stu[index].english);
stu[index].ave=stu[index].sum/3;
}
printf("添加成绩完成!\n");
感想总结
在合作完成一个项目时,首先捋顺大流程,确立主要的框架,预留各个功能的接口后再进行各个部分的分工会比较合理且高效。
同样的,类似甚至完全相同的功能可以通过共用函数来提高效率,减少部分工作量。
由于功能完成后需要合并进行联调,对自己完成的功能中函数的命名也不能太过随意,可以与成员讨论确定各部分函数名,避免有函数重名等现象。并且添加注释也会有助于其他成员的理解,也有助于联调时查错、改正。
ATTENTION:由于完整代码过多,已上传至我的Github,看所有点击这里。