C语言学生成绩管理系统详解[通俗易懂]

文章目录一、系统概述二、数据类型三、自定义函数说明四、运行界面五、源代码源代码请直接跳到最后引言:最近写了C语言的大作业,感觉做得还行,记录一下,给后人一些参考,给自己留更深印象方便后续改进!不知道发了这篇博客会不会认为我抄袭…害怕.jpg一、系统概述使用单向链表和文件作为基本数据结构,设计一个学生成绩管理程序,管理某学校学生成绩。[1]插入数据[2]修改对应数据项的数据[3]删除对应学号的信息[4]查找某学号的信息[5]查找不及格学生[6]对学生成绩进行排名[7]统计各个等级的学生

大家好,又见面了,我是你们的朋友全栈君。

源代码请直接跳到最后

引言:最近写了C语言的大作业,感觉做得还行,记录一下,给后人一些参考,给自己留更深印象方便后续改进!

不知道发了这篇博客会不会认为我抄袭…害怕.jpg

一、系统概述

使用单向链表和文件作为基本数据结构,设计一个学生成绩管理程序,管理某学校学生成绩。
[1]插入数据
[2]修改对应数据项的数据
[3]删除对应学号的信息
[4]查找某学号的信息
[5]查找不及格学生
[6]对学生成绩进行排名
[7]统计各个等级的学生人数
[8]输出所有学生信息
[9]分页显示学生信息

C语言学生成绩管理系统详解[通俗易懂]

二、数据类型

//枚举
enum sex{ 
   women,man}; 
struct StuLink{ 
   
	int  xh;                   //学号
	char xm[20];               //姓名 
	enum sex  xb;              //性别 
	int  cj;                   //成绩,范围[0,100] 前四个为输入项 
	char dj;                   //等级
	int  mc;                   //名次
	struct StuLink *next;      //下一项 
};
char sex[][3]={ 
   "女","男"};     //用于输出“男女”中文字符 
int size=sizeof(struct StuLink);  //节点字节大小 
  1. 注意姓名是xm[20],是字符串;而等级是cj,单个字符;这会影响到赋值问题
  2. 其中姓名、性别、成绩是输入项,名字、等级、名次由程序计算得出

三、自定义函数说明

1. main 函数

函数首部:void main

参数列表:
[1] menu1:用于接收一级菜单选择
[2] menu2:用于接收一级菜单选择
[3] i:用于 for 循环迭代变量
[4]n:用于接收“插入数据”功能的学生个数
[5] dj_add[5]:用于储存各等级人数
[6] head:用于储存头节点的地址
[7]pw:用于储存尾节点的地址

返回值:无

实现功能:选择对应功能并实现

算法描述:

void main(){ 
   
// 声明变量
	int menu1,menu2;        //menu1:一级菜单 menu2:二级菜单 
	int i=0,n,dj_add[5]={ 
   0,0,0,0,0};
	struct StuLink *head=NULL,*pw;   //*head:学生信息链表头指针 pw:尾节点 
	
// 声明函数
// 从数据文件中逐行读取学生信息生成学生链表,返回头指针 
	struct StuLink *ReadFromFile();
// 先将学生链表按学号升序排序,再将学生链表中的数据逐行保存到数据文件
	void SaveToFile(struct StuLink *head);
// SortLink函数:按指定数据项的顺序【1:学号(升序)】或者【2:成绩(降序)】对学生链表进行排序 
	struct StuLink *SortLink(struct StuLink *head,int i); 
// InsertNode函数:在链表尾插入一个新结点。新结点的学号是链表中最大学号加1,姓名和成绩从键盘输入
// (注意:成绩必须在[0,100]区间的整数),根据成绩计算等级。
// 注意:插入结点会导致链表中各结点名次的变化。
	struct StuLink *InsertNode(struct StuLink *pw);
// EditNode函数:修改链表中指定学号的结点(学号不能修改,成绩必须在[0,100]区间的整数)
// 注意:当修改成绩时会导致等级和名次的变化
	void EditNode(struct StuLink *head); 
//DeleteNode函数:删除链表中指定学号的结点。注意:删除结点会导致链表中各结点名次的变化
	struct StuLink *DeleteNode(struct StuLink *head);
// QueryNode函数:查询链表中指定学号的结点,并显示查询结果。
void QueryNode(struct StuLink *head);
// QueryLink函数:查询链表中不及格的所有结点,并显示查询结果。
void QueryLink(struct StuLink *head);
//RankLink函数:计算链表中每个结点的名次。名次规则:按成绩降序排名,从第1名开始依次排名,
//若出现并列名次,则名次需要叠加。例如,若出现5个并列第1名,则没有第2名,下一个名次是第6名,依此类推。
void RankLink(struct StuLink *head);
//AnalysisLink函数:统计并返回各等级人数。等级标准:
//A:90及以上 B:80及以上 C:70及以上 D:60及以上 E:60以下
void AnalysisLink(struct StuLink *head,int *dj_add);
//OutputLink_1函数:按指定数据项的顺序【1:学号(升序)】或者【2:成绩(降序)】输出学生成绩表、各等级人数。
//学生成绩表每行输出一个学生信息(依次为学号、姓名、性别、成绩、等级和名次,各项间以1个空格隔开),
//各等级人数分行输出。
void  OutputLink_1(struct StuLink *head,int i);
//OutputLink_2函数:分页显示全部学生的信息。
//分页功能:每页显示10个学生信息,有上一页、下一页、首页和最后一页的翻页功能。
void  OutputLink_2(struct StuLink *head,int i);
	
// 执行语句
	head=ReadFromFile();     //读取文件到链表,获取头指针 
	
	
// 菜单
	while(1){ 
   
		system("cls");                  //清控制台,Windows 
		printf("========================================\n");//40个=
		printf("= =\n");
		printf("= 学生成绩管理程序 =\n");
		printf("= by:xxx =\n"); 
		printf("========================================\n");
		printf("= =\n");
		printf("= 1-数据维护 2-数据查询 =\n");
		printf("= 3-统计分析 4-报表输出 =\n");
		printf("= 0-退出 =\n");
		printf("= =\n");
		printf("========================================\n");
// printf("\n");
		printf("请选择:");
		scanf("%d",&menu1); 
		switch(menu1){ 
                    //一级菜单 
			case 1:
				while(1){ 
                         //循环输出二级菜单 
					system("cls");
					printf("\n");
					printf("========================================\n");
					printf("= =\n");
					printf("= 1-数据插入 2-数据修改 =\n");
					printf("= 3-数据删除 0-返回上级 =\n");
					printf("= =\n");
					printf("========================================\n");
					printf("请选择:");
					scanf("%d",&menu2); 
					switch(menu2){ 
         //二级菜单 
						case 1:
							printf("请输入要插入的学生个数(n>0): "); 
							scanf("%d",&n);
							while(n<=0){ 
   
								printf("!!!请输入正确的学生个数!!!: ");
								scanf("%d",&n);
							}
							pw=head;
							if(pw){ 
   
								while(pw->next)   //获取尾部节点 
									pw=pw->next;
							}
							
							for(i=0;i<n;i++){ 
   
								pw=InsertNode(pw);
								if(head==NULL) head=pw;
							}
							// 计算名次
							RankLink(head);
// SaveToFile(head); 
							break;
						case 2:
							EditNode(head);
							// 计算名次
							RankLink(head);
// SaveToFile(head);
							break;
						case 3:
							head=DeleteNode(head);
							// 计算名次
							RankLink(head);
// SaveToFile(head); 
							break;
						case 0:
							break;
					}
					if(menu2==0) break;
					}
				break;
			case 2:
				while(1){ 
                         //循环输出二级菜单 
					system("cls");
					printf("\n");
					printf("========================================\n");
					printf("= =\n");
					printf("=1-学号查询 2-不及格学生查询 0-返回上级=\n");
					printf("= =\n");
					printf("========================================\n");
					printf("请选择:");
					scanf("%d",&menu2); 
					switch(menu2){ 
         //二级菜单 
						case 1:
							QueryNode(head);
							printf("\n"); system("pause");
							break;
						case 2:
							QueryLink(head); 
							printf("\n"); system("pause");
							break;
						case 0:
							break;
					}
					if(menu2==0) break;
					}
				break;
			case 3:
				while(1){ 
                         //循环输出二级菜单 
					system("cls");
					printf("\n");
					printf("========================================\n");
					printf("= =\n");
					printf("= 1-成绩名次计算 2-成绩频次分析 =\n");
					printf("= 0-返回上级 =\n");
					printf("= =\n");
					printf("========================================\n");
					printf("请选择:");
					scanf("%d",&menu2); 
					switch(menu2){ 
         //二级菜单 
						case 1:
							RankLink(head);
							break;
						case 2:
							AnalysisLink(head,dj_add);
							printf("'A'有%d人;'B'有%d人,'C'有%d人,'D'有%d人,'E'有%d人,共有%d人\n",
							dj_add[0],dj_add[1],dj_add[2],dj_add[3],dj_add[4],dj_add[0]+dj_add[1]+dj_add[2]+dj_add[3]+dj_add[4]); 
							printf("\n"); system("pause"); 
							break;
						case 0:
							break;
					}
					if(menu2==0) break;
					}
				break;
			case 4:
				while(1){ 
                         //循环输出二级菜单 
					system("cls");
					printf("\n");
					printf("========================================\n");
					printf("= =\n");
					printf("=1-排序显示学生信息 2-分页显示学生信息=\n");
					printf("= 0-返回上级 =\n");
					printf("= =\n");
					printf("========================================\n");
					printf("请选择:");
					scanf("%d",&menu2); 
					switch(menu2){ 
         //二级菜单 
						case 1:
							printf("请选择按【1:学号(升序)】或者【2:成绩(降序)】输出学生成绩表:");
							scanf("%d",&i);
							while((i!=1)&&(i!=2)){ 
   
								printf("!!!请选择正确选项!!!1 or 2 : ");
								scanf("%d",&i);
							}
							OutputLink_1(head,i);
							printf("\n"); 
							system("pause"); 
							break;
						case 2:
							printf("请选择按【1:学号(升序)】或者【2:成绩(降序)】输出学生成绩表:");
							scanf("%d",&i);
							while((i!=1)&&(i!=2)){ 
   
								printf("!!!请选择正确选项!!!1 or 2 : ");
								scanf("%d",&i);
							}
							OutputLink_2(head,i);
							break;
						case 0:
							break;
					}
					if(menu2==0) break;
					}
				break;
			case 0:
				printf("========================================\n");
				printf("= =\n");
				printf("= 你已经退出学生管理系统 =\n");
				printf("= =\n");
				printf("========================================\n");
				return;       //退出main函数 
		}
	} 

} 

