学生信息管理系统-教师端和学生端双客户端部分功能实现(开源)

这是一个使用C语言编写的学生成绩管理系统,包括学生和教师两端的登录、注册功能,以及对学生成绩的增删查改、排序和统计等功能。系统使用文件存储数据,并实现了简单的密码安全性处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

工作环境:VISUAL STUDIO 2017

以下为代码部分

本代码仅供学习用途,禁止照搬照抄!

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <time.h>
#include<String.h>
#include<ctype.h>//包含数字,字母判断的函数

typedef struct The_users { //typedef 可以定义结构体别名
	char name[100]; 		//账号,为了防止数组越界将数组范围定义更大一些
	char pwd[100]; 		//密码
	char phone[100];		//手机号
	int situation;  //状态值
} Users;	//该结构体别名
//以下为打印菜单部分函数
void Option2(int);	//学生菜单switch
void Register();	//学生注册模块
void Login();		//学生登录模块
void ReadaFile(char *filename);//文件初始化
void Login2();//老师登陆模块
void Register2();//老师注册模块
void Option3(int option);//老师菜单switch
void caidan3();//打印菜单-教师端
void caidan1();//打印菜单-选择端
void caidan2();//打印菜单-学生端
void Option1(int option);//总菜单switch
char Stuname[10] = { 'S', 'u', 's', 'e', 'r', 's', '.', 't', 'x', 't' }; //学生文档路径
char Teachername[10] = { 'T', 'u', 's', 'e', 'r', 's', '.', 't', 'x', 't' }; //老师文档路径
void Lockzhanghao(char *filename, Users b);//3次锁号函数,有bug未能实现
void gongneng2();//教师端功能
void gongneng();//学生端功能
void gongnengswitch2(int option);//教师端switch
void gongnengswitch(int option);//学生端switch
//以下为系统功能实现部分的函数
void printBubblesort2(struct Node* StudentNode);
struct Node* SearchNode2(struct Node* StudentNode, char* name);
void PrintAverage80(struct Node* StudentNode);
void PrintAverage(struct Node* StudentNode);//计算并打印平均数
void printBubblesort(struct Node* StudentNode);//冒泡排序
void InsertNode();
struct Node* CreatNode();//创建头结点
struct Node* CreatNewNode(struct Student data);//创建新结点
void CreatNodeList(struct Node* HeadNode, struct Student data);
void deletestudent();
void deletenode(struct Node* headnode, char* name);
struct Node* SearchNode(struct Node* StudentNode, char* name);
void PrintNode(struct Node* StudentNode);
void PrintList(struct Node* StudentNode);
void ReadFromFile(char* filename, struct Node* StudentNode);
void SaveFile1(char* filename, struct Node* StudentNode);
struct Node* StudentNode;//学生信息节点StudentNode(结构体变量),本程序该全局变量作为头节点
char S1[5] = { 's','.','t','x','t' };//文件的保存路径
//以下为封面函数
void welcome();//打印封面
void cursor(int x, int y);//定位光标
void Windowstime();//获得电脑时间
void AppearCursor();//光标出现
void HideCursor();//隐藏光标
void PrintExit();//退出封面

struct Student {//定义学生信息(结构体类型)
	char name[20];//姓名
	char sex[20];//性别
	char number[20];//学号
	float grade1;//第一科
	float grade2;//第二科
	float grade3;//第三科

};
struct Node {//定义学生信息节点(结构体类型)
	struct Student data;//数据域
	struct Node* Next;//指针域
};

int i = 0, flag = 1, menu = 0;
int main() {//主函数
	welcome();
	system("cls");
	AppearCursor();
	caidan1();//主函数只有菜单1,然后在各个嵌套函数中实现功能
}

void ReadaFile(char *filename) {//创建/判断是否有文件生成
	FILE* fp = fopen(filename, "r");
	if (fp == NULL) {
		fp = fopen(filename, "w");
	}
	fclose(fp);
}


//通过Option2函数接收代表功能对应的数字来调用其他功能函数
void Option2(int option) {//学生菜单
	switch (option) {
	case 1:
		Login();
		break;
	case 2:
		Register();
		break;
	case 3:
		system("cls");
		caidan1();
		//return;
		//flag = 0;		//flag置0,结束主函数循环(也可以不要此句)
		exit(0);
	}
}

/*
  注册账号模块
 */
