從零開始的C程序設計大作業——學生成績管理系統


前言

學生成績管理系統可以說是C語言程序設計的結課的必備大作業了。花了些時間,費了些頭發肝了下,完成了兩個系統,一個是控制台版本的,另一個用easyx圖形庫進行了優化。
先放出完成后的演示圖片占個坑。具體的實現過程,等我再梳理下,再慢慢更新整理到論壇上來。

演示DEMO

基礎控制台版本

image.png
輸出所有學生信息

控制台版本開發過程整理

開發環境

系統: win10

IDE: Dev Cpp

前置知識

需要掌握基礎的C語言知識

  • 順序結構
  • 分支結構
  • 循環結構
  • 數組、字符串
  • 函數
  • 結構體、指針
  • 鏈表
  • 文件操作

功能分析

工欲善其事必先利其器,先分析好整體功能和大體的布局再慢慢動手進行代碼的實現。
基礎設想是,先顯示主菜單,通過輸入數字選擇對應的功能,包括有增加學生信息,刪除學生信息,修改學生信息,查詢學生信息以及退出程序功能。
image.png

主菜單界面實現

使用輸出語句來實現界面。計划使用數字鍵來代表各自的功能。

//主菜單界面 
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("請輸入對應的功能鍵(數字): ");
}

image.png

功能框架搭建

先處理好整個功能框架,通過輸入數字,進行分支判斷,不同的數字代表不同的功能。先將要實現的功能做個簡易的版本出來,之后再慢慢填充細節。
想的是執行完某些功能后還能繼續進行操作,所以將程序放入循環中,並在操作執行完成后,詢問繼續操作,再根據選擇進行處理。

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;
}

tLRiEed7FC.gif

數據結構定義

圍繞學生信息進行處理,那么思考學生具有哪些信息。包含,學號,姓名,性別,語文,數學,英語成績,還有個總分。將對應屬性集合在一塊,采用結構體方式進行數據操作。並使用鏈表的方式將數據進行串聯。

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;
		}
	 }
}

image-20201225155709522

增加學生信息

接下來是增加學生的信息,此處采用頭插法將鏈表結點進行插入。將學生信息的增加分成了兩部分,一部分是界面的打印,一部分是底層數據的處理。

image-20201225180440775

界面實現:

//增加學生信息
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;
}

image-20201225161643690

image-20201225161603787

文件數據的寫入

這部分和文件的讀取部分相似,思路是將整個鏈表內容存儲到文件中。

使用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);
}

6nW6K36jsj

Ne41ND5ZLg

學生信息查詢

接下來是實現學生信息查詢功能,計划也是頁面輸出部分與邏輯實現部分進行分離。打算,可以通過學號與姓名兩個關鍵值進行信息的查找。因為是鏈表結構,為了方便之后的操作,邏輯函數會返回查找到的學生信息的前一個結點位置,這樣的話也能在刪除學生信息與修改學生信息中進行函數的復用了。

界面實現:

//查詢學生信息
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;
}

4aoMYPA7rj

Mk9h8hz0gF

學生信息修改

依舊是分成兩部分,先輸出界面,過程邏輯的話就沿用學生信息查詢的部分。實現邏輯是這樣的:先查到要查詢的學生信息,在對信息修改,改完了再保存到文件中。

頁面和實現部分:

//修改學生信息
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);
}

image-20201226175035839

image-20201226175102218

學生信息刪除

接下來實現學生信息刪除部分。頁面部分輸出提示,之后輸入學號查詢要刪除的學生信息。利用之前實現的查詢信息的函數得到結點位置,之后再根據位置刪除對應的結點,再將修改后的信息保存至文件中去。

頁面部分

//刪除學生信息
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);//釋放結點空間 
	
}

image-20201226210348062

70euw6DARL

image-20201226210102154

結束界面

到此為止,這個小系統的基礎功能都已經完成了。接下來把結束界面處理下。

//退出程序
void goodBye(){
	system("cls");
	printf("歡迎下次使用~\n");
	exit(0);//結束程序 
}

ConsolePauser_F0B8oTbtcU

學生成績管理系統V1.0版本到此也就完結了。之后也可以在此基礎上進行其他功能的開發,比如,程序排序,最高分,平均分等等的處理。大體都是圍繞鏈表的遍歷,插入和刪除操作來執行的。再結合自己對界面的設計即可。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM