73:学生成绩管理系统/图书管理系统/......

前言:

        作为我的第一篇”大作“哈哈,在此选择了“学生成绩管理系统”作为题目。具体题目的要求找不到了,但菜单第一页显示绝对是足够的。

        该程序基于链表实现,以二进制文件储存数据。下面直接看代码:        //基于VS2022

代码部分:

菜单:

void menu()									//打印菜单;
{
	printf_s("///\n");
	printf_s("/  欢迎试用学生成绩管理系统!:)           /\n");
	printf_s("/  请选择有关操作(输入相应数字):       /\n");
	printf_s("//                                            *****\n");
	printf_s("//     1.录入学生成绩及有关信息;             *****\n");
	printf_s("//     2.浏览所有学生成绩;                   *****\n");
	printf_s("//     3.查询某位学生成绩;                   *****\n");
	printf_s("//     4.成绩排序与统计;                     *****\n");
	printf_s("//     5.修改学生信息;                       *****\n");
	printf_s("//     0.退出系统;                           *****\n");
	printf_s("***************************************************\n");

}  

        首当其冲的便是菜单函数,用于提示按下相应的按键以执行对应操作。下面将逐个实现。

分块程序://依据程序运行方式排序

void Clear()
{
	system("pause");						//暂停程序;
	system("cls");							//清空控制台,使界面更好看;
}

        一个蛮好用的小插件。

void LoadStu(Node*head)
{
	FILE* file = fopen("./StuT", "r");
	if (!file)
	{
		printf_s("未找到文件,跳过读取。\n");
		return;
	}
	//创建一个结点,将文件存入内存空间;
	Node* new = malloc(sizeof(Node));
	new->next = NULL;
	Node* move = head;
	while (fread(&new->student, sizeof(Stu), 1, file) == 1)
	{
		move->next = new;
		move = new;
		new = malloc(sizeof(Node));
		new->next = NULL;
	}
	free(new);	//清理多创建的空间;
	//关闭文件;
	fclose(file);
	printf("读取成功。\n");
}

         一个文件读取模块,作用于选择操作之前,用于读取已存储文件,涉及文件操作函数。

void InStu(Node*head)
{
	Node* new = malloc(sizeof(Node));		//为新的结点分配区域;
	new->next = NULL;						//初始化;
	printf_s("请输入学生的学号、姓名、语文成绩1、数学成绩2、英语成绩3:\n");
	scanf("%d%s%d%d%d",&new->student.StuNum, &new->student.Name, & new->student.Score1, & new->student.Score2, & new->student.Score3);
											//使用scanf_s需要限制输入字数,不好用;scanf输入时需要以回车键为完成一次输入的标志;

	Node* move = head;						//创建新指针,使之随列表创建移动,便于操作;
	while (move->next != NULL)
	{
		move = move->next;
	}

	move->next = new;						//将新学生信息插入尾部;
	SaveStu(head);
	Clear();
}

        此程序用于录入学生信息,采用链表的操作将程序插入尾部。

void SaveStu(Node* head)
{
	//打开文件;
	FILE* file = fopen("./StuT", "w");
	if (file == NULL)
	{
		printf_s("打开文件失败。\n");
		return;
	}
	Node* move = head->next;
	while (move != NULL)	//写入数据;//结构体;
	{
		if (fwrite(&move->student, sizeof(Stu), 1, file) != 1)
		{
			printf_s("保存%s出现错误。\n", move->student.Name);
		}
		move = move->next;
	}
	//关闭文件;
	fclose(file);
}

        运行文件操作,储存链表数据,每一次储存都会覆盖掉上一次的数据。

void PrintStu(Node*head)					//遍历链表并打印;
{
	Node* move = head->next;				//指向首结点(数据结点);//只可用于普通的遍历中;
	while (move != NULL)
	{
		printf_s("学号:%d;\t姓名:%s;\t\n语文成绩1:%d;\t数学成绩2:%d;\t英语成绩3:%d;\t\n", move->student.StuNum, move->student.Name, move->student.Score1, move->student.Score2, move->student.Score3);
		move = move->next;
	}
}

        用于浏览所有学生信息。

void CountStudent(Node* head)				//统计学生总数;
{
	int count = 0;
	Node* move = head->next;				//指向首结点(数据结点);//只可用于普通的遍历中;
	while (move != NULL)
	{
		count++;
		move = move->next;
	}
	printf_s("学生总人数为:%d\n", count);
	Clear();
}

        通过链表计算学生总数。

void FindStuNum(Node*head)		//遍历;
{
	int StuNum = 0;
	printf_s("请输入学生学号:\n");
	scanf("%d", &StuNum);
	Node* move = head->next;
	while (move != NULL)
	{
		if (StuNum == move->student.StuNum)		//找到了;
		{
			printf_s("学号:%d;\t姓名:%s;\t\n语文成绩1:%d;\t数学成绩2:%d;\t英语成绩3:%d;\t\n", move->student.StuNum, move->student.Name, move->student.Score1, move->student.Score2, move->student.Score3);

			Clear();
			return;		//直接跳出函数;break只跳出循环;
		}
		move = move->next;
	}
	printf_s("未找到学生信息。\n");
	Clear();
}

        依据学号查找学生信息。

void FindName(Node* head)
{
	char name[10];
	printf_s("请输入学生姓名:\n");
	scanf("%s", &name);
	Node* move = head->next;
	while (move != NULL)
	{
		if (strcmp(name,move->student.Name)==0)	//找到了;strcmp(arr1, arr2)
		{
			printf_s("学号:%d;\t姓名:%s;\t\n语文成绩1:%d;\t数学成绩2:%d;\t英语成绩3:%d;\t\n", move->student.StuNum, move->student.Name, move->student.Score1, move->student.Score2, move->student.Score3);

			Clear();
			return;		//直接跳出函数;break只跳出循环;
		}
		move = move->next;
	}
	printf_s("未找到学生信息。\n");
	Clear();
}

        依据姓名查找。

void SortStu(Node* head)		//通过一个新的指针来控制遍历的次数;//Node*turn;
{
	int count = 0;		//示例:统计某科目不及格人数;
	Node* save = NULL;
	Node* move = NULL;
	printf_s("//  选择需要排序的科目:1.语文;2.数学;3.英语;\n");
	char m = _getch();
	switch (m)
	{
	case '1':
		for (Node* turn = head->next; turn->next != NULL; turn = turn->next)	//科目1;
		{
			for (move = head->next; move->next != save; move = move->next)		//从前到后,从小到大排序;
			{
				if (move->student.Score1 > move->next->student.Score1)
				{
					Stu temp = move->student;
					move->student = move->next->student;
					move->next->student = temp;
				}
			}
			save = move;	//保存最大的;
		}
		for (move = head->next; move->student.Score1 <= 60; move = move->next)
		{
			count++;
		}
		printf_s("//  科目1不及格的学生人数为:%d\n", count);
		break;
	case '2':
		for (Node* turn = head->next; turn->next != NULL; turn = turn->next)	//科目2;
		{
			for (move = head->next; move->next != save; move = move->next)		//从前到后,从小到大排序;
			{
				if (move->student.Score2 > move->next->student.Score2)
				{
					Stu temp = move->student;
					move->student = move->next->student;
					move->next->student = temp;
				}
			}
			save = move;	//保存最大的;
		}
		for (move = head->next; move->student.Score2 <= 60; move = move->next)
		{
			count++;
		}
		printf_s("//  科目2不及格的学生人数为:%d\n", count);
		break;
	case '3':
		for (Node* turn = head->next; turn->next != NULL; turn = turn->next)	//科目3;
		{
			for (move = head->next; move->next != save; move = move->next)		//从前到后,从小到大排序;
			{
				if (move->student.Score3 > move->next->student.Score3)
				{
					Stu temp = move->student;
					move->student = move->next->student;
					move->next->student = temp;
				}
			}
			save = move;	//保存最大的;
		}
		for (move = head->next; move->student.Score3 <= 60; move = move->next)
		{
			count++;
		}
		printf_s("//  科目3不及格的学生人数为:%d\n", count);
		break;
	default:
		printf_s("//  选择出现错误。\n");
	}
	PrintStu(head);

	Clear();
}

        计算不及格人数,这里手动输入了三门科目,但如果用更好的结构体操作可以做到更多科目,我想应该会有大佬能加上Excel,但并不是此文章的重点所在。

void ModifyStu(Node* head)
{
	printf_s("//  请输入要修改的学生学号:\n");
	int StuNum;
	scanf("%d", &StuNum);
	Node* move = head->next;
	while (move != NULL)
	{
		if (move->student.StuNum == StuNum)
		{
			printf_s("请输入学生的姓名、成绩1、成绩2、成绩3:\n");
			scanf("%s%d%d%d",  &move->student.Name, &move->student.Score1,&move->student.Score2,  &move->student.Score3);
			SaveStu(head);		//保存信息;
			printf_s("//  修改成功。\n");
			Clear();
			return;
		}
		move = move->next;
	}
	printf_s("//  未找到学生信息。\n");
	Clear();
}

        依据学号修改学生信息。

void DelStu(Node* head)
{
	printf_s("//  请输入要删除学生的学号:\n");
	int StuNum;
	scanf("%d", &StuNum);
	Node* move = head;
	while (move->next != NULL)		//更改其有关信息的前一个结点
	{
		if (move->next->student.StuNum == StuNum)
		{
			Node* p = move->next;
			move->next = move->next->next;		//跳过结点;
			free(p);
			p = NULL;
			SaveStu(head);
			printf_s("//  删除成功。\n");
			Clear();
			return;
		}
		move = move->next;
	}
	printf_s("//  未找到学生。\n");
	Clear();
}

        依据学号删除学生信息。