2. ReadFromFile 函数

函数首部:struct StuLink *ReadFromFile()

参数列表:
[1]fp:用于储存储存在缓冲区的文件地址
[2]p1:用于储存开辟的新节点的地址
[3]p2:用于储存尾节点的地址
[4]head:用于储存首节点的地址
[5]ch:用于接收文件第一个字符

返回值:head 的地址

实现功能:
1.写打开文件
2.2.读取文件第一个字符,若是 EOF 文件终止符,则返回 head 的指针,函数结束;否则将 fp 的地址重置为文件开头
3.3.循环:若 fp 指针不为空,则开辟新节点,并且接入链表的尾节点(根据情况),读取 文件第一行信息并且赋值到 p1 指向的节点中
4.4.写关闭文件,返回 head 的地址

算法描述:

struct StuLink *ReadFromFile(){ 
   
	FILE *fp;                           //指向student.dat文件 
	struct StuLink *p1,*p2,*head=NULL;  //head:头节点 p1:开辟新节点 p2:尾节点 
	char ch;
	
	if((fp=fopen("student.dat","r"))==NULL){ 
      //读开student.dat 
		printf("打开student.dat失败\n");
		exit(0); 
	} 
	ch=fgetc(fp);                               //读取文件第一个字符
	if(ch==EOF){ 
                                   //EOF文件终止符
		printf("文件为空\n");
		return head;	
	}else{ 
   
		rewind(fp);                            // 将fp的地址重置为文件开头
	}
	
	while(!feof(fp)){ 
   
		if((p1=(struct StuLink *)malloc(size))==NULL) { 
   
			printf("不能成功分配储存块");
			exit(0);
		}
		p1->next=NULL;
		if(head==NULL)  head=p1;        //首节点 
			else p2->next=p1;     //非首节点,表尾插入新节点 
		p2=p1;                    // p2指向新的表尾结点 
		fscanf(fp,"%d %s %d %d %s %d\n",&p1->xh,p1->xm,&p1->xb,&p1->cj,&p1->dj,&p1->mc);
// 读取\n是防止fp以为文件未完 
		printf("%-5d%-10s%-5d%-5d%-5c%-5d\n",p1->xh,p1->xm,p1->xb,p1->cj,p1->dj,p1->mc);
	}
	fclose(fp);                                 //关闭student.dat
	return head;
} 

3. SortLink 函数

函数首部:struct StuLink *SortLink(struct StuLink *head,int i)

参数列表:
[1]head:储存首节点的地址
[2]i:用于储存排序方式的选项
[3]xh:用于储存学号
[4]xb:用于储存性别
[5]cj:用于储存成绩
[6]mc:用于储存名次
[7]xm:用于储存姓名
[8]dj:用于储存等级
[9]p1:用于表示被比较节点的地址
[10]p2:用于表示比较节点的地址
[11]p3:用于表示中间节点的地址

返回值:head 的地址

实现功能:

  1. 判断 head 是否为空,为空则返回 head 并且结束函数
  2. 进行排序,快速排序,交换连个节点的数据项,而不是改变链表的节点信息
  3. 返回 head,结束函数

算法描述:

struct StuLink *SortLink(struct StuLink *head,int i){ 
   
		if(head==NULL)return head;
// 使用交换数据的形式交换两个节点 
		int xh,xb,cj,mc;
		char xm[20],dj;
// p1:被比较节点 p2:比较节点 p3:快速排序储存节点 
		struct StuLink *p1=head,*p2=head->next,*p3=p1;
		switch(i){ 
   
			case 1:
// 快速排序
				while(p1->next){ 
   
					p2=p1->next;
					p3=p1;
					while(p2){ 
   
						if(p3->xh>p2->xh) 
							p3=p2;
						p2=p2->next;
					}
					if(p3->xh<p1->xh){ 
   
						xh=p3->xh;  xb=p3->xb;
						cj=p3->cj;  mc=p3->mc;
						strcpy(xm,p3->xm);  dj=p3->dj;
						p3->xh=p1->xh;  p3->xb=p1->xb;
						p3->cj=p1->cj;  p3->mc=p1->mc;
						strcpy(p3->xm,p1->xm);  p3->dj=p1->dj;
						p1->xh=xh;  p1->xb=xb;
						p1->cj=cj;  p1->mc=mc;
						strcpy(p1->xm,xm);  p1->dj=dj;
					} 
					p1=p1->next;
				} 
				break;
			case 2:
// 快速排序
				while(p1->next){ 
   
					p2=p1->next;
					p3=p1;
					while(p2){ 
   
						if(p3->cj<p2->cj) 
							p3=p2;
						p2=p2->next;
					}
					if(p3->cj>p1->cj){ 
   
						xh=p3->xh;  xb=p3->xb;
						cj=p3->cj;  mc=p3->mc;
						strcpy(xm,p3->xm);  dj=p3->dj;
						p3->xh=p1->xh;  p3->xb=p1->xb;
						p3->cj=p1->cj;  p3->mc=p1->mc;
						strcpy(p3->xm,p1->xm);  p3->dj=p1->dj;
						p1->xh=xh;  p1->xb=xb;
						p1->cj=cj;  p1->mc=mc;
						strcpy(p1->xm,xm);  p1->dj=dj;
					} 
					p1=p1->next;
				} 
				break;
		} 
		return head;
	}

4. SaveToFile 函数

函数首部:void SaveToFile(struct StuLink *head)

参数列表:
[1]head:用于表示首节点的地址
[2]fp:用于表示缓冲区文件的地址
[3]i:用于储存排序方式

返回值:无

实现功能:写开文件,循环将链表中的信息储存到文件中

算法描述:

	void SaveToFile(struct StuLink *head){ 
   
		FILE *fp;
		int i=1;
		head=SortLink(head,i);
		struct StuLink *p=head;
		if((fp=fopen("student.dat","w"))==NULL){ 
   
			printf("写开文件失败!");
			exit(0);
		}
		while(p){ 
   
// 写入文件 
			fprintf(fp,"%d %s %d %d %c %d\n",p->xh,p->xm,p->xb,p->cj,p->dj,p->mc);
			p=p->next;
		}
		fclose(fp); 
	}

5. InsertNode 函数

函数首部:struct StuLink *InsertNode

