項目概況
用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,看所有點擊這裏。