学生管理系统(简易版)

前言

本管理系统是一个简易版本的学生管理系统,中间仍存在许多的问题,笔者目前展示的是未完全完成状态。后面增加功能后再进行更改。
这是本管理系统的大体逻辑:

一、文件的读取、写入和保存

结构体变量
typedef struct student
{
	char name[20];//姓名
	char num[20];//学号
	char iclass[10];//班级
	int chinese;//语文
	int math;//数学
	int english;//英语
	int sum;//总分
	char key[20];//密码
}stu;

typedef struct node
{
	struct student stu;
	struct node* next;
}node;

这里先给出我的结构体变量,由于教师和学生大致逻辑相同,这里就不多做展示了。

1.1文件的读取和写入

void ReadStudent()
{
	char file[100] = { "class.txt" };
	FILE* fp = fopen(file, "r");
	node* move = head/*>next*/;
	if (fp == NULL)
	{
		fp = fopen(file, "w+");//如果该文件不存在,则将该文件创建出来。
		fclose(fp);
	}
	else
	{
		while (!feof(fp))
		{ 
			node* p = (node*)malloc(sizeof(node));
			p->next = NULL; 
			fscanf(fp, "%s %s %s %d %d %d %s\n", p->stu.name, p->stu.num,
				p->stu.iclass, &p->stu.chinese, &p->stu.math, &p->stu.english, p->stu.key);
			while (move->next != NULL) {
				move = move->next;
			}
			p->stu.sum = p->stu.chinese + p->stu.math + p->stu.english;
			move -> next = p;
		}
		printf("读取成功\n");
	}
	fclose(fp);
}
由于总分是三科成绩之和,所以笔者并未将其存入文件中,在每次打开文件时做加法即可。

这里我将所有学生信息存储在一个文件中,直接将所有信息读取至文件中即可。

1.2文件的写入

void SaveInfo()
{
	FILE* fp = fopen("class.txt", "w");
	if (fp == NULL)
	{
		printf("文件打开失败!\n");
	}
	node* p = head->next;
	while (p)
	{
		fprintf(fp, "%s %s %s %d %d %d %s\n", p->stu.name, p->stu.num,
			p->stu.iclass, p->stu.chinese, p->stu.math, p->stu.english, p->stu.key);
		p = p->next;
	}
	fclose(fp);
}

每次保存学生信息都将整个链表保存一遍,每遍历一个节点,就用fprintf将该节点保存至文件之中。由于文件仅有一个,笔者并未按班级分开保存,故而信息的保存不用判断,较为简单。

二、 管理系统功能

在这里插入图片描述

主界面

2.1登录界面

void LoginBackGround()
{
	printf("欢迎来到后台登录界面!");
	char a[7] = { "123456" };
	char b[7] = { 0 };
	for (int j = 3; j > 0; j--)
	{
		printf("\n密码:");
		int i = 0;
		while (1)
		{
			key[i] = getch();
			if (key[i] == '\r')
				break;
			if (key[i] == '\b' && i > 0)
			{
				printf("\b");
				_putch(' ');
				printf("\b");
				key[--i] = '\0';
				continue;
			}
			if (key[i] == '\b' && i == 0)
			{
				printf("\b");
				_putch(' ');
				printf("\b");
				i = -1;
				continue;
			}
			printf("*");
			i++;
		}
		key[i] = '\0';
		if (strcmp(key, a) == 0)
		{
			printf("\n您的密码输入正确,即将进入个人界面!\n");
			system("pause");
			system("cls");
			Menu3();
		}
		else
		{
			if (j == 1)
				break;
			printf("您的密码输入有误,请重新输入。");
			printf("\n请注意您还有%d次机会", j-1);
		}
	}
	printf("您已经三次输入错误,即将返回主页面");
	return;
}

笔者这里隐式输入中只实现了回删并重新输入,并未用ASCII码表限制一些不可用符号的输入,并未完全掌握这里的知识,过段时间学会后再加上。

2.2后台功能的实现

后台界面显示

后台界面如图所示

2.2.1增加学生