参数列表:
[1]pw:用于表示链表尾节点的地址
[2]p1:用于表示新节点的地址
[3]xm:用于表示姓名字符串的地址

返回值:pw 的地址

实现功能:开辟一个新节点,用 p1 指向新节点,并向其赋值,同时检查性别和成绩的正确性, 根据成绩计算等级,再将 p1 接在 pw 后面

算法描述

struct StuLink *InsertNode(struct StuLink *pw){ 
   
	struct StuLink *p1;    //pw:原链表尾节点 p1:开辟新节点 
	if((p1=(struct StuLink *)malloc(size))==NULL) { 
   
			printf("不能成功分配储存块\n");
			exit(0);
	}
	p1->next=NULL;
	if(pw)
		p1->xh=pw->xh+1;
	else 
		p1->xh=1;
	char xm[20];
	printf("请依次输入姓名、性别(男1女0)、成绩[0,100]: ");
	scanf("%s%d%d",xm,&p1->xb,&p1->cj);
	while(p1->xb!=0&&p1->xb!=1){ 
   
		printf("! ! ! 性别只能是1或0,请重新输入性别1:男 0:女 ");
		scanf("%d",&p1->xb); 
	}
	while(p1->cj<0 || p1->cj>100){ 
   
		printf("! ! ! 成绩范围是0~100,请重新输入成绩 ");
		scanf("%d",&p1->cj); 
	}
	strcpy(p1->xm,xm);
	
// p1->mc=1; // 名次暂时命名为1 
	if(p1->cj>=90) p1->dj='A';
	else if(p1->cj>=80)  p1->dj='B';
	else if(p1->cj>=70)  p1->dj='C';
	else if(p1->cj>=60)  p1->dj='D';
	else p1->dj='E';
	if(pw==NULL)	pw=p1;
	else{ 
   
		pw->next=p1;	
		pw=pw->next;
	}
	return pw;
}

6. EditNode函数

函数首部:void EditNode(struct StuLink *head)

参数列表:
[1]head:用于表示首节点的地址
[2]p1:用于表示循环寻找对应学号地址
[3]xm:用于表示姓名字符串
[4]n:用于表示要修改的学号
[5]re:用于表示要修改的数据项

返回值:无 实现功能:先判断链表是否为空,为空则退出函数。输入一个学号,判断是否存在,不存在则退 出函数;存在则输出对应学生信息,选择要修改的数据项进行修改

返回值:无

算法描述:

void EditNode(struct StuLink *head){ 
   
	if(head==NULL){ 
   
		printf("学生数据为空!\n");
		printf("\n"); system("pause");	
		return;
	}
	 
	struct StuLink *p1=head;
	char xm[20];
	
	int n,re;
	printf("请输入你要修改的学生信息的学号:");
	scanf("%d",&n) ;
	while(p1){ 
   
		if(p1->xh==n){ 
   
			break;
		}else{ 
   
			p1=p1->next;
		}
	}
	if(p1){ 
   
		printf("你要修改的学生信息为:\n");
		printf("学号 姓名 性别 成绩 等级 名次 ##男1女0##\n");
		printf("%-6d%-10s%-6d%-6d%-6c%-6d\n",p1->xh,p1->xm,p1->xb,p1->cj,p1->dj,p1->mc);
	} else{ 
   
		printf("你输入的学号有误!\n");
		printf("\n"); system("pause");	
		return;
	} 
	printf("请选择要修改的数据项:0-不修改 1-姓名 2-性别 3-成绩 "); 
	scanf("%d",&re);
	while(re<0||re>3){ 
   
		printf("输入有误!重新输入: ");
		scanf("%d",&re);
	}
	switch(re){ 
   
		case 0:break;
		case 1:
			printf("请输出新的姓名:");
			scanf("%s",xm);
			strcpy(p1->xm,xm);
			break;
		case 2:
			printf("请输入新的性别:");
			scanf("%d",&p1->xb);
			while(p1->xb!=0&&p1->xb!=1){ 
   
				printf("! ! ! 性别只能是1或0,请重新输入性别1:男 0:女 ");
				scanf("%d",&p1->xb); 
			}
			break;
		case 3:
			printf("请输入新的成绩:");
			scanf("%d",&p1->cj);
			while(p1->cj<0 || p1->cj>100){ 
   
				printf("! ! ! 成绩范围是0~100,请重新输入成绩 ");
				scanf("%d",&p1->cj); 
			}
			if(p1->cj>=90) p1->dj='A';
				else if(p1->cj>=80)  p1->dj='B';
				else if(p1->cj>=70)  p1->dj='C';
				else if(p1->cj>=60)  p1->dj='D';
				else p1->dj='E';
			break;	
	}
}

**7. DeleteNode 函数 **

函数首部:struct StuLink *DeleteNode(struct StuLink *head)

参数列表:
[1]head:用于表示首节点的地址
[2]p1:用于表示循环查找对应节点的地址
[3]p2:用于表示 p1 指向的节点的前驱节点的地址
[4]del_xh:用于表示被删除学生的学号

返回值:head 的地址

算法描述:

struct StuLink *DeleteNode(struct StuLink *head){ 
   
	if(head==NULL){ 
   
		printf("学生数据为空!\n");
		printf("\n"); system("pause");	
		return head;
	}
	struct StuLink *p1=head,*p2;
	int del_xh;
	printf("请输入要删除的学号:");
	scanf("%d",&del_xh); 
	while((p1->xh!=del_xh)&&(p1->next!=NULL)){ 
   
		p2=p1;p1=p1->next;
	} 
	if(p1->xh==del_xh){ 
      //找到 
		if(head==p1) head=head->next;   //首节点 
		else p2->next=p1->next;         //非首节点 
		free(p1); 
		printf("删除成功!\n");
	}else printf("未找到此学号对应节点!\n");
	printf("\n"); system("pause"); 
	return head;
}

8. QueryNode 函数

函数首部:void QueryNode(struct StuLink *head)

参数列表:
[1]head:用于表示首节点的地址
[2]query_xh:用于表示查询的学号
[3]p1:用于表示循环查找对应节点的地址
[4]p2:用于表示 p1 指向的节点的前驱节点的地址

返回值:无

实现功能:先判断链表是否为空,为空则退出函数。接收要查询的学号,循环寻找,找到则输出学学 生信息;否则输出未找到

算法描述:

void QueryNode(struct StuLink *head){ 
   
	if(head==NULL){ 
   
		printf("学生数据为空!\n");
		printf("\n"); system("pause");	
		return;
	}
	int query_xh;
	struct StuLink *p1=head,*p2;
	printf("请输入要查询的学生学号:");
	scanf("%d",&query_xh); 
	while((p1->xh!=query_xh)&&(p1->next!=NULL)){ 
   
		p2=p1;p1=p1->next;
	} 
	if(p1->xh==query_xh){ 
              //找到 
		printf("查找结果为:\n"); 
		printf("学号:%-5d姓名:%-10s成绩:%-5d等级:%-5c名次:%-5d",p1->xh,p1->xm,p1->cj,p1->dj,p1->mc);
		if(p1->xb==1) printf("性别:男\n");
		else printf("性别:女\n"); 
	}else printf("未找到该学号对应学生!\n");
}

9. QueryLink 函数

函数首部:void QueryLink(struct StuLink *head)

参数列表:
[1]head:用于表示首节点的地址
[2]p1:用于表示循环链表各节点的地址
[3]n:用于表示循环次数

返回值:无

实现功能:先判断链表是否为空,为空则退出函数。循环查找不及格学习,符合则输出,不符合则下 一个。若一个不及格的都没有,则输出没有不及格学生

算法描述:

void QueryLink(struct StuLink *head){ 
   
	if(head==NULL){ 
   
		printf("学生数据为空!\n");
		printf("\n"); system("pause");	
		return;
	}
	struct StuLink *p1=head;
	int n=0;
	while(p1){ 
   
		if(p1->cj<60){ 
   
			n++; if(n==1) printf("未及格学生信息为:\n"); 
			printf("学号:%-5d姓名:%-10s成绩:%-5d等级:%-5c名次:%-5d",p1->xh,p1->xm,p1->cj,p1->dj,p1->mc);
			if(p1->xb==1) printf("性别:男\n");
				else printf("性别:女\n"); 
		}
		p1=p1->next;
	}
	if(n==0) printf("没有不及格学生!\n");
}

10. RankLink 函数

函数首部:void RankLink(struct StuLink *head)