int main()
{
	//创建头结点;
	Node* head = malloc(sizeof(Node));		//头结点的地址;
	head->next = NULL;						//空的头结点方便后续操作;
	LoadStu(head);
	char m;									//通用选择数;

	while (1)
	{
		menu();								//打印菜单;
		char Chi = _getch();				//避免scanf产生的一些错误;
		switch (Chi)
		{
		case '1':							//录入学生成绩及有关信息;
			InStu(head);
			break;
		case '2':							//浏览所有学生成绩;
			PrintStu(head);
			CountStudent(head);	//计算学生人数;
			break;
		case '3':							//查询某位学生成绩;//学号、姓名;
			printf_s("//   请选择查找方式:1.学号查找;  2.姓名查找;    //\n");
			m = _getch();
			switch (m)
			{
			case '1':
				FindStuNum(head);
				break;
			case '2':
				FindName(head);
				break;
			default:
				printf_s("选择出错了!请重新输入。\n");
				Clear();
				break;
			}
			break;
		case '4':							//成绩排序与统计;
			SortStu(head);
			break;
		case '5':							//删除学生信息; //+修改信息;
			printf_s("// 请选择更改方式:1.修改学生信息;  2.删除学生信息;  //\n");
			m = _getch();
			switch (m)
			{
			case '1':
				ModifyStu(head);
				break;
			case '2':
				DelStu(head);
				break;
			default:
				printf_s("选择出错了!请重新输入。\n");
				Clear();
				break;
			}
			break;
		case '0':							//退出系统;
			system("cls");
			exit(0);
			break;
		default:							//意外......
			printf_s("选择出错了!请重新输入。\n");
			Clear();
			break;
		}
	}

	return 0;
}

        主函数。

#include <stdio.h>
#include <stdlib.h>		//为后续使用链表做准备;
#include <conio.h>
#include <string.h>


//学生信息;
typedef struct _Student		//使用typedef对struct _Student重命名
{
	int StuNum;
	char Name[10];
//	char Course1[5];	//设定固定科目;注释3行;
	int Score1;
//	char Course2[5];		
	int Score2;
//	char Course3[5];		
	int Score3;
}Stu;


//结点信息;		//链表结点;
typedef struct _Node
{
	Stu student;
	struct _Node* next;
}Node;

//有关函数声明;

void menu();		//打印菜单选项;
void Clear();		//暂停和清理;
void LoadStu(Node* head);	//程序启动时先读取文件;
void InStu(Node* head);		//录入学生信息;
void SaveStu(Node* head);	//存储学生信息;
void PrintStu(Node* head);	//打印ALL有关信息;
void CountStudent(Node* head);	//统计学生总人数;
void FindStuNum(Node* head);	//学号查找;
void FindName(Node* head);		//姓名查找;
void SortStu(Node* head);		//成绩排序与统计;
void DelStu(Node* head);		//删除学生信息;
void ModifyStu(Node* head);		//修改学生信息;

        头文件。 

一点解析:

        在此程序中,先定义一个头结点,始终指向链表的第一个空的头结点,链表各数据之间通过结点相连接,通过结点可直接访问链表中的数据。故再定义一个Node*move指针用来实现对链表的操作。设计结构如下:

        有关文件操作函数的一些内容:

fopen:
"r"    以“只读”方式打开文件。只允许读取,不允许写入。文件必须存在,否则打开失败。
"w"    以“写入”方式打开文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么清空文件内容(相当于删除原文件,再创建一个新文件)。
"a"    以“追加”方式打开文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么将写入的数据追加到文件的末尾(文件原有的内容保留)。
"r+"以“读写”方式打开文件。既可以读取也可以写入,也就是随意更新文件。文件必须存在,否则打开失败。
"w+"以“写入/更新”方式打开文件,相当于w和r+叠加的效果。既可以读取也可以写入,也就是随意更新文件。如果文件不存在,那么创建一个新文件;
    如果文件存在,那么清空文件内容(相当于删除原文件,再创建一个新文件)。
"a+"以“追加/更新”方式打开文件,相当于a和r+叠加的效果。既可以读取也可以写入,也就是随意更新文件。如果文件不存在,那么创建一个新文件;
    如果文件存在,那么将写入的数据追加到文件的末尾(文件原有的内容保留)。
"t"    文本文件。如果不写,默认为"t"。
"b"    二进制文件。

可参考:

        c语言链表详解(超详细)_Mr.Gzj的博客-CSDN博客

        学生成绩管理系统-哔哩哔哩_Bilibili

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值