前言
學生成績管理系統可以說是C語言程序設計的結課的必備大作業了。花了些時間,費了些頭發肝了下,完成了兩個系統,一個是控制台版本的,另一個用easyx圖形庫進行了優化。
先放出完成后的演示圖片占個坑。具體的實現過程,等我再梳理下,再慢慢更新整理到論壇上來。
演示DEMO
基礎控制台版本
控制台版本開發過程整理
開發環境
系統: win10
IDE: Dev Cpp
前置知識
需要掌握基礎的C語言知識
- 順序結構
- 分支結構
- 循環結構
- 數組、字符串
- 函數
- 結構體、指針
- 鏈表
- 文件操作
功能分析
工欲善其事必先利其器,先分析好整體功能和大體的布局再慢慢動手進行代碼的實現。
基礎設想是,先顯示主菜單,通過輸入數字選擇對應的功能,包括有增加學生信息,刪除學生信息,修改學生信息,查詢學生信息以及退出程序功能。
主菜單界面實現
使用輸出語句來實現界面。計划使用數字鍵來代表各自的功能。
//主菜單界面
void welcome(){
printf("************************\n");
printf("** 學生成績管理系統 **\n");
printf("** 作者:咸魚君 **\n");
printf("** **\n");
printf("** 增加學生信息 ---1 **\n");
printf("** 刪除學生信息 ---2 **\n");
printf("** 修改學生信息 ---3 **\n");
printf("** 查詢學生信息 ---4 **\n");
printf("** 輸出學生信息 ---5 **\n");
printf("** 退出管理系統 ---0 **\n");
printf("請輸入對應的功能鍵(數字): ");
}
功能框架搭建
先處理好整個功能框架,通過輸入數字,進行分支判斷,不同的數字代表不同的功能。先將要實現的功能做個簡易的版本出來,之后再慢慢填充細節。
想的是執行完某些功能后還能繼續進行操作,所以將程序放入循環中,並在操作執行完成后,詢問繼續操作,再根據選擇進行處理。
int main(){
int choice=0;
while(true){
welcome();
scanf("%d",&choice);
switch(choice){
case 1://增加學生信息
addStuInfo();
break;
case 2://刪除學生信息
deleteStuInfo();
break;
case 3://修改學生信息
fixStuInfo();
break;
case 4://查詢學生信息
searchStuInfo();
break;
case 5://輸出學生信息
printStuInfo();
break;
case 0://退出程序
goodBye();
break;
}
printf("是否需要繼續操作?(yes:1 / no:0 ):");
scanf("%d",&choice);
if(choice==0){
break;
}
}
return 0;
}
數據結構定義
圍繞學生信息進行處理,那么思考學生具有哪些信息。包含,學號,姓名,性別,語文,數學,英語成績,還有個總分。將對應屬性集合在一塊,采用結構體方式進行數據操作。並使用鏈表的方式將數據進行串聯。
typedef struct Node{
int id;//學號
char name[30];//姓名
char sex[10];//性別
int ch;//語文
int ma;//數學
int en;//英語
int sum;//總分
struct Node *next;//指向下一個結點
}node;
文件數據的讀取
這此程序的數據都要以文件的形式進行信息的保存,如果想要在屏幕上輸出數據,那么得先讀取文件中的信息才行。
C語言中文件讀取操作要使用文件指針和相關函數,格式如下。
FILE *fpr=fopen("文件名","操作方式");
fscanf(fpr,"%d",&intValue);
文件名需要加上后綴名,操作方式因為是要從文件中讀取信息,所以寫r。如果是進行信息的寫入則是w。
之后需要將讀取的信息以鏈表的方式組織起來,打算采用尾插法的方式插入數據。
// 尾插法
t->next=s;//鏈表尾指針 的后一個結點指向新結點
t=s;//更新尾結點
t->next=NULL;//鏈表尾指針 的后一個結點指向NULL
讀取函數
// 文件輸入
int readFile(Node *L){
FILE *fpr=fopen("studentInfo.txt","r");
node *t=L;
node st;
node *s;
if(fpr==NULL){
return 0;
}else{
//fscanf()
while(fscanf(fpr,"%d %s %s %d %d %d %d",&st.id,st.name,st.sex,&st.ch,&st.ma,&st.en,&st.sum)!=EOF){
s=(node *)malloc(sizeof(node));
*s=st;
// 尾插法
t->next=s;//鏈表尾指針 的后一個結點指向新結點
t=s;//更新尾結點
t->next=NULL;//鏈表尾指針 的后一個結點指向NULL
}
}
fclose(fpr);//關閉文件指針
return 1;
}
輸出所有學生信息
接下來完成所有學生信息的輸出。此處需要考察鏈表的遍歷。
void printStuInfo(node *L){
system("cls");
node *p=L->next;
printf("________________________________________________________\n");
printf("|學號\t|姓名\t|性別\t|語文\t|數學\t|英語\t|總分\t|\n");
printf("________________________________________________________\n");
if(p!=NULL){
while(p!=NULL){
printf("%d|%s\t|%s\t|%d\t|%d\t|%d\t|%d\t|\n",p->id,p->name,p->sex,p->ch,p->ma,p->en,p->sum);
printf("________________________________________________________\n");
p=p->next;
}
}
}
增加學生信息
接下來是增加學生的信息,此處采用頭插法將鏈表結點進行插入。將學生信息的增加分成了兩部分,一部分是界面的打印,一部分是底層數據的處理。
界面實現:
//增加學生信息
void printAddStuInfo(){
//
system("cls");
node st;
printf("請輸入新增學生相關信息\n");
printf("學號:");
scanf("%d",&st.id);
printf("姓名:");
scanf("%s",st.name);
printf("性別:");
scanf("%s",st.sex);
printf("語文:");
scanf("%d",&st.ch);
printf("數學:");
scanf("%d",&st.ma);
printf("英語:");
scanf("%d",&st.en);
st.sum=st.ch+st.ma+st.en;
insertStuInfo(&List,st);
}
功能實現:
void insertStuInfo(node *L,node e){
//頭插法
node *h=L;
node *s=(node *)malloc(sizeof(node));
*s=e;
s->next=h->next;
h->next=s;
}
文件數據的寫入
這部分和文件的讀取部分相似,思路是將整個鏈表內容存儲到文件中。
使用fprintf()將文件信息進行存儲。
//保存文件
int saveFile(node *L){
FILE *fpw=fopen("studentInfo.txt","w");
if(fpw==NULL) return 0;
node *p=L->next;
while(p!=NULL){
fprintf(fpw,"%d %s %s %d %d %d %d\n",p->id,p->name,p->sex,p->ch,p->ma,p->en,p->sum);
p=p->next;
}
fclose(fpw);//關閉文件指針
return 1;
}
再在學生信息的增加過程中添加文件數據的保存操作。
void insertStuInfo(node *L,node e){
//頭插法
node *h=L;
node *s=(node *)malloc(sizeof(node));
*s=e;
s->next=h->next;
h->next=s;
//保存文件
saveFile(L);
}
學生信息查詢
接下來是實現學生信息查詢功能,計划也是頁面輸出部分與邏輯實現部分進行分離。打算,可以通過學號與姓名兩個關鍵值進行信息的查找。因為是鏈表結構,為了方便之后的操作,邏輯函數會返回查找到的學生信息的前一個結點位置,這樣的話也能在刪除學生信息與修改學生信息中進行函數的復用了。
界面實現:
//查詢學生信息
void printSearchStuInfo(node *L){
system("cls");
int choice=0;
int id;
char name[50];
node *st;
printf("按學號查詢----- 1\n");
printf("按姓名查詢----- 2\n");
printf("請輸入查詢方式:");
scanf("%d",&choice);
if(choice == 1){
printf("請輸入要查詢的學號:");
scanf("%d",&id);
st=searchStuInfoById(id,L);
if(st==NULL){
printf("查無此人!\n");
}else{
st=st->next;
printf("________________________________________________________\n");
printf("|學號\t|姓名\t|性別\t|語文\t|數學\t|英語\t|總分\t|\n");
printf("________________________________________________________\n");
printf("%d|%s\t|%s\t|%d\t|%d\t|%d\t|%d\t|\n",st->id,st->name,st->sex,st->ch,st->ma,st->en,st->sum);
printf("________________________________________________________\n");
}
}else if(choice ==2){
printf("請輸入要查詢的姓名:");
scanf("%s",name);
st=searchStuInfoByName(name,L);
if(st==NULL){
printf("查無此人!\n");
}else{
st=st->next;
printf("________________________________________________________\n");
printf("|學號\t|姓名\t|性別\t|語文\t|數學\t|英語\t|總分\t|\n");
printf("________________________________________________________\n");
printf("%d|%s\t|%s\t|%d\t|%d\t|%d\t|%d\t|\n",st->id,st->name,st->sex,st->ch,st->ma,st->en,st->sum);
printf("________________________________________________________\n");
}
}
}
邏輯實現:
思路是遍歷整個鏈表,逐一對關鍵信息進行比較。
按學號進行查找,找不到返回NULL,找到了返回前一個結點位置
//按學號進行查找
node * searchStuInfoById(int id,node *L){
node *p=L;
while(p->next!=NULL){
if(p->next->id==id){
return p;
}
p=p->next;
}
return NULL;
}
按姓名進行查找,找不到返回NULL,找到了返回前一個結點位置
//按姓名進行查找
node * searchStuInfoByName(char name[],node *L){
node *p=L;
while(p->next!=NULL){
if(strcmp(name,p->next->name)==0){
return p;
}
p=p->next;
}
return NULL;
}
學生信息修改
依舊是分成兩部分,先輸出界面,過程邏輯的話就沿用學生信息查詢的部分。實現邏輯是這樣的:先查到要查詢的學生信息,在對信息修改,改完了再保存到文件中。
頁面和實現部分:
//修改學生信息
void printFixStuInfo(node *L){
system("cls");
int id;
int choice=-1;
printf("請輸入要查找的學生學號");
scanf("%d",&id);
node *st=searchStuInfoById(id,L);
if(st==NULL){
printf("查無此人!");
return;
}
st=st->next;
while(1){
system("cls");
printf("________________________________________________________\n");
printf("|學號\t|姓名\t|性別\t|語文\t|數學\t|英語\t|總分\t|\n");
printf("________________________________________________________\n");
printf("%d|%s\t|%s\t|%d\t|%d\t|%d\t|%d\t|\n",st->id,st->name,st->sex,st->ch,st->ma,st->en,st->sum);
printf("________________________________________________________\n");
printf("修改姓名---- 1\n");
printf("修改性別---- 2\n");
printf("修改語文---- 3\n");
printf("修改數學---- 4\n");
printf("修改英語---- 5\n");
printf("請輸入要修改的信息: ");
scanf("%d",&choice);
switch(choice){
case 1:
printf("請輸入姓名:");
scanf("%s",st->name);
break;
case 2:
printf("請輸入性別:");
scanf("%s",st->sex);
break;
case 3:
printf("請輸入語文:");
scanf("%d",&st->ch);
break;
case 4:
printf("請輸入數學:");
scanf("%d",&st->ma);
break;
case 5:
printf("請輸入英語:");
scanf("%d",&st->en);
break;
}
st->sum=st->ch+st->ma+st->en;
printf("是否繼續修改學生信息?(y-1 / n-0)\n");
scanf("%d",&choice);
if(choice == 0){
break;
}
}
printf("________________________________________________________\n");
printf("|學號\t|姓名\t|性別\t|語文\t|數學\t|英語\t|總分\t|\n");
printf("________________________________________________________\n");
printf("%d|%s\t|%s\t|%d\t|%d\t|%d\t|%d\t|\n",st->id,st->name,st->sex,st->ch,st->ma,st->en,st->sum);
printf("________________________________________________________\n");
//保存文件信息
saveFile(L);
}
學生信息刪除
接下來實現學生信息刪除部分。頁面部分輸出提示,之后輸入學號查詢要刪除的學生信息。利用之前實現的查詢信息的函數得到結點位置,之后再根據位置刪除對應的結點,再將修改后的信息保存至文件中去。
頁面部分
//刪除學生信息
void printDeleteStuInfo(node *L){
system("cls");
int id;
node *p;
printf("請輸入要查找的學生學號");
scanf("%d",&id);
node *st=searchStuInfoById(id,L);
p=st;
if(st==NULL){
printf("查無此人!");
return;
}
st=st->next;
printf("________________________________________________________\n");
printf("|學號\t|姓名\t|性別\t|語文\t|數學\t|英語\t|總分\t|\n");
printf("________________________________________________________\n");
printf("%d|%s\t|%s\t|%d\t|%d\t|%d\t|%d\t|\n",st->id,st->name,st->sex,st->ch,st->ma,st->en,st->sum);
printf("________________________________________________________\n");
deleteStuInfo(p);
saveFile(L);
}
結點刪除部分
//刪除學生信息
void deleteStuInfo(node *pr){
node *s=pr->next;
pr->next=s->next;
s->next=NULL;
free(s);//釋放結點空間
}
結束界面
到此為止,這個小系統的基礎功能都已經完成了。接下來把結束界面處理下。
//退出程序
void goodBye(){
system("cls");
printf("歡迎下次使用~\n");
exit(0);//結束程序
}
學生成績管理系統V1.0版本到此也就完結了。之后也可以在此基礎上進行其他功能的開發,比如,程序排序,最高分,平均分等等的處理。大體都是圍繞鏈表的遍歷,插入和刪除操作來執行的。再結合自己對界面的設計即可。