参数列表:
[1]head:用于表示首节点的地址
[2]i:用于表示排序的升降序
[3]p1:用于表示循环链表中节点的地址
[4]p2:用于表示 p1 指向的节点的前驱节点的地址
[5]n:用于表示循环次数

返回值:无

实现功能:先判断链表是否为空,为空则退出函数。学生按成绩降序排序,再计算链表中每个结 点的名次,最后保存(学号升序)到文件中。

算法描述:

void RankLink(struct StuLink *head){ 
   
	int i=2;
	if(head==NULL){ 
   
		printf("学生数据为空!\n");
		printf("\n"); system("pause");	
		return;
	}
	head=SortLink(head,i);
	struct StuLink *p1=head,*p2;
	
	int n=1;
	while(p1){ 
   
		p1->mc=n;
		n++;
		if((p1!=head)&&((p1->cj)==(p2->cj))) p1->mc=p2->mc;
		p2=p1;
		p1=p1->next;
	}
	SaveToFile(head);
}

11. AnalysisLink 函数

函数首部:void AnalysisLink(struct StuLink *head,int *dj_add)

参数列表:
[1]head:用于表示首节点的地址
[2]dj_add:用于表示各个等级的人数数组
[3]p1:用于表示循环链表中的节点

返回值:无

实现功能:先判断链表是否为空,为空则退出函数。循环各节点,判断成绩且对应等级统计数递增

算法描述:

void AnalysisLink(struct StuLink *head,int *dj_add){ 
   
	if(head==NULL){ 
   
		printf("学生数据为空!\n");
		printf("\n"); system("pause");	
		return;
	}
	struct StuLink *p1=head;
	while(p1){ 
   
		if(p1->cj>=90) dj_add[0]++;
		else if(p1->cj>=80) dj_add[1]++;
		else if(p1->cj>=70) dj_add[2]++;
		else if(p1->cj>=60) dj_add[3]++;
		else  dj_add[5]++;
		p1=p1->next;
	}	
}

12. OutputLink_1 函数

函数首部:void OutputLink_1(struct StuLink *head,int i)

参数列表:
[1]head:用于表示首节点的地址
[2]p1:用于表示循环链表节点的地址

返回值:无

实现功能:先判断链表是否为空,为空则退出函数。循环各节点,输出信息

算法描述:

void  OutputLink_1(struct StuLink *head,int i){ 
   
	if(head==NULL){ 
   
		printf("学生数据为空!\n");
		printf("\n"); system("pause");	
		return;
	}
	head=SortLink(head,i);
	struct StuLink *p1=head;
	printf("所有学生信息为:\n");
	printf("学号 姓名 性别 成绩 等级 名次\n");
	while(p1){ 
   
		
		printf("%-6d%-10s",p1->xh,p1->xm);
		if(p1->xb==1) printf("男 ");
			else printf("女 "); 
		printf("%-6d%-6c%-6d\n",p1->cj,p1->dj,p1->mc);
		p1=p1->next;
	}
}

13. OutputLink_2 函数

函数首部:void OutputLink_2(struct StuLink *head,int i)

参数列表:
[1]head:用于表示首节点的地址
[2]i:用于表示排序的升降序
[3]sum:用于表示学生总数
[4]n:用于表示当前输出个数
[5]num1:用于表示菜单选择
[6]page_sum:用于表示总页数
[7]page_now:用于表示当前页数
[8]pf_num:用于表示当前输出的个数,控制不超过 10 个

返回值:无

实现功能:先判断链表是否为空,为空则退出函数。先输出第一页,判断总人数,是否有下一页, 无则退出函数,有则继续。接收输入选择功能数字,判断数字时候合理,不合理重新输入。使用 switch 跳到对应功能。1:用上次输出的当前页数*10-20 就等于“上一页”的第一个的学生个数,再用 n 控制 p1 循环到此处进行输出。2:跟着 p1 继续输出。3:输出第一页。4:用(sum/10)*10 就等于最后一页的第一 个学生个数,用 p1 循环到此处,输出即可。

算法描述:

void  OutputLink_2(struct StuLink *head,int i){ 
   
	if(head==NULL){ 
   
		printf("学生数据为空!\n");
		printf("\n"); system("pause");	
		return;
	}
	head=SortLink(head,i);
// sum:学生总数 n:当前输出个数 
	int n=1,num1,sum=0,page_sum,page_now=1,pf_num=0;
	struct StuLink *p1=head;
	while(p1){ 
   
		sum++;
		p1=p1->next;
	}
	p1=head;
	page_sum=sum/10+1;
	system("cls");
	printf("学号 姓名 性别 成绩 等级 名次\n");
	pf_num=1;
	while(p1&&pf_num<=10){ 
   
		printf("%-6d%-10s",p1->xh,p1->xm);
		if(p1->xb==1) printf("男 ");
			else printf("女 "); 
		printf("%-6d%-6c%-6d\n",p1->cj,p1->dj,p1->mc);
		pf_num++;
		p1=p1->next;
	}
	if(sum<=10){ 
   
		printf("\n只有一页,暂无上下页功能\n"); 
		system("pause"); return ;
	}else{ 
   
		printf("\n 2-下一页 3-首页 4-尾页 5-返回上级\n");
		printf(" 当前第%-2d页,共%-2d页\n",page_now,page_sum); 
		scanf("%d",&num1);
		while(num1<2||num1>5){ 
   
			printf("请输入正确的数字: ");
			scanf("%d",&num1);
		}
	}
	while(1) { 
   
		switch(num1){ 
   
			case 1:
				system("cls");
				p1=head;
				n=1;
				while(n<=page_now*10-20){ 
   
					p1=p1->next;
					n++;
				}
				printf("学号 姓名 性别 成绩 等级 名次\n");
				pf_num=1;
				while(p1&&pf_num<=10){ 
   
					printf("%-6d%-10s",p1->xh,p1->xm);
					if(p1->xb==1) printf("男 ");
						else printf("女 "); 
					printf("%-6d%-6c%-6d\n",p1->cj,p1->dj,p1->mc);
					pf_num++;
					p1=p1->next;
				}
				page_now--;                                          //当前页数-1
				if(page_now==1){ 
   
					printf("\n 2-下一页 3-首页 4-尾页 5-返回上级\n");
					printf(" 当前第%-2d页,共%-2d页\n",page_now,page_sum); 
					scanf("%d",&num1);
					while(num1<2||num1>5){ 
   
						printf("请输入正确的数字: ");
						scanf("%d",&num1);
					}
				}else{ 
   
					printf("\n1-上一页 2-下一页 3-首页 4-尾页 5-返回上级\n");
					printf(" 当前第%-2d页,共%-2d页\n"); 
					scanf("%d",&num1);
					while(num1<1||num1>4){ 
   
						printf("请输入正确的数字: ");
						scanf("%d",&num1);
					}
				}
				break;
			case 2:
				system("cls");
				printf("学号 姓名 性别 成绩 等级 名次\n");
				pf_num=1;
				while(p1&&pf_num<=10){ 
   
					printf("%-6d%-10s",p1->xh,p1->xm);
					if(p1->xb==1) printf("男 ");
						else printf("女 "); 
					printf("%-6d%-6c%-6d\n",p1->cj,p1->dj,p1->mc);
					pf_num++;
					p1=p1->next;
				}
				page_now++;                                          //当前页数+1 
				if(page_now==page_sum){ 
   
					printf("\n1-上一页 3-首页 4-尾页 5-返回上级\n");
					printf(" 当前第%-2d页,共%-2d页\n",page_now,page_sum); 
					scanf("%d",&num1);
					while(num1<1||num1>5||num1==2){ 
   
						printf("请输入正确的数字: ");
						scanf("%d",&num1);
					}
				}else{ 
   
					printf("\n1-上一页 2-下一页 3-首页 4-尾页 5-返回上级\n");
					printf(" 当前第%-2d页,共%-2d页\n"); 
					scanf("%d",&num1);
					while(num1<1||num1>5){ 
   
						printf("请输入正确的数字: ");
						scanf("%d",&num1);
					}
				}
				break;
			case 3:
				system("cls");
				p1=head;
				page_now=1;
				printf("学号 姓名 性别 成绩 等级 名次\n");
				pf_num=1;
				while(p1&&pf_num<=10){ 
   
					printf("%-6d%-10s",p1->xh,p1->xm);
					if(p1->xb==1) printf("男 ");
						else printf("女 "); 
					printf("%-6d%-6c%-6d\n",p1->cj,p1->dj,p1->mc);
					pf_num++;
					p1=p1->next;
				}
				printf("\n 2-下一页 3-首页 4-尾页 5-返回上级\n");
				printf(" 当前第%-2d页,共%-2d页\n",page_now,page_sum); 
				scanf("%d",&num1);
				while(num1<2||num1>5){ 
   
					printf("请输入正确的数字: ");
					scanf("%d",&num1);
				}
				break;
			case 4:
				system("cls");
				p1=head;
				page_now=page_sum;
				n=1;
				while(n<=(sum/10)*10){ 
   
					p1=p1->next;
					n++;
				}
				printf("学号 姓名 性别 成绩 等级 名次\n");
				pf_num=1;
				while(p1&&pf_num<=10){ 
   
					printf("%-6d%-10s",p1->xh,p1->xm);
					if(p1->xb==1) printf("男 ");
						else printf("女 "); 
					printf("%-6d%-6c%-6d\n",p1->cj,p1->dj,p1->mc);
					pf_num++;
					p1=p1->next;
				}
				printf("\n1-上一页 3-首页 4-尾页 5-返回上级\n");
				printf(" 当前第%-2d页,共%-2d页\n",page_now,page_sum); 
				scanf("%d",&num1);
				while(num1<1||num1>5||num1==2){ 
   
					printf("请输入正确的数字: ");
					scanf("%d",&num1);
				}
				break;
			case 5:
				break;
		}
		if(num1==5) break;
	}
}

四、运行界面

一:主菜单

C语言学生成绩管理系统详解[通俗易懂]

二:二级菜单——数据维护

C语言学生成绩管理系统详解[通俗易懂]

  1. 数据插入

    C语言学生成绩管理系统详解[通俗易懂]

  2. 数据修改

    C语言学生成绩管理系统详解[通俗易懂]

    C语言学生成绩管理系统详解[通俗易懂]

  3. 数据删除

    C语言学生成绩管理系统详解[通俗易懂]

三:二级菜单——数据查询

C语言学生成绩管理系统详解[通俗易懂]

  1. 学号查询

C语言学生成绩管理系统详解[通俗易懂]

C语言学生成绩管理系统详解[通俗易懂]

  1. 不及格学生查询

C语言学生成绩管理系统详解[通俗易懂]

四:二级菜单——统计分析

C语言学生成绩管理系统详解[通俗易懂]

  1. 成绩名次计算:无输出
  2. 成绩频次分析

C语言学生成绩管理系统详解[通俗易懂]

五:二级菜单——报表输出

C语言学生成绩管理系统详解[通俗易懂]

  1. 排序显示学生信息

​ 学号升序:

C语言学生成绩管理系统详解[通俗易懂]

​ 成绩降序:

C语言学生成绩管理系统详解[通俗易懂]

  1. 分页显示学生信息

    C语言学生成绩管理系统详解[通俗易懂]

    C语言学生成绩管理系统详解[通俗易懂]

六、退出

C语言学生成绩管理系统详解[通俗易懂]

五、源代码

注意要在同个目录新建一个student.dat文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//枚举
enum sex{ 
   women,man}; 
struct StuLink{ 
   
	int  xh;                   //学号
	char xm[20];               //姓名 
	enum sex  xb;              //性别 
	int  cj;                   //成绩,范围[0,100] 前四个为输入项 
	char dj;                   //等级
	int  mc;                   //名次
	struct StuLink *next;      //下一项 
};
char sex[][3]={ 
   "女","男"};     //用于输出“男女”中文字符 
int size=sizeof(struct StuLink);  //节点字节大小 

void main(){ 
   
// 声明变量
	int menu1,menu2;        //menu1:一级菜单 menu2:二级菜单 
	int i=0,n,dj_add[5]={ 
   0,0,0,0,0};
	struct StuLink *head=NULL,*pw;   //*head:学生信息链表头指针 pw:尾节点 
	
// 声明函数
// 从数据文件中逐行读取学生信息生成学生链表,返回头指针 
	struct StuLink *ReadFromFile();
// 先将学生链表按学号升序排序,再将学生链表中的数据逐行保存到数据文件
	void SaveToFile(struct StuLink *head);
// SortLink函数:按指定数据项的顺序【1:学号(升序)】或者【2:成绩(降序)】对学生链表进行排序 
	struct StuLink *SortLink(struct StuLink *head,int i); 
// InsertNode函数:在链表尾插入一个新结点。新结点的学号是链表中最大学号加1,姓名和成绩从键盘输入
// (注意:成绩必须在[0,100]区间的整数),根据成绩计算等级。
// 注意:插入结点会导致链表中各结点名次的变化。
	struct StuLink *InsertNode(struct StuLink *pw);
// EditNode函数:修改链表中指定学号的结点(学号不能修改,成绩必须在[0,100]区间的整数)
// 注意:当修改成绩时会导致等级和名次的变化
	void EditNode(struct StuLink *head); 
//DeleteNode函数:删除链表中指定学号的结点。注意:删除结点会导致链表中各结点名次的变化
	struct StuLink *DeleteNode(struct StuLink *head);
// QueryNode函数:查询链表中指定学号的结点,并显示查询结果。
void QueryNode(struct StuLink *head);
// QueryLink函数:查询链表中不及格的所有结点,并显示查询结果。
void QueryLink(struct StuLink *head);
//RankLink函数:计算链表中每个结点的名次。名次规则:按成绩降序排名,从第1名开始依次排名,
//若出现并列名次,则名次需要叠加。例如,若出现5个并列第1名,则没有第2名,下一个名次是第6名,依此类推。
void RankLink(struct StuLink *head);
//AnalysisLink函数:统计并返回各等级人数。等级标准:
//A:90及以上 B:80及以上 C:70及以上 D:60及以上 E:60以下
void AnalysisLink(struct StuLink *head,int *dj_add);
//OutputLink_1函数:按指定数据项的顺序【1:学号(升序)】或者【2:成绩(降序)】输出学生成绩表、各等级人数。
//学生成绩表每行输出一个学生信息(依次为学号、姓名、性别、成绩、等级和名次,各项间以1个空格隔开),
//各等级人数分行输出。
void  OutputLink_1(struct StuLink *head,int i);
//OutputLink_2函数:分页显示全部学生的信息。
//分页功能:每页显示10个学生信息,有上一页、下一页、首页和最后一页的翻页功能。
void  OutputLink_2(struct StuLink *head,int i);
	
// 执行语句
	head=ReadFromFile();     //读取文件到链表,获取头指针 
	
	
// 菜单
	while(1){ 
   
		system("cls");                  //清控制台,Windows 
		printf("========================================\n");//40个=
		printf("= =\n");
		printf("= 学生成绩管理程序 =\n");
		printf("= by:xxx =\n"); 
		printf("========================================\n");
		printf("= =\n");
		printf("= 1-数据维护 2-数据查询 =\n");
		printf("= 3-统计分析 4-报表输出 =\n");
		printf("= 0-退出 =\n");
		printf("= =\n");
		printf("========================================\n");
// printf("\n");
		printf("请选择:");
		scanf("%d",&menu1); 
		switch(menu1){ 
                    //一级菜单 
			case 1:
				while(1){ 
                         //循环输出二级菜单 
					system("cls");
					printf("\n");
					printf("========================================\n");
					printf("= =\n");
					printf("= 1-数据插入 2-数据修改 =\n");
					printf("= 3-数据删除 0-返回上级 =\n");
					printf("= =\n");
					printf("========================================\n");
					printf("请选择:");
					scanf("%d",&menu2); 
					switch(menu2){ 
         //二级菜单 
						case 1:
							printf("请输入要插入的学生个数(n>0): "); 
							scanf("%d",&n);
							while(n<=0){ 
   
								printf("!!!请输入正确的学生个数!!!: ");
								scanf("%d",&n);
							}
							pw=head;
							if(pw){ 
   
								while(pw->next)   //获取尾部节点 
									pw=pw->next;
							}
							
							for(i=0;i<n;i++){ 
   
								pw=InsertNode(pw);
								if(head==NULL) head=pw;
							}
							// 计算名次
							RankLink(head);
// SaveToFile(head); 
							break;
						case 2:
							EditNode(head);
							// 计算名次
							RankLink(head);
// SaveToFile(head);
							break;
						case 3:
							head=DeleteNode(head);
							// 计算名次
							RankLink(head);
// SaveToFile(head); 
							break;
						case 0:
							break;
					}
					if(menu2==0) break;
					}
				break;
			case 2:
				while(1){ 
                         //循环输出二级菜单 
					system("cls");
					printf("\n");
					printf("========================================\n");
					printf("= =\n");
					printf("=1-学号查询 2-不及格学生查询 0-返回上级=\n");
					printf("= =\n");
					printf("========================================\n");
					printf("请选择:");
					scanf("%d",&menu2); 
					switch(menu2){ 
         //二级菜单 
						case 1:
							QueryNode(head);
							printf("\n"); system("pause");
							break;
						case 2:
							QueryLink(head); 
							printf("\n"); system("pause");
							break;
						case 0:
							break;
					}
					if(menu2==0) break;
					}
				break;
			case 3:
				while(1){ 
                         //循环输出二级菜单 
					system("cls");
					printf("\n");
					printf("========================================\n");
					printf("= =\n");
					printf("= 1-成绩名次计算 2-成绩频次分析 =\n");
					printf("= 0-返回上级 =\n");
					printf("= =\n");
					printf("========================================\n");
					printf("请选择:");
					scanf("%d",&menu2); 
					switch(menu2){ 
         //二级菜单 
						case 1:
							RankLink(head);
							break;
						case 2:
							AnalysisLink(head,dj_add);
							printf("'A'有%d人;'B'有%d人,'C'有%d人,'D'有%d人,'E'有%d人,共有%d人\n",
							dj_add[0],dj_add[1],dj_add[2],dj_add[3],dj_add[4],dj_add[0]+dj_add[1]+dj_add[2]+dj_add[3]+dj_add[4]); 
							printf("\n"); system("pause"); 
							break;
						case 0:
							break;
					}
					if(menu2==0) break;
					}
				break;
			case 4:
				while(1){ 
                         //循环输出二级菜单 
					system("cls");
					printf("\n");
					printf("========================================\n");
					printf("= =\n");
					printf("=1-排序显示学生信息 2-分页显示学生信息=\n");
					printf("= 0-返回上级 =\n");
					printf("= =\n");
					printf("========================================\n");
					printf("请选择:");
					scanf("%d",&menu2); 
					switch(menu2){ 
         //二级菜单 
						case 1:
							printf("请选择按【1:学号(升序)】或者【2:成绩(降序)】输出学生成绩表:");
							scanf("%d",&i);
							while((i!=1)&&(i!=2)){ 
   
								printf("!!!请选择正确选项!!!1 or 2 : ");
								scanf("%d",&i);
							}
							OutputLink_1(head,i);
							printf("\n"); 
							system("pause"); 
							break;
						case 2:
							printf("请选择按【1:学号(升序)】或者【2:成绩(降序)】输出学生成绩表:");
							scanf("%d",&i);
							while((i!=1)&&(i!=2)){ 
   
								printf("!!!请选择正确选项!!!1 or 2 : ");
								scanf("%d",&i);
							}
							OutputLink_2(head,i);
							break;
						case 0:
							break;
					}
					if(menu2==0) break;
					}
				break;
			case 0:
				printf("========================================\n");
				printf("= =\n");
				printf("= 你已经退出学生管理系统 =\n");
				printf("= =\n");
				printf("========================================\n");
				return;       //退出main函数 
		}
	} 

} 