void AddStudent()
{
	printf("注意:请输入正确的班级及学号,不然无法增加学生!\n");
	node* move = head;
	node* fresh = (node*)malloc(sizeof(node));
	fresh->next = NULL;
	printf("请输入您要增加学生的姓名:");
	scanf("%s", fresh->stu.name);
	strcpy(name, fresh->stu.name);
	while (move->next  != NULL)
	{
		if (strcmp(move->stu.name, fresh->stu.name) == 0)
		{
			printf("\n该学生已被系统录入,请勿重新录入!\n");
			system("pause");
			system("cls");
			return;
		}
		move = move->next;
	}
	printf("\n请依次输入该学生学号,班级,语文成绩,数学成绩,英语成绩:\n");
	scanf("%s %s %d %d %d", fresh->stu.num, fresh->stu.iclass, &fresh->stu.chinese,&fresh->stu.math, &fresh->stu.english);
	fresh->stu.sum = fresh->stu.chinese + fresh->stu.math + fresh->stu.english;
	if (strcmp(fresh->stu.iclass, "网络1班") == 0 || strcmp(fresh->stu.iclass, "网络2班") == 0 || strcmp(fresh->stu.iclass, "网络3班") == 0)
	{
		strcpy(fresh->stu.key, "000000");
		move->next = fresh;
		printf("增加成功!");
		return;
	}
	else {
		printf("没有这个班级,无法增加该学生!\n");
		printf("即将返回上个页面!\n");
		system("pause");
		system("cls");
		Menu3();
	}
}

由于笔者的问题,所有班级学生姓名不能重复,后期在增加判断姓名的功能。
下文中先判断班级是否是存在的班级,如果不存在该班级,也无法录入该学生信息,避免出现录入不存在班级的问题。同时由于教师注册操作和增加学生实现方式相同,在这里就不过多做展示。

2.2.2修改学生信息

void ChangeStudent()
{
	node* move = head;
	printf("请输入您要更改学生的姓名:");
	scanf("%s", name);
	while (move->next  != NULL)
	{
		if (strcmp(name, move->stu.name) == 0)
		{
			printf("已找到该名学生,请输入您要更改的内容:");
			printf("1.学号    2.班级   \n3.语文    4.数学    5.英语\n");
			int n;// score;
			scanf("%d", &n);
			int score = 0;
			switch(n)
			{
			case 1:
				printf("请输入该名学生新的学号:");
				char num[20];
				scanf("%s", num);
				strcpy(move->stu.num, num);
				printf("\n修改成功!\n");
				return;
				break;
			case 2:
				printf("请输入该名学生新转入的班级:");
				char iclass[20];
				scanf("%s", iclass);
				strcpy(move->stu.iclass, iclass);
				printf("修改成功!");
				return;
				break;
			case 3:
				printf("请输入该名学生正确的语文成绩:");
				scanf("%d", &score);
				move->stu.sum -= move->stu.chinese;
				move->stu.chinese = score;
				move->stu.sum += move->stu.chinese;
				printf("修改成功!");
				return;
				break;
			case 4:
				printf("请输入该名学生正确的数学成绩:");
				scanf("%d", &score);
				move->stu.sum -= move->stu.math;
				move->stu.math = score;
				move->stu.sum += move->stu.math;
				printf("修改成功!");
				return;
				break;
			case 5:
				printf("请输入该名学生正确的英语成绩:");
				scanf("%d", &score);
				move->stu.sum -= move->stu.english;
				move->stu.english = score;
				move->stu.sum += move->stu.english;
				printf("修改成功!");
				return;
				break;
			default:
				printf("没有这个选项,请重新输入!\n");
				return;
				break;
			}
		}
		move = move->next;
	}
	printf("未找到该名学生,请确您输入的信息!");
}

由于查询学生信息仅仅是将学生查询出后打印该学生信息,查询操作在修改学生信息中有体现,故该功能也不做展示。修改操作即是将想要修改的一项更改,将链表中的东西修改以后,将该函数执行完成后一定要将链表的内的信息即使保存在文件中。即使用一次文件的写入函数。

2.2.3查询年纪成绩

该操作要对成绩进行排序,笔者为了练习链表的排序,在这里用了三种不同的排序方法分别排序了我的三科成绩。由于任一一种排序均可实现对成绩的排序功能,笔者这里只放一种排序进行展示,其余的排序方法不做展示。