void Register() {
	system("cls");//换页
	Users a, b;		//定义两个临时用结构体变量,a用于写入文件
	a.situation = 0;
	FILE *fp;
	char temp_pwd[20];
	//int count = 0;
	printf("\n\t\t欢迎来到注册界面!\n");
	printf("____________________________________________________________________\n");
	printf("[注册要求]");
	printf("\n\n\t\t(1) 用户名必须为英文字母或英文字母+数字,总长度不超过8个字符\n\n");
	printf("\t\t(2) 密码不低于6位,总长度不超过10个字符\n\n");
	printf("____________________________________________________________________");
	fp = fopen("Susers.txt", "r");
	fread(&b, sizeof(Users), 1, fp); 	//读入一个用户信息,用于在下面查找注册的账号名是否存在
	printf("\n\t\t请设置账号:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
	scanf("%s", a.name);//这里有个bug,会导致数组越界
	while (1) {
		int len_name = strlen(a.name);
		int count = 0;//遍历数字长度
		for (int j = 0; j < len_name; j++) {
			if (isdigit(a.name[j])) {	//判断账号是否仅由纯数字组成
				count++;
			}
		}
		if (count == len_name) {
			printf("\t\t非法用户名 !请重新注册!\n");//如果由纯数字组成,则返回
			Sleep(1000);
			fclose(fp);
			system("cls");
			return;
		}
		if (len_name > 8) {
			printf("\t\t非法用户名 !请重新注册!\n");//不能输入中文符号,不然会导致程序重启
			Sleep(1000);
			fclose(fp);
			system("cls");
			return;
		}
		for (int j = 0; j < len_name; j++) {
			if (!isalnum(a.name[j])) {	//判断是否仅由字母与数字组成账号长度
				printf("\t\t非法用户名 !请重新注册!\n");//不能输入中文符号,不然会导致程序重启
				Sleep(1000);
				fclose(fp);
				system("cls");
				return;
			}
		}
		if (strcmp(a.name, b.name)) { 	//如果注册账号不存在
			if (!feof(fp)) {  						//如果未到文件尾
				fread(&b, sizeof(Users), 1, fp);	//继续读入下一个用户信息
			}
			else {
				break;		//检查完毕,跳出
			}
		}
		else {	//如果此账号已存在,退出
			printf("\t\t此用户名已存在!请重新注册!\n");
			Sleep(1000);
			fclose(fp);
			system("cls");
			return;
		}
	}
	printf("\t\t请输入您的手机号:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
	scanf("%s", a.phone);
	int time = 2;
	do {
		printf("\t\t请设置密码:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
		i = 0;
		/*
		  以下代码段用于将输入的明文替换为'*'
		  起到保护作用,但仍存一点bug
		 */
		do {
			a.pwd[i] = _getch();
			if (a.pwd[i] == '\r')
				break;
			if (a.pwd[i] == '\b') {//如果退格
				if (i == 0) {
					printf("\a");
					continue;
				}
				i = i - 1;
				printf("\b");
			}
			else {
				i = i + 1;
				printf("*");
			}
		} while (a.pwd[i] != '\n');	//当接收到回车符时完成密码接收
		a.pwd[i] = '\0';//遍历后的结束位
		int len_password = strlen(a.pwd);
		if (len_password < 6 || len_password>10) {
			printf("\n\t\t密码输入格式错误!请重新注册!\n");
			Sleep(1000);
			fclose(fp);
			system("cls");
			return;
			break;
		}
		printf("\n");
		printf("\t\t请确认密码:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
		/*
		  再接收一次密码
		  用于验证,防止用户设置密码出错
		 */
		i = 0;
		do {
			temp_pwd[i] = _getch();
			if (temp_pwd[i] == '\r')
				break;
			if (temp_pwd[i] == '\b') {
				if (i == 0) {
					printf("\a");
					continue;
				}
				i = i - 1;
				printf("\b");
			}
			else {
				i = i + 1;
				printf("*");
			}
		} while (temp_pwd[i] != '\n');
		temp_pwd[i] = '\0';
		printf("\n");
		if (!strcmp(a.pwd, temp_pwd)) {	//如果两次输入的密码相同就可以注册了
			fp = fopen("Susers.txt", "a");	// a-向文件尾部追加写入
			fwrite(&a, sizeof(Users), 1, fp);//二进制输入
			printf("\t\t账号注册成功!\n");
			Sleep(1000);
			fclose(fp);
			system("cls");
			return;
		}
		else {
			if (time != 0) {
				printf("\n\t\t两次输入的密码不相同!\t请重新输入(剩余%d次机会)\n", time);
				time--;
				continue;	//如果本次密码匹配不相同跳出,进入下一次输入
			}
			else {
				printf("\n\t\t多次输入错误,即将退出!");
				Sleep(1000);
				fclose(fp);
				system("cls");
				return;
			}
		}
	} while (time >= 0);
}

/*
  学生登录模块
 */
void Login() {
	system("cls");//换页
	Users a, b;	//定义结构体The_users别名
	FILE *fp;
	printf("\t\t\n欢迎来到登录界面!\n\n");
	printf("\t\t请输入账号/手机号:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
	scanf("%s", a.name);//a是用户输入的账户
	int len_name = strlen(a.name);
	for (int j = 0; j <= len_name; j++) {
		a.phone[j] = a.name[j];//将输入值赋值给phone
	}
	printf("\t\t请输入密码:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
	i = 0;
	/*
	  采用相同的方法掩盖明文密码
	 */
	do {
		a.pwd[i] = _getch();
		if (a.pwd[i] == '\r')
			break;
		if (a.pwd[i] == '\b') {
			if (i == 0) {
				printf("\a");
				continue;
			}
			i = i - 1;
			printf("\b");
		}
		else {
			i = i + 1;
			printf("*");
		}
	} while (a.pwd[i] != '\n' && i < 20);
	a.pwd[i] = '\0';//遍历后的结束位
	printf("\n");
	fp = fopen("Susers.txt", "r+b");
	while (1) {
		fread(&b, sizeof(Users), 1, fp); //读入一个结构体字符块 写入b
		if ((strcmp(a.name, b.name) == 0) && (!feof(fp))) {      	//如果有此账号
			break;								//此账号已经注册 可以登录
		}
		else {
			if ((strcmp(a.phone, b.phone) == 0) && (!feof(fp))) {
				break;
			}

			else {
				if (!feof(fp)) { //如果文件没有读完
					continue;
				}
				else {
					printf("\t\t账号/手机号或密码错误!\n");
					fclose(fp);
					Sleep(1000);
					system("cls");
					return;
				}
			}
		}
	}
	if (b.situation != 3) {//如果没有输错3次
		if (strcmp(a.pwd, b.pwd) == 0) {        /*如果密码匹配*/
			system("cls");
			printf("\t\t登录成功!欢迎使用!\n");
			Sleep(1000);
			fclose(fp);
			system("cls");
			gongneng();
		}
		else {
			printf("\t\t账号或密码错误!……\n");
			fclose(fp);
			// Lockzhanghao(Stuname,b);//3次锁号函数,有bug已停用
			Sleep(1000);
			system("cls");
			return;
		}
	}
	else {
		printf("\t\t由于密码输错3次,该账号已锁定!……");
		fclose(fp);
		Sleep(1000);
		system("cls");
		return;
	}
}



void caidan3() {
	while (flag) {
		ReadaFile(Teachername);
		do {
			printf("-----------------------------教师端-学生信息管理系统登陆界面--------------------------------------\n");
			printf("\t\t\t\t       菜单栏\n");
			printf("\t\t\t\t       ①登录\n");
			printf("\t\t\t\t       ②注册\n");
			printf("\t\t\t\t       ③返回上一页\n");
			printf("-----------------------------------------------------------------------------------\n");
			printf("\n");
			printf("\t\t\t\t   请输入选项:[\t]\b\b\b\b\b");
			scanf("%d", &menu);
			if (menu > 3 || menu < 1) {
				printf("输入错误,请重新输入!");
				Sleep(1000);
				system("cls");
			}
		} while (menu > 3 || menu < 1);
		Option3(menu);
	}
}

void caidan1() {
	while (flag) {
		do {
			//cursor(34, 8);
			
			printf("-----------------------------学生信息管理系统登陆界面--------------------------------------\n");
			//cursor(53, 12);
			printf("\t\t\t\t       菜单栏\n");
			printf("\t\t\t\t       ①学生端\n");
			printf("\t\t\t\t       ②教师端\n");
			printf("\t\t\t\t       ③退出系统\n");
			printf("-----------------------------------------------------------------------------------\n");
			printf("\n");
			//cursor(28, 16);
			printf("\t\t\t\t   请输入选项:[\t]\b\b\b\b\b");
			scanf("%d", &menu);
			if (menu > 3 || menu < 1) {
				printf("输入错误,请重新输入!");
				Sleep(1000);
				system("cls");
			}
		} while (menu > 3 || menu < 1);
		Option1(menu);
	}
}

void Option1(int option) {//主菜单
	switch (option) {
	case 1:
		system("cls");//换页
		caidan2();
		break;
	case 2:
		system("cls");//换页
		caidan3();
		break;
	case 3:
		system("cls");
		printf("\n\t\t谢谢使用!\n");
		//flag = 0;		//flag置0,结束主函数循环(也可以不要此句)
		PrintExit();
		exit(0);
	}
}

//通过Option3函数接收代表功能对应的数字来调用其他功能函数
void Option3(int option) {//老师菜单
	switch (option) {
	case 1:
		Login2();
		break;
	case 2:
		Register2();
		break;
	case 3:
		system("cls");
		caidan1();
		//return ;
		//flag = 0;		//flag置0,结束主函数循环(也可以不要此句)

	}
}

/*
  注册账号模块
 */
void Register2() {
	system("cls");//换页
	Users a, b;		//定义两个临时用结构体变量,a用于写入文件
	a.situation = 0;
	FILE *fp;
	char temp_pwd[20];
	//int count = 0;
	printf("\n\t\t欢迎来到注册界面!\n");
	printf("____________________________________________________________________\n");
	printf("[注册要求]");
	printf("\n\n\t\t(1) 用户名必须为英文字母或英文字母+数字,总长度不超过8个字符\n\n");
	printf("\t\t(2) 密码不低于6位,总长度不超过10个字符\n\n");
	printf("____________________________________________________________________");
	printf("\n\t\t请设置账号:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
	fp = fopen("Tusers.txt", "r");
	fread(&b, sizeof(Users), 1, fp); 	//读入一个用户信息,用于在下面查找注册的账号名是否存在
	scanf("%s", a.name);
	while (1) {
		int len_name = strlen(a.name);//接受字符串长度
		int count = 0;//遍历数字长度
		for (int j = 0; j < len_name; j++) {
			if (isdigit(a.name[j])) {	//判断账号是否仅由纯数字组成
				count++;
			}
		}
		if (count == len_name) {
			printf("\t\t非法用户名 !请重新注册!\n");
			Sleep(1000);
			fclose(fp);
			system("cls");
			return;
		}
		if (len_name > 8) {
			printf("\t\t非法用户名 !请重新注册!\n");
			Sleep(1000);
			fclose(fp);
			system("cls");
			return;
		}
		for (int j = 0; j < len_name; j++) {
			if (!isalnum(a.name[j])) {	//判断是否仅由字母与数字组成与账号长度
				printf("\t\t非法用户名 !请重新注册!\n");//不能输入中文符号,不然会导致程序重启
				Sleep(1000);
				fclose(fp);
				system("cls");
				return;
			}
		}
		if (strcmp(a.name, b.name)) { 	//如果注册账号不存在
			if (!feof(fp)) {  						//如果未到文件尾
				fread(&b, sizeof(Users), 1, fp);	//继续读入下一个用户信息
			}
			else {
				break;		//检查完毕,跳出
			}
		}
		else {	//如果此账号已存在,退出
			printf("\t\t此用户名已存在!请重新注册!\n");
			Sleep(1000);
			fclose(fp);
			system("cls");
			return;
		}
	}
	printf("\t\t请输入您的手机号:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
	scanf("%s", a.phone);
	int time = 2;
	do {
		printf("\t\t请设置密码:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
		i = 0;
		/*
		  以下代码段用于将输入的明文替换为'*'
		  起到保护作用,但仍存一点bug
		 */
		do {
			a.pwd[i] = _getch();
			if (a.pwd[i] == '\r')
				break;
			if (a.pwd[i] == '\b') {//如果退格
				if (i == 0) {
					printf("\a");
					continue;
				}
				i = i - 1;
				printf("\b");
			}
			else {
				i = i + 1;
				printf("*");
			}
		} while (a.pwd[i] != '\n' && i < 20);	//当接收到回车符或者密码长度已够时完成密码接收
		a.pwd[i] = '\0';//遍历后的结束位(很重要)
		int len_password = strlen(a.pwd);
		if (len_password < 6 || len_password>10) {
			printf("\n\t\t密码输入格式错误!请重新注册!\n");
			Sleep(1000);
			fclose(fp);
			system("cls");
			return;
			break;
		}
		printf("\n");
		printf("\t\t请确认密码:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
		/*
		  再接收一次密码
		  用于验证,防止用户设置密码出错
		 */
		i = 0;
		do {
			temp_pwd[i] = _getch();
			if (temp_pwd[i] == '\r')
				break;
			if (temp_pwd[i] == '\b') {
				if (i == 0) {
					printf("\a");
					continue;
				}
				i = i - 1;
				printf("\b");
			}
			else {
				i = i + 1;
				printf("*");
			}
		} while (temp_pwd[i] != '\n' && i < 20);
		temp_pwd[i] = '\0';
		printf("\n");
		if (!strcmp(a.pwd, temp_pwd)) {	//如果两次输入的密码相同就可以注册了
			fp = fopen("Tusers.txt", "a");	// a-向文件尾部追加写入
			fwrite(&a, sizeof(Users), 1, fp);//二进制输入
			printf("\t\t账号注册成功!\n");
			Sleep(1000);
			fclose(fp);
			system("cls");
			return;
		}
		else {
			if (time != 0) {
				printf("\n\t\t两次输入的密码不相同!\t请重新输入(剩余%d次机会)\n", time);
				time--;
				continue;	//如果本次密码匹配不相同跳出,进入下一次输入
			}
			else {
				printf("\n\t\t多次输入错误,即将退出!");
				Sleep(1000);
				fclose(fp);
				system("cls");
				return;
			}
		}
	} while (time >= 0);
}

/*
  教师登录模块
 */
void Login2() {
	system("cls");//换页
	Users a, b;	//定义结构体The_users别名
	FILE *fp;
	printf("\t\t\n欢迎来到登录界面!\n\n");
	printf("\t\t请输入账号/手机号:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
	scanf("%s", a.name);//a是用户输入的账户
	int len_name = strlen(a.name);
	for (int j = 0; j <= len_name; j++) {
		a.phone[j] = a.name[j];//将输入值赋值给phone
	}
	printf("\t\t请输入密码:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
	i = 0;
	/*
	  采用相同的方法掩盖明文密码
	 */
	do {
		a.pwd[i] = _getch();
		if (a.pwd[i] == '\r')
			break;
		if (a.pwd[i] == '\b') {
			if (i == 0) {
				printf("\a");
				continue;
			}
			i = i - 1;
			printf("\b");
		}
		else {
			i = i + 1;
			printf("*");
		}
	} while (a.pwd[i] != '\n' && i < 20);
	a.pwd[i] = '\0';//遍历后的结束位
	printf("\n");
	fp = fopen("Tusers.txt", "r+b");
	while (1) {
		fread(&b, sizeof(Users), 1, fp); //读入一个结构体字符块 写入b
		if ((strcmp(a.name, b.name) == 0) && (!feof(fp))) {      	//如果有此账号
			break;								//此账号已经注册 可以登录
		}
		else {
			if ((strcmp(a.phone, b.phone) == 0) && (!feof(fp))) {
				break;
			}

			else {
				if (!feof(fp)) { //如果文件没有读完
					continue;
				}
				else {
					printf("\t\t账号/手机号或密码错误!\n");
					fclose(fp);
					Sleep(1000);
					system("cls");
					return;
				}
			}
		}
	}
	if (b.situation != 3) {//如果没有输错3次
		if (strcmp(a.pwd, b.pwd) == 0) {        /*如果密码匹配*/
			system("cls");
			printf("\t\t登录成功!欢迎使用!\n");
			Sleep(1000);
			fclose(fp);
			system("cls");
			gongneng2();
		}
		else {
			printf("\t\t账号或密码错误!……\n");
			fclose(fp);
			// Lockzhanghao(Teachername,b);//3次锁号函数,有bug已停用
			Sleep(1000);
			system("cls");
			return;
		}
	}
	else {
		printf("\t\t由于密码输错3次,该账号已锁定!……");
		fclose(fp);
		Sleep(1000);
		system("cls");
		return;
	}
}


void caidan2() {
	while (flag) {
		ReadaFile(Stuname);
		do {
			printf("-----------------------------学生端-学生信息管理系统登陆界面--------------------------------------\n");
			printf("\t\t\t\t       菜单栏\n");
			printf("\t\t\t\t       ①登录\n");
			printf("\t\t\t\t       ②注册\n");
			printf("\t\t\t\t       ③返回上一页\n");
			printf("-----------------------------------------------------------------------------------\n");
			printf("\n");
			printf("\t\t\t\t   请输入选项:[\t]\b\b\b\b\b");
			scanf("%d", &menu);
			if (menu > 3 || menu < 1) {
				printf("输入错误,请重新输入!");
				Sleep(1000);
				system("cls");
			}
		} while (menu > 3 || menu < 1);
		Option2(menu);
	}
}

void Lockzhanghao(char *filename, Users b) {//账号锁定,有bug已停用,结构体数组和结构体两种数据格式不能
	Users a[100];
	FILE *fp;
	fp = fopen(filename, "r");
	int count = 0;
	while (1) {
		fread(&a[count], sizeof(Users), 1, fp);
		if (!feof(fp)) { //如果文件没有读完
			if (a[count].name == b.name) {
				a[count].situation++;
				printf("\n\n%d", a[count].situation);
			}
			count++;
			continue;
		}
		else {
			fclose(fp);
			break;

		}
	}
	fp = fopen(filename, "w");
	fclose(fp);//清空文件
	fp = fopen(filename, "w");
	for (int j = 0; j < count; j++) {
		fwrite(&a[count], sizeof(Users), 1, fp);
	}
	fclose(fp);
}

void gongneng2() {//教师端功能
	while (flag) {
		StudentNode = CreatNode();//创建链表(表头),使得StudentNode成为表头
		ReadFromFile(S1, StudentNode);//读入之前的文件信息
		do {
			printf("-----------------------------教师端-学生信息管理系统--------------------------------------\n");
			printf("\t\t\t\t1.添加某学生信息\n");//1.添加某学生信息(学号、姓名、性别、三科成绩) 2.学生基本信息输出 3.按学号查询学生信息
			printf("\t\t\t\t2.学生基本信息输出\n");//4.按学号修改某学生信息 5.求每个人平均成绩并输出 6.删除某学生信息
			printf("\t\t\t\t3.按学号查询学生信息\n");//7.输出平均分为80分以上的同学信息 8.将学生总分由小到大排序 9.退出
			printf("\t\t\t\t4.按学号修改某学生信息\n");//----------------------------------------------------------------
			printf("\t\t\t\t5.求每个人平均成绩并输出\n");//学生端 1.查询本人成绩 2.按姓名查询成绩 3.查找所有学生总成绩综合排名 4.输出平均分为80分以上的同学信息 5.退出
			printf("\t\t\t\t6.删除某学生信息\n");
			printf("\t\t\t\t7.输出平均分为80分以上的同学信息\n");
			printf("\t\t\t\t8.将学生总分由小到大排序\n");
			printf("\t\t\t\t9.退出\n");
			printf("-----------------------------------------------------------------------------------\n");
			printf("\n");
			printf("\t\t\t\t   请输入选项:[\t]\b\b\b\b\b");
			scanf("%d", &menu);
			if (menu > 9 || menu < 1) {
				printf("输入错误,请重新输入!");
				Sleep(1000);
				system("cls");
			}
		} while (menu > 9 || menu < 1);
		gongnengswitch2(menu);
	}
}

void gongneng() {//学生端功能
	while (flag) {
		StudentNode = CreatNode();//创建链表(表头),使得StudentNode成为表头
		ReadFromFile(S1, StudentNode);//读入之前的文件信息
		do {
			printf("-----------------------------学生端-学生信息管理系统--------------------------------------\n");
		//1.添加某学生信息(学号、姓名、性别、三科成绩) 2.学生基本信息输出 3.按学号查询学生信息
			printf("\t\t\t\t1.按姓名查询成绩\n");//4.按学号修改某学生信息 5.求每个人平均成绩并输出 6.删除某学生信息
			printf("\t\t\t\t2.查找所有学生总成绩综合排名\n");//7.输出平均分为80分以上的同学信息 8.将学生总分由小到大排序 9.退出
			printf("\t\t\t\t3.输出平均分为80分以上的同学信息\n");//----------------------------------------------------------------
			printf("\t\t\t\t4.退出\n");//学生端 1.查询本人成绩 2.按姓名查询成绩 3.查找所有学生总成绩综合排名 4.输出平均分为80分以上的同学信息 5.退出
			printf("-----------------------------------------------------------------------------------\n");
			printf("\n");
			printf("\t\t\t\t   请输入选项:[\t]\b\b\b\b\b");
			scanf("%d", &menu);
			if (menu > 5 || menu < 1) {
				printf("输入错误,请重新输入!");
				Sleep(1000);
				system("cls");
			}
		} while (menu > 5 || menu < 1);
		gongnengswitch(menu);
	}
}

void gongnengswitch2(int option) {//对应的switch选项实现
	struct Student s;
	switch (option) {
	case 1://已实现
		system("cls");
		InsertNode();
		SaveFile1(S1, StudentNode);//保存文件(路径,头节点)
		printf("插入操作执行完成!-------------");
		Sleep(1000);
		system("cls");
		return;

	case 2://已实现
		system("cls");
		printf("\t【浏览信息】\n");
		PrintNode(StudentNode);//链表输出
		printf("浏览操作执行完成--------------");
		Sleep(1000);
		system("cls");
		return;

	case 3://已实现
		system("cls");
		printf("\t【查找信息】\n");
		printf("请输入查找的学号:");
		scanf("%s", s.name);
		if (SearchNode(StudentNode, s.name) == NULL) {
			printf("未找到相关信息!\n");
			Sleep(1000);
			system("cls");
		}
		else
		{
			PrintList(SearchNode(StudentNode, s.name));
			printf("查找操作执行完成---------------");
			system("pause");
			system("cls");
			return;
		}

		break;
	default:printf("输入数据有误,重新输入\n");
		Sleep(1000);
		system("cls");
		return;

	case 4://已实现
		system("cls");
		printf("\t【更改信息】\n");
		printf("请输入更改的学号:");
		scanf("%s", s.name);
		if (SearchNode(StudentNode, s.name) == NULL) {
			printf("未找到相关信息!\n");
		}
		else
		{
			struct Node* s1 = SearchNode(StudentNode, s.name);
			printf("请输入新的学生信息");
			printf("请输入同学姓名,性别,学号,三科成绩");
			scanf("%s%s%s%f%f%f", s1->data.name, s1->data.sex, s1->data.number, &s1->data.grade1, &s1->data.grade2, &s1->data.grade3);
			printf("修改操作执行完成--------------");
			SaveFile1(S1, StudentNode);//保存文件
		}
		Sleep(1000);
		system("cls");
		return;

	case 5://已实现
		system("cls");
		printf("姓名\t性别\t学号\t平均成绩\n");//打印标题
		PrintAverage(StudentNode);
		system("pause");
		system("cls");
		return;

	case 6://已实现
		system("cls");
		printf("\t【删除信息】\n");
		deletestudent();
		SaveFile1(S1, StudentNode);//保存文件
		printf("删除操作执行完成---------------");
		Sleep(1000);
		system("cls");
		return;

	case 7://已实现
		system("cls");
		printf("姓名\t性别\t学号\t平均成绩\n");//打印标题
		PrintAverage80(StudentNode);
		system("pause");
		system("cls");
		return;

	case 8://已实现
		system("cls");
		printBubblesort(StudentNode);
		system("pause");
		system("cls");
		return;
	case 9://已实现
		system("cls");
		printf("\n\t\t谢谢使用!\n");
		Sleep(1000);
		system("cls");
		caidan1();
	}
}

void gongnengswitch(int option) {//对应的switch选项实现
	struct Student s;
	switch (option) {
	case 1://按名字查询成绩(已实现)
		system("cls");
		printf("\t【查找信息】\n");
		printf("请输入查找的名字:");
		scanf("%s", s.name);
		if (SearchNode2(StudentNode, s.name) == NULL) {
			printf("未找到相关信息!\n");
		}
		else
		{
			PrintList(SearchNode2(StudentNode, s.name));
			printf("查找操作执行完成---------------");
		}
		system("pause");
		system("cls");
		return;

	case 2://查看所有学生总成绩综合排名(从大到小排名)(已实现)
		system("cls");
		printBubblesort2(StudentNode);
		system("pause");
		system("cls");
		return;

	case 3://输出平均分大于80分同学成绩(已实现)
		system("cls");
		printf("姓名\t性别\t学号\t平均成绩\n");//打印标题
		PrintAverage80(StudentNode);
		system("pause");
		system("cls");
		return;

	case 4:
		system("cls");
		printf("\n\t\t谢谢使用!\n");
		Sleep(1000);
		system("cls");
		caidan1();
	}
}

//以下为功能实现部分的函数
void InsertNode() {//插入函数
	int x;
	struct Student S;//数据域
	printf("请输入学生个数\n");
	scanf("%d", &x);
	for (int i = 1; i <= x; i++) {//i作遍历,x为学生数
		printf("请输入第%d个同学姓名,性别,学号,以及三科成绩\n", i);
		scanf("%s%s%s%f%f%f", S.name, S.sex, S.number, &S.grade1, &S.grade2, &S.grade3);//这样写会有bug,因为一旦有数据格式非法输入就会导致数据栈损坏
		CreatNodeList(StudentNode, S);//将StudentNode头节点和数据域生成的结点连接起来
	}
}
struct Node* CreatNode() //建立头节点(建立链表)
{
	struct Node* HeadNode = (struct Node*)malloc(sizeof(struct Node));
	HeadNode->Next = NULL;
	return HeadNode;//返回表头(头节点),本程序是用StudentNode接收头节点,也可以传节点进来在函数中接收,返回StudentNode头节点
}
struct Node* CreatNewNode(struct Student data) {//建立新结点函数
	struct Node* NewNode = (struct Node*)malloc(sizeof(struct Node));//新节点创建
	NewNode->data = data;//将数据域变成一个结点
	NewNode->Next = NULL;
	return NewNode;//注意!该函数在CreatNodeList(插入节点)函数里面使用,不单独使用
}
void CreatNodeList(struct Node* HeadNode, struct Student data) {//将数据域(结构体)变成一个节点并实现节点连接
	struct Node* NewNode = CreatNewNode(data);//将数据域变成一个结点
	NewNode->Next = HeadNode->Next;//新节点与前后节点连接
	HeadNode->Next = NewNode;//注意!!此功能在插入函数(InsertNode)中实现
}
void deletestudent() {//删除节点
	char name[10];
	printf("请输入需要删除的学生名字\n");
	scanf("%s", name);
	deletenode(StudentNode, name);
}
void deletenode(struct Node* headnode, char *name) {//将头节点(表头),和名字(查找)输入函数
	struct Node* posnode = headnode->Next;
	struct Node* posnodefront = headnode;//初始化目标节点的位置
	if (posnode == NULL) {
		printf("数据为空,无法删除");

	}
	else
	{
		while (strcmp(posnode->data.name, name)) {//判断名字是否相等
			posnodefront = posnode;
			posnode = posnodefront->Next;//相当于pmove,遍历链表
			if (posnode == NULL) { printf("未找到指定位置,无法删除"); return; }
		}
		posnodefront->Next = posnode->Next;//连接节点
		free(posnode);
	}
}
struct Node* SearchNode(struct Node* StudentNode, char* name) {//查找学号节点
	struct Node* pMove = StudentNode->Next;
	if (pMove == NULL) {
		printf("未找到该学生");
		return(pMove);
	}
	else
	{
		while (strcmp(pMove->data.number, name)) {
			pMove = pMove->Next;
			if (pMove == NULL)break;
		}
		return pMove;
	}
}
void PrintList(struct Node* StudentNode) {//打印单个节点
	printf("姓名\t性别\t学号\t科目成绩\n");
	printf("%s\t%s\t%s\t%f\t%f\t%f\n", StudentNode->data.name, StudentNode->data.sex, StudentNode->data.number, StudentNode->data.grade1, StudentNode->data.grade2, StudentNode->data.grade3);
}
void PrintNode(struct Node* StudentNode) {//浏览信息
	struct Node* pow = StudentNode->Next;
	printf("姓名\t性别\t学号\t科目成绩\n");
	while (pow) {
		printf("%s\t%s\t%s\t%f\t%f\t%f\n", pow->data.name, pow->data.sex, pow->data.number, pow->data.grade1, pow->data.grade2, pow->data.grade3);
		pow = pow->Next;
	}
}

void SaveFile1(char* filename, struct Node* StudentNode) {
	FILE* fp = fopen(filename, "w");
	struct Node* pow = StudentNode->Next;
	while (pow) {//当指针非空时
		fprintf(fp, "%s\t%s\t%s\t%f\t%f\t%f\n", pow->data.name, pow->data.sex, pow->data.number, pow->data.grade1, pow->data.grade2, pow->data.grade3);//文件写入,同时数据之间存在间隙
		pow = pow->Next;//遍历链表
	}
	fclose(fp);
}

void ReadFromFile(char *filename, struct Node* StudentNode) {//加载之前的文件
	FILE* fp = fopen(filename, "r");
	if (fp == NULL) {
		fp = fopen(filename, "w");
	}
	struct Student data;
	while (fscanf(fp, "%s\t%s\t%s\t%f\t%f\t%f\n", data.name, data.sex,
		data.number, &data.grade1, &data.grade2, &data.grade3) != -1) {//这样写会有bug,因为一旦有数据格式非法输入就会导致数据栈损坏
		CreatNodeList(StudentNode, data);//导入之前生成的链表
		memset(&data, 0, sizeof(data));//内存初始化
	}
	fclose(fp);
}

void printBubblesort(struct Node* StudentNode) { //传入头结点进行冒从小到大的泡算法,然后打印
	struct Student p[1000];
	struct Node* pow = StudentNode->Next;
	int n = 0;
	while (pow) {//当结构体指针非空时
		p[n] = pow->data;//这里之前会报错,不知道为什么?
		pow = pow->Next;//遍历链表
		n++;
	}
	int i, j;
	for (i = 0; i < n; i++) {
		for (j = i + 1; j < n; j++) {
			if (p[i].grade1 + p[i].grade2 + p[i].grade3 >= p[j].grade1 + p[j].grade2 + p[j].grade3) {//判断的条件,顺序为从小到大
				struct Student temp = p[i];
				p[i] = p[j];
				p[j] = temp;
			}
		}
	}
	printf("排名\t姓名\t性别\t学号\t科目1成绩\t科目2成绩\t科目3成绩\t科目总分\n");
	for (i = 0; i < n; i++) {
		printf("[ %d ]\t%s\t%s\t%s\t%f\t%f\t%f\t%f\n", i + 1,  p[i].name, p[i].sex, p[i].number, p[i].grade1, p[i].grade2, p[i].grade3, p[i].grade1+p[i].grade2+p[i].grade3);
	}
}

void PrintAverage(struct Node* StudentNode) {//打印平均成绩
	struct Node* pow = StudentNode->Next;
	while (pow) {
		float aver = (pow->data.grade1 + pow->data.grade2 + pow->data.grade3) / 3;//定义并计算平均数
		printf("%s\t%s\t%s\t%f\n", pow->data.name, pow->data.sex, pow->data.number, aver);
		pow = pow->Next;
	}
}

void PrintAverage80(struct Node* StudentNode) {//打印平均成绩大于80分
	struct Node* pow = StudentNode->Next;
	while (pow) {
		float aver = (pow->data.grade1 + pow->data.grade2 + pow->data.grade3) / 3;//定义并计算平均数
		if (aver > 80) {
			printf("%s\t%s\t%s\t%f\n", pow->data.name, pow->data.sex, pow->data.number, aver);
		}
		pow = pow->Next;
	}
}

struct Node* SearchNode2(struct Node* StudentNode, char* name) {//查找姓名节点
	struct Node* pMove = StudentNode->Next;
	if (pMove == NULL) {
		printf("未找到该学生");
		return(pMove);
	}
	else
	{
		while (strcmp(pMove->data.name, name)) {
			pMove = pMove->Next;
			if (pMove == NULL)break;
		}
		return pMove;
	}
}

void printBubblesort2(struct Node* StudentNode) { //传入头结点进行冒从大到小的泡算法,然后打印
	struct Student p[1000];
	struct Node* pow = StudentNode->Next;
	int n = 0;
	while (pow) {//当结构体指针非空时
		p[n] = pow->data;//这里为什么会报错?
		pow = pow->Next;//遍历链表
		n++;
	}
	int i, j;
	for (i = 0; i < n; i++) {
		for (j = i + 1; j < n; j++) {
			if (p[i].grade1 + p[i].grade2 + p[i].grade3 <= p[j].grade1 + p[j].grade2 + p[j].grade3) {//判断的条件,顺序为从小到大
				struct Student temp = p[i];
				p[i] = p[j];
				p[j] = temp;
			}
		}
	}
	printf("排名\t姓名\t性别\t学号\t科目1成绩\t科目2成绩\t科目3成绩\t科目总分\n");
	for (i = 0; i < n; i++) {
		printf("[ %d ]\t%s\t%s\t%s\t%f\t%f\t%f\t%f\n", i + 1, p[i].name, p[i].sex, p[i].number, p[i].grade1, p[i].grade2, p[i].grade3, p[i].grade1 + p[i].grade2 + p[i].grade3);
	}
}

void HideCursor()
{
	CONSOLE_CURSOR_INFO cursor_info = { 1, 0 };
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}
void AppearCursor()
{
	CONSOLE_CURSOR_INFO cursor_info = { 1, 1 };
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}
void Windowstime()
{
	SYSTEMTIME sys;
	printf("\t\t\t\t\t  当前时间为:");
	GetLocalTime(&sys); //获取系统时间到程序的函数 
	printf("%4d-%02d-%02d %02d:%02d \n\n", sys.wYear, sys.wMonth, sys.wDay, sys.wHour, sys.wMinute); //按照年/月/日 时/分 格式打印
	return;
}
void cursor(int x, int y)
{
	COORD coord;
	coord.X = x;
	coord.Y = y;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
void welcome() {//欢迎函数
	HideCursor();		//为了美观 隐藏光标 
	cursor(0, 21);		//将光标定位在(0,21)处
	Windowstime();		//显示系统时间 
	int i, j;
	char star = '*';
	for (i = 0; i <= 100; i++) {
		cursor(44, 8);
		printf("欢迎使用学生信息管理系统");
		cursor(53, 12);
		printf("启动中...");
		cursor(28, 16);
		printf("<");
		for (j = 0; j < 50; j++) {	//打印进度条 
			if (j < i / 2)
				printf("*");
			else printf("o");
		}
		printf(">");
		printf("%d%%", i);
		Sleep(20);	//每 20ms 进一格 
	}
	return;
}
void PrintExit() {//关闭界面 
	system("cls");
	HideCursor();
	cursor(0, 21);
	Windowstime();
	int i, j;
	for (i = 0; i <= 100; i++) {
		cursor(44, 8);
		printf("感谢使用学生信息管理系统");
		cursor(49, 12);
		printf("数据保存中...");
		cursor(28, 16);
		printf("<");
		for (j = 0; j < 50; j++) {
			if (j < i / 2)
				printf("*");
			else printf("o");
		}
		printf(">");
		printf("%d%%", i);
		Sleep(5);
	}
	cursor(0, 26);
	return;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值