// 自 定 义 函 数 
// 从数据文件中逐行读取学生信息生成学生链表,返回头指针 
struct StuLink *ReadFromFile(){ 
   
	FILE *fp;                           //指向student.dat文件 
	struct StuLink *p1,*p2,*head=NULL;  //head:头节点 p1:开辟新节点 p2:尾节点 
	char ch;
	
	if((fp=fopen("student.dat","r"))==NULL){ 
      //读开student.dat 
		printf("打开student.dat失败\n");
		exit(0); 
	} 
	ch=fgetc(fp);                               //读取文件第一个字符
	if(ch==EOF){ 
                                   //EOF文件终止符
		printf("文件为空\n");
		return head;	
	}else{ 
   
		rewind(fp);                            // 将fp的地址重置为文件开头
	}
	
	while(!feof(fp)){ 
   
		if((p1=(struct StuLink *)malloc(size))==NULL) { 
   
			printf("不能成功分配储存块");
			exit(0);
		}
		p1->next=NULL;
		if(head==NULL)  head=p1;        //首节点 
			else p2->next=p1;     //非首节点,表尾插入新节点 
		p2=p1;                    // p2指向新的表尾结点 
		fscanf(fp,"%d %s %d %d %s %d\n",&p1->xh,p1->xm,&p1->xb,&p1->cj,&p1->dj,&p1->mc);
// 读取\n是防止fp以为文件未完 
		printf("%-5d%-10s%-5d%-5d%-5c%-5d\n",p1->xh,p1->xm,p1->xb,p1->cj,p1->dj,p1->mc);
	}
	fclose(fp);                                 //关闭student.dat
	return head;
} 

// SortLink函数:按指定数据项的顺序【1:学号(升序)】或者【2:成绩(降序)】对学生链表进行排序
	struct StuLink *SortLink(struct StuLink *head,int i){ 
   
		if(head==NULL)return head;
// 使用交换数据的形式交换两个节点 
		int xh,xb,cj,mc;
		char xm[20],dj;
// p1:被比较节点 p2:比较节点 p3:快速排序储存节点 
		struct StuLink *p1=head,*p2=head->next,*p3=p1;
		switch(i){ 
   
			case 1:
// 快速排序
				while(p1->next){ 
   
					p2=p1->next;
					p3=p1;
					while(p2){ 
   
						if(p3->xh>p2->xh) 
							p3=p2;
						p2=p2->next;
					}
					if(p3->xh<p1->xh){ 
   
						xh=p3->xh;  xb=p3->xb;
						cj=p3->cj;  mc=p3->mc;
						strcpy(xm,p3->xm);  dj=p3->dj;
						p3->xh=p1->xh;  p3->xb=p1->xb;
						p3->cj=p1->cj;  p3->mc=p1->mc;
						strcpy(p3->xm,p1->xm);  p3->dj=p1->dj;
						p1->xh=xh;  p1->xb=xb;
						p1->cj=cj;  p1->mc=mc;
						strcpy(p1->xm,xm);  p1->dj=dj;
					} 
					p1=p1->next;
				} 
				break;
			case 2:
// 快速排序
				while(p1->next){ 
   
					p2=p1->next;
					p3=p1;
					while(p2){ 
   
						if(p3->cj<p2->cj) 
							p3=p2;
						p2=p2->next;
					}
					if(p3->cj>p1->cj){ 
   
						xh=p3->xh;  xb=p3->xb;
						cj=p3->cj;  mc=p3->mc;
						strcpy(xm,p3->xm);  dj=p3->dj;
						p3->xh=p1->xh;  p3->xb=p1->xb;
						p3->cj=p1->cj;  p3->mc=p1->mc;
						strcpy(p3->xm,p1->xm);  p3->dj=p1->dj;
						p1->xh=xh;  p1->xb=xb;
						p1->cj=cj;  p1->mc=mc;
						strcpy(p1->xm,xm);  p1->dj=dj;
					} 
					p1=p1->next;
				} 
				break;
		} 
		return head;
	}

// 先将学生链表按学号升序排序,再将学生链表中的数据逐行保存到数据文件
	void SaveToFile(struct StuLink *head){ 
   
		FILE *fp;
		int i=1;
		head=SortLink(head,i);
		struct StuLink *p=head;
		if((fp=fopen("student.dat","w"))==NULL){ 
   
			printf("写开文件失败!");
			exit(0);
		}
		while(p){ 
   
// 写入文件 
			fprintf(fp,"%d %s %d %d %c %d\n",p->xh,p->xm,p->xb,p->cj,p->dj,p->mc);
			p=p->next;
		}
		fclose(fp); 
	}
	
// InsertNode函数:在链表尾插入一个新结点。新结点的学号是链表中最大学号加1,姓名和成绩从键盘输入
// (注意:成绩必须在[0,100]区间的整数),根据成绩计算等级。
// 注意:插入结点会导致链表中各结点名次的变化。
struct StuLink *InsertNode(struct StuLink *pw){ 
   