void Bubble(node* head)//冒泡排序
{
	int i, count = 0, num;
	node* p = head;
	node* q, *tail;
	while (p->next != NULL)
	{
		count++;
		p = p->next;
	}
	for (int i = 0; i < count - 1; i++)
	{
		num = count - i - 1;
		q = head->next;
		p = q->next;
		tail = head;
		while (num--)
		{
			if (q->stu.sum < p->stu.sum)
			{
				q->next = p->next;
				p->next = q;
				tail->next = p;
			}//交换节点
			tail = tail->next;
			q = tail->next;
			p = q->next;
		}
	}
}

void ListStudent()//打印学生信息
{
	node* move = head->next;
	printf("姓名\t班级\t\t学号\t语文\t数学\t英语\t总分\n");
	while (move != NULL)
	{
		move->stu.sum = move->stu.chinese + move->stu.math + move->stu.english;
		printf("%s\t%s\t\t%s\t%d\t%d\t%d\t%d\n", move->stu.name, move->stu.iclass, move->stu.num,
			move->stu.chinese, move->stu.math, move->stu.english, move->stu.sum);
		move = move->next;
	}
}

由于笔者没有将所有信息专门拿出来放在一个链表中进行排序,直接对原来链表进行排序并更改链表顺序,故而每次排序后链表顺序都会改变。如果想让原有链表输入学生信息顺序不变,请使用一个新的链表放置学生信息,并进行学生排序。

其余几个功能的实现方式都在这三个功能实现是被使用,故笔者在这里不展示其余几个功能的代码,避免浪费空间时间。

2.3学生界面功能实现

在这里插入图片描述

2.3.1学生注册

该功能不放在学生界面内,而是主界面。但涉及到学生自己操作,故而放在这里进行讲解。

void LoginStudent()
{
	printf("注意:本系统只能本年纪学生注册,其余人无法注册!\n");
	printf("注意:初始密码不能当作您的密码使用,否则无法登录!\n");
	printf("注意:请输入6-18位之间仅含数字和字母的密码!\n");
	node* move = head->next;
	printf("请输入您的姓名,学号,班级:");
	char iclass[20], num[20];
	scanf("%s %s %s", name, num, iclass);
	int i = 0;
	while (move != NULL)
	{
		if (strcmp(name, move->stu.name) == 0&& strcmp(num, move->stu.num) == 0&& strcmp(iclass, move->stu.iclass) == 0)
		{
			printf("您的信息全部正确,请修改您的密码!\n");
			if (strcmp(move->stu.key ,"000000")==0)
			{
				printf("请输入您的密码:");
				int i = 0;
				while (1)
				{
					key[i] = getch();
					if (key[i] == '\r')
						break;
					if (key[i] == '\b' && i > 0)
					{
						printf("\b");
						_putch(' ');
						printf("\b");
						key[--i] = '\0';
						continue;
					}
					if (key[i] == '\b' && i == 0)
					{
						printf("\b");
						_putch(' ');
						printf("\b");
						i = -1;
						continue;
					}
					i++;
					printf("*");
				}
				key[i] = '\0';
				if (strcmp(key, move->stu.key) == 0)/*不能学生输入的密码
				还是初始密码,不然学生注册相当于没有完成,仍然登陆不上学生界面。*/
				{
					printf("\n您输入的密码为初始密码,不能用初始密码作为您的密码\n");
					printf("即将返回主页面\n");
					system("pause");
					system("cls");
					Menu();
				}
				if (strlen(key) < 6 || strlen(key) > 18) {/*控制密码长度位于
				规定的范围内。*/
					printf("\n请输入6-18位的密码!\n");
					printf("即将返回主页面\n");
					system("pause");
					system("cls");
					Menu();
				}
				strcpy(move->stu.key, key);
				printf("\n注册成功!");
				system("pause");
				system("cls");
				Menu();
			}
			else
			{
				printf("该生已完成注册,请勿重复注册!");
				return;
			}
		}
		move = move->next;
	}
	printf("系统中未查询到该名学生,请提醒管理员录入学生信息!");
	system("pause");
	system("cls");
}