	struct StuLink *p1;    //pw:原链表尾节点 p1:开辟新节点 
	if((p1=(struct StuLink *)malloc(size))==NULL) { 
   
			printf("不能成功分配储存块\n");
			exit(0);
	}
	p1->next=NULL;
	if(pw)
		p1->xh=pw->xh+1;
	else 
		p1->xh=1;
	char xm[20];
	printf("请依次输入姓名、性别(男1女0)、成绩[0,100]: ");
	scanf("%s%d%d",xm,&p1->xb,&p1->cj);
	while(p1->xb!=0&&p1->xb!=1){ 
   
		printf("! ! ! 性别只能是1或0,请重新输入性别1:男 0:女 ");
		scanf("%d",&p1->xb); 
	}
	while(p1->cj<0 || p1->cj>100){ 
   
		printf("! ! ! 成绩范围是0~100,请重新输入成绩 ");
		scanf("%d",&p1->cj); 
	}
	strcpy(p1->xm,xm);
	
// p1->mc=1; // 名次暂时命名为1 
	if(p1->cj>=90) p1->dj='A';
	else if(p1->cj>=80)  p1->dj='B';
	else if(p1->cj>=70)  p1->dj='C';
	else if(p1->cj>=60)  p1->dj='D';
	else p1->dj='E';
	if(pw==NULL)	pw=p1;
	else{ 
   
		pw->next=p1;	
		pw=pw->next;
	}
	return pw;
}

// EditNode函数:修改链表中指定学号的结点(学号不能修改,成绩必须在[0,100]区间的整数)
// 注意:当修改成绩时会导致等级和名次的变化
void EditNode(struct StuLink *head){ 
   
	if(head==NULL){ 
   
		printf("学生数据为空!\n");
		printf("\n"); system("pause");	
		return;
	}
	 
	struct StuLink *p1=head;
	char xm[20];
	
	int n,re;
	printf("请输入你要修改的学生信息的学号:");
	scanf("%d",&n) ;
	while(p1){ 
   
		if(p1->xh==n){ 
   
			break;
		}else{ 
   
			p1=p1->next;
		}
	}
	if(p1){ 
   
		printf("你要修改的学生信息为:\n");
		printf("学号 姓名 性别 成绩 等级 名次 ##男1女0##\n");
		printf("%-6d%-10s%-6d%-6d%-6c%-6d\n",p1->xh,p1->xm,p1->xb,p1->cj,p1->dj,p1->mc);
	} else{ 
   
		printf("你输入的学号有误!\n");
		printf("\n"); system("pause");	
		return;
	} 
	printf("请选择要修改的数据项:0-不修改 1-姓名 2-性别 3-成绩 "); 
	scanf("%d",&re);
	while(re<0||re>3){ 
   
		printf("输入有误!重新输入: ");
		scanf("%d",&re);
	}
	switch(re){ 
   
		case 0:break;
		case 1:
			printf("请输出新的姓名:");
			scanf("%s",xm);
			strcpy(p1->xm,xm);
			break;
		case 2:
			printf("请输入新的性别:");
			scanf("%d",&p1->xb);
			while(p1->xb!=0&&p1->xb!=1){ 
   
				printf("! ! ! 性别只能是1或0,请重新输入性别1:男 0:女 ");
				scanf("%d",&p1->xb); 
			}
			break;
		case 3:
			printf("请输入新的成绩:");
			scanf("%d",&p1->cj);
			while(p1->cj<0 || p1->cj>100){ 
   
				printf("! ! ! 成绩范围是0~100,请重新输入成绩 ");
				scanf("%d",&p1->cj); 
			}
			if(p1->cj>=90) p1->dj='A';
				else if(p1->cj>=80)  p1->dj='B';
				else if(p1->cj>=70)  p1->dj='C';
				else if(p1->cj>=60)  p1->dj='D';
				else p1->dj='E';
			break;	
	}
}

//DeleteNode函数:删除链表中指定学号的结点。注意:删除结点会导致链表中各结点名次的变化
struct StuLink *DeleteNode(struct StuLink *head){ 
   
	if(head==NULL){ 
   
		printf("学生数据为空!\n");
		printf("\n"); system("pause");	
		return head;
	}
	struct StuLink *p1=head,*p2;
	int del_xh;
	printf("请输入要删除的学号:");
	scanf("%d",&del_xh); 
	while((p1->xh!=del_xh)&&(p1->next!=NULL)){ 
   
		p2=p1;p1=p1->next;
	} 
	if(p1->xh==del_xh){ 
      //找到 
		if(head==p1) head=head->next;   //首节点 
		else p2->next=p1->next;         //非首节点 
		free(p1); 
		printf("删除成功!\n");
	}else printf("未找到此学号对应节点!\n");
	printf("\n"); system("pause"); 
	return head;
}

// QueryNode函数:查询链表中指定学号的结点,并显示查询结果。
void QueryNode(struct StuLink *head){ 
   
	if(head==NULL){ 
   
		printf("学生数据为空!\n");
		printf("\n"); system("pause");	
		return;
	}
	int query_xh;
	struct StuLink *p1=head,*p2;
	printf("请输入要查询的学生学号:");
	scanf("%d",&query_xh); 
	while((p1->xh!=query_xh)&&(p1->next!=NULL)){ 
   
		p2=p1;p1=p1->next;
	} 
	if(p1->xh==query_xh){ 
              //找到 
		printf("查找结果为:\n"); 
		printf("学号:%-5d姓名:%-10s成绩:%-5d等级:%-5c名次:%-5d",p1->xh,p1->xm,p1->cj,p1->dj,p1->mc);
		if(p1->xb==1) printf("性别:男\n");
		else printf("性别:女\n"); 
	}else printf("未找到该学号对应学生!\n");
}

// QueryLink函数:查询链表中不及格的所有结点,并显示查询结果。
void QueryLink(struct StuLink *head){ 
   
	if(head==NULL){ 
   
		printf("学生数据为空!\n");
		printf("\n"); system("pause");	
		return;
	}
	struct StuLink *p1=head;
	int n=0;
	while(p1){ 
   
		if(p1->cj<60){ 
   
			n++; if(n==1) printf("未及格学生信息为:\n"); 
			printf("学号:%-5d姓名:%-10s成绩:%-5d等级:%-5c名次:%-5d",p1->xh,p1->xm,p1->cj,p1->dj,p1->mc);
			if(p1->xb==1) printf("性别:男\n");
				else printf("性别:女\n"); 
		}
		p1=p1->next;
	}
	if(n==0) printf("没有不及格学生!\n");
}

//RankLink函数:计算链表中每个结点的名次。名次规则:按成绩降序排名,从第1名开始依次排名,
//若出现并列名次,则名次需要叠加。例如,若出现5个并列第1名,则没有第2名,下一个名次是第6名,依此类推。
void RankLink(struct StuLink *head){ 
   
	int i=2;
	if(head==NULL){ 
   
		printf("学生数据为空!\n");
		printf("\n"); system("pause");	
		return;
	}
	head=SortLink(head,i);
	struct StuLink *p1=head,*p2;
	
	int n=1;
	while(p1){ 
   
		p1->mc=n;
		n++;
		if((p1!=head)&&((p1->cj)==(p2->cj))) p1->mc=p2->mc;
		p2=p1;
		p1=p1->next;
	}
	SaveToFile(head);
}

//AnalysisLink函数:统计并返回各等级人数。等级标准:
//A:90及以上 B:80及以上 C:70及以上 D:60及以上 E:60以下
void AnalysisLink(struct StuLink *head,int *dj_add){ 
   
	if(head==NULL){ 
   
		printf("学生数据为空!\n");
		printf("\n"); system("pause");	
		return;
	}
	struct StuLink *p1=head;
	while(p1){ 
   
		if(p1->cj>=90) dj_add[0]++;
		else if(p1->cj>=80) dj_add[1]++;
		else if(p1->cj>=70) dj_add[2]++;
		else if(p1->cj>=60) dj_add[3]++;
		else  dj_add[5]++;
		p1=p1->next;
	}	
}

//OutputLink_1函数:按指定数据项的顺序【1:学号(升序)】或者【2:成绩(降序)】输出学生成绩表、各等级人数。
//学生成绩表每行输出一个学生信息(依次为学号、姓名、性别、成绩、等级和名次,各项间以1个空格隔开),
//各等级人数分行输出。
void  OutputLink_1(struct StuLink *head,int i){ 
   
	if(head==NULL){ 
   
		printf("学生数据为空!\n");
		printf("\n"); system("pause");	
		return;
	}
	head=SortLink(head,i);
	struct StuLink *p1=head;
	printf("所有学生信息为:\n");
	printf("学号 姓名 性别 成绩 等级 名次\n");
	while(p1){ 
   
		
		printf("%-6d%-10s",p1->xh,p1->xm);
		if(p1->xb==1) printf("男 ");
			else printf("女 "); 
		printf("%-6d%-6c%-6d\n",p1->cj,p1->dj,p1->mc);
		p1=p1->next;
	}
}

//OutputLink_2函数:分页显示全部学生的信息。
//分页功能:每页显示10个学生信息,有上一页、下一页、首页和最后一页的翻页功能。
void  OutputLink_2(struct StuLink *head,int i){ 
   
	if(head==NULL){ 
   
		printf("学生数据为空!\n");
		printf("\n"); system("pause");	
		return;
	}
	head=SortLink(head,i);
// sum:学生总数 n:当前输出个数 
	int n=1,num1,sum=0,page_sum,page_now=1,pf_num=0;
	struct StuLink *p1=head;
	while(p1){ 
   
		sum++;
		p1=p1->next;
	}
	p1=head;
	page_sum=sum/10+1;
	system("cls");
	printf("学号 姓名 性别 成绩 等级 名次\n");
	pf_num=1;
	while(p1&&pf_num<=10){ 
   
		printf("%-6d%-10s",p1->xh,p1->xm);
		if(p1->xb==1) printf("男 ");
			else printf("女 "); 
		printf("%-6d%-6c%-6d\n",p1->cj,p1->dj,p1->mc);
		pf_num++;
		p1=p1->next;
	}
	if(sum<=10){ 
   
		printf("\n只有一页,暂无上下页功能\n"); 
		system("pause"); return ;
	}else{ 
   
		printf("\n 2-下一页 3-首页 4-尾页 5-返回上级\n");
		printf(" 当前第%-2d页,共%-2d页\n",page_now,page_sum); 
		scanf("%d",&num1);
		while(num1<2||num1>5){ 
   
			printf("请输入正确的数字: ");
			scanf("%d",&num1);
		}
	}
	while(1) { 
   
		switch(num1){ 
   
			case 1:
				system("cls");
				p1=head;
				n=1;
				while(n<=page_now*10-20){ 
   
					p1=p1->next;
					n++;
				}
				printf("学号 姓名 性别 成绩 等级 名次\n");
				pf_num=1;
				while(p1&&pf_num<=10){ 
   
					printf("%-6d%-10s",p1->xh,p1->xm);
					if(p1->xb==1) printf("男 ");
						else printf("女 "); 
					printf("%-6d%-6c%-6d\n",p1->cj,p1->dj,p1->mc);
					pf_num++;
					p1=p1->next;
				}
				page_now--;                                          //当前页数-1
				if(page_now==1){ 
   
					printf("\n 2-下一页 3-首页 4-尾页 5-返回上级\n");
					printf(" 当前第%-2d页,共%-2d页\n",page_now,page_sum); 
					scanf("%d",&num1);
					while(num1<2||num1>5){ 
   
						printf("请输入正确的数字: ");
						scanf("%d",&num1);
					}
				}else{ 
   
					printf("\n1-上一页 2-下一页 3-首页 4-尾页 5-返回上级\n");
					printf(" 当前第%-2d页,共%-2d页\n"); 
					scanf("%d",&num1);
					while(num1<1||num1>4){ 
   
						printf("请输入正确的数字: ");
						scanf("%d",&num1);
					}
				}
				break;
			case 2:
				system("cls");
				printf("学号 姓名 性别 成绩 等级 名次\n");
				pf_num=1;
				while(p1&&pf_num<=10){ 
   
					printf("%-6d%-10s",p1->xh,p1->xm);
					if(p1->xb==1) printf("男 ");
						else printf("女 "); 
					printf("%-6d%-6c%-6d\n",p1->cj,p1->dj,p1->mc);
					pf_num++;
					p1=p1->next;
				}
				page_now++;                                          //当前页数+1 
				if(page_now==page_sum){ 
   
					printf("\n1-上一页 3-首页 4-尾页 5-返回上级\n");
					printf(" 当前第%-2d页,共%-2d页\n",page_now,page_sum); 
					scanf("%d",&num1);
					while(num1<1||num1>5||num1==2){ 
   
						printf("请输入正确的数字: ");
						scanf("%d",&num1);
					}
				}else{ 
   
					printf("\n1-上一页 2-下一页 3-首页 4-尾页 5-返回上级\n");
					printf(" 当前第%-2d页,共%-2d页\n"); 
					scanf("%d",&num1);
					while(num1<1||num1>5){ 
   
						printf("请输入正确的数字: ");
						scanf("%d",&num1);
					}
				}
				break;
			case 3:
				system("cls");
				p1=head;
				page_now=1;
				printf("学号 姓名 性别 成绩 等级 名次\n");
				pf_num=1;
				while(p1&&pf_num<=10){ 
   
					printf("%-6d%-10s",p1->xh,p1->xm);
					if(p1->xb==1) printf("男 ");
						else printf("女 "); 
					printf("%-6d%-6c%-6d\n",p1->cj,p1->dj,p1->mc);
					pf_num++;
					p1=p1->next;
				}
				printf("\n 2-下一页 3-首页 4-尾页 5-返回上级\n");
				printf(" 当前第%-2d页,共%-2d页\n",page_now,page_sum); 
				scanf("%d",&num1);
				while(num1<2||num1>5){ 
   
					printf("请输入正确的数字: ");
					scanf("%d",&num1);
				}
				break;
			case 4:
				system("cls");
				p1=head;
				page_now=page_sum;
				n=1;
				while(n<=(sum/10)*10){ 
   
					p1=p1->next;
					n++;
				}
				printf("学号 姓名 性别 成绩 等级 名次\n");
				pf_num=1;
				while(p1&&pf_num<=10){ 
   
					printf("%-6d%-10s",p1->xh,p1->xm);
					if(p1->xb==1) printf("男 ");
						else printf("女 "); 
					printf("%-6d%-6c%-6d\n",p1->cj,p1->dj,p1->mc);
					pf_num++;
					p1=p1->next;
				}
				printf("\n1-上一页 3-首页 4-尾页 5-返回上级\n");
				printf(" 当前第%-2d页,共%-2d页\n",page_now,page_sum); 
				scanf("%d",&num1);
				while(num1<1||num1>5||num1==2){ 
   
					printf("请输入正确的数字: ");
					scanf("%d",&num1);
				}
				break;
			case 5:
				break;
		}
		if(num1==5) break;
	}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/128372.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • allegro16.6转pads9.5实战攻略

    allegro16.6转pads9.5实战攻略1)要建立两个用户变量(如已存在,不需要建立) 。AEX_BIN_ROOTD:\MentorGraphics\9.5PADS\SDD_HOME\translators\win32\bi

  • 【汇编小白】关于masm5.0 显示 Unable to open input file

    【汇编小白】关于masm5.0 显示 Unable to open input file   然后, &lt;https://blog.csdn.net/w605283073/article/details/8334732?_t_t_t=0.2288642483095238&gt;这里也有讲解(侵删)ummmmm…第一次在这个平台写东西,不知道有没有人看and…为啥这个文章的标签,中文我加不来。,。加不来啊 (win10自带的微软输入法。,。输中文输一…

  • MODIS数据说明

    MODIS数据说明MODIS目前主要存在于两颗卫星上:TERRA和AQUA。TERRA卫星每日地方时上午10:30时过境,因此也把它称作地球观测第一颗上午星(EOS-AM1)。AQUA每日地方时下午过境,因此称作地球观测第一颗下午星(EOS-PM1)。两颗星相互配合,每1-2天可重复观测整个地球表面,得到36个波段(表1)的观测得到,这些数据广泛用于全球陆地、海洋和低层大气内的动态变化过程研究。MODIS获

  • 音视频编解码技术(一):MPEG-4/H.264 AVC 编解码标准

    音视频编解码技术(一):MPEG-4/H.264 AVC 编解码标准一、H264概述H.264,通常也被称之为H.264/AVC(或者H.264/MPEG-4AVC或MPEG-4/H.264AVC)1.H.264视频编解码的意义H.264的出现就是为了创

  • C++类中静态变量和静态方法使用介绍

    C++类中静态变量和静态方法使用介绍刷剑指offer第64题涉及到类内静态成员与方法的知识,有点模糊,找了两篇博客整理一下。转自:https://www.cnblogs.com/sixue/p/3997324.html    最近一直看c++相关的项目,但总是会被c++类中的静态成员变量与静态成员函数的理解感觉很是模糊,不明白为什么类中要是用静态成员变量.于是在网上搜集了一些资料,自己再稍微总结下。静态成员的概…

  • 简单工厂模式

    简单工厂模式

    2021年11月30日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号