学生注册是由于增加学生后学生密码为初始密码,学生必须先进行注册更改密码,不能使用初始密码进行登录,避免出现别人查看该学生信息的情况而进行的设立。(虽然有点鸡肋,但存在一定有意义!!!)

2.3.2学生界面

void Menu1(node* move)
{
	printf("*********************************************\n");
	printf("----------------【学生界面】-----------------\n");
	printf("*********************************************\n\n");
	printf("****************系统功能菜单*****************\n");
	printf("*                                           *\n");
	printf("*\t\t┌───────────────┐\t    *\n");
	printf("*\t\t│1.查看个人信息 │\t   *\n");
	printf("*\t\t│2.更改密码\t│\t    *\n");
	printf("*\t\t│3.返回主界面\t│\t    *\n");
	printf("*\t\t└───────────────┘\t    *\n");
	printf("*                                           *\n");
	printf("******************欢迎使用*******************\n\n");
	int n;
	while (1)
	{
		printf("请输入您的选择:");
		scanf("%d", &n);
		switch (n)
		{
		case 1:
			printf("姓名:%s\n", move->stu.name);
			printf("班级:%s\n", move->stu.iclass);
			printf("学号:%s\n", move->stu.num);
			printf("语文:%d\n", move->stu.chinese);
			printf("数学:%d\n", move->stu.math);
			printf("英语:%d\n", move->stu.english);
			printf("总分:%d\n", move->stu.sum);
			break;
		case 2:
			printf("请输入您的新密码:");
			scanf("%s", key);
			strcpy(move->stu.key, key);
			SaveInfo();
			system("pause");
			printf("更改成功!\n");
			break;
		case 3:
			system("pause");
			system("cls");
			Menu();
			break;
		default:
			printf("\n没有这个选项,请重新选择!\n");
			break;
		}
	}
}

由于学生界面实现的功能比较简单,故而仅使用一个函数来进行实现。
该函数已经传入了该学生信息的节点,故而直接对该节点进行更改,而后密码保存一定还要存入文件中。

2.4教师界面

在这里插入图片描述

2.4.1班级成绩的排序

void OurClass(Node* Move, node* head)
{
	node* move = head;
	node* head1 = (node*)malloc(sizeof(node));
	head1->next = NULL;
	node* move1 = head1;//定义一个新的链表头
	while (move->next != NULL)
	{ 
		if (strcmp( Move->tea.iclass ,move->stu.iclass ) == 0)
		{
			move1 = head1;
			node* move2 = (node*)malloc(sizeof(node));
			move2->next = NULL;
			move2->stu = move->stu ;
			while (move1->next != NULL)
			{
				move1 = move1->next;
			}
			move1->next = move2;
		}
		move = move->next;
	}//将该班学生信息放置进新创建的链表顺序中
	Bubble(head1);//冒泡排序
	move1 = head1->next ;
	printf("姓名\t班级\t\t学号\t语文\t数学\t英语\t总分\n");
	while (move1/*->next*/  != NULL)
	{
		printf("%s\t%s\t\t%s\t%d\t%d\t%d\t%d\n", move1->stu.name, move1->stu.iclass, move1->stu.num,
			move1->stu.chinese, move1->stu.math, move1->stu.english, move1->stu.sum);
		move1 = move1->next;
	}//打印该班学生信息
}

该函数即实现了不改变原来链表顺序下对于当前班级排序的功能,即将该班级学生消息取出放置在一个新的链表中,而后对于该链表进行排序即可。
由于排序使用函数与全年级学生排序使用函数相同,这里笔者只对该班总成绩进行排序,没有对单科成绩进行排序。

2.4.2教师密码更改

由于和学生本人更改自己密码操作相同,这里笔者不多做赘述。

三、收获和问题

3.1收获

  • 对与链表的排序使用的更加熟练,将所学的快速,选择,冒泡三种链表的排序方法运用在该管理系统内,在实现功能同时也更好的熟练使用该几项排序。
  • feof函数

feof()是检测流上的文件结束符的函数,如果文件结束,则返回非0值,否则返回0

3.2问题

  • 许多地方没有考虑到逻辑的问题,没有在代码中警告出现一些不符合常理的情况。
  • 有些功能的实现考虑并不全面,对于链表的使用熟练但并不精通有些地方的底层逻辑。
  • 10
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值