C语言实现学生管理系统(链表、文件操作、模块化设计)

目录

一、总体设计

        1、数据存储

        2、内容设计

        3、界面设计

        4、结构设计

二、核心代码分析

1、administrator.h

2、administrator.c

 3、student.h

 4、student.c

5、ui.h

6、ui.c

7、main.c

三、总结


一、总体设计

        1、数据存储

        分别使用struct Studentstruct Administrator分别存储学生和管理员的数据,成员数据类型全部使用char*,读写方便,将使用两个分开的本地文件存储数据。使用二进制读写方式保证数据的安全

        2、内容设计

        管理员:需要一个ADMregister.exe用来单独注册管理员的账号,之后管理员可以在学生系统(STM.exe)平台登录。登录之后可以对其他管理进行操作注册管理员账号、查找管理员密码、修改管理员账号和密码、查看所有管理员账号、注销管理员账号信息、退出当前页面)。同样可以对学生进行操作注册学生用户、查找学生、修改学生信息  、注销学生用户 、查看所有学生信息 、查看排行耪  、打印所有学生信息 、退出当前页面

        3、界面设计

        /*主界面*//*登录界面*//*管理员界面*//*学生界面*//*学生管理界面*//*管理管理员界面*/在每个界面都会显示当前的日期和时间

 

 

 

        4、结构设计

        模块化设计可以更加方便我们编程。头文件、源文件、主程序文件分开。[administrator.h]、[resource.h]、[student.h]、[ui.h]、[administrator.c]、[resource.c]、[student.c]、[ui.c]、[main.c]

C语言的基本操作,就不用多说了。

二、核心代码分析

1、administrator.h

#ifndef _ADMINISTRATOR_H__
#define _ADMINISTRATOR_H__


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


/*注册管理员用户和密码*/
void Adm_Register();
/*查找管理员账户密码*/
char* searchAdmUser(char* username);
/*读取用户本地信息返回相应的链表数据*/
struct Administrator* readAdmUserData();
/*只用链表以后要及时释放链表的空间防止内存泄露*/
void releaseAdmSpace(struct Administrator* list);
/*修改管理员的相关信息(修改链表的数据)*/
struct Administrator* changeAdmData(char* _Key);
/*保存链表的数据(保存链表的数据)*/
int saveAdmData(struct Administrator* saveOb, char* saveMode);
/*输入用户名和密码完成登录操作*/
int AdmLogin();
/*打印管理员的数据(打印链表的数据)*/
void printAllAdm(struct Administrator* list);
/*注销管理员(删除链表的数据)*/
struct Administrator* unRegisterAdm(char* _Key);


/*管理员结构体*/
struct Administrator
{
	char User[12];		//用户名和密码12位
	char Pwd[12];
	struct Administrator* next;

};


#endif // !ADMINISTRATOR

2、administrator.c


#include "administrator.h"



/*
* @引用:未引用
* @功能:读取用户本地信息返回相应的链表数据
* @参数:无
* @返值:struct Administrator*链表头节点
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
struct Administrator* readAdmUserData()
{
	FILE* fp;
	//读取文件测试
	fp = fopen("./admdatas.dat", "rb+");	//打开文件
	/*创建头节点*/
	struct Administrator* read_head = (struct Administrator*)malloc(sizeof(struct Administrator));
	/*temp变量*/
	struct Administrator* temp = (struct Administrator*)malloc(sizeof(struct Administrator));
	/*让头节点的下一个为空*/
	read_head->next = NULL;
	if (fp)					//如果打开文件
	{
		fseek(fp, 0, 0);	//找到文件开头
		/*
		如果读取到有效字节---循环
		方法二:feof(文件流)判断是否到文件末尾,但是有缺陷:最后一行会多读一次
		*/
		while (fread(temp, sizeof(struct Administrator), 1, fp))
		{
			//创建节点
			struct Administrator* read = (struct Administrator*)malloc(sizeof(struct Administrator));
			//copy字符串
			strcpy(read->User, temp->User);
			strcpy(read->Pwd, temp->Pwd);
			//链表链接
			read->next = read_head->next;
			read_head->next = read;
		}
		//关闭文件流
		fclose(fp);
	}
	//遍历链表--打印读取到的信息
	/*struct Administrator* pMove = read_head->next;
	while (pMove)
	{
		printf("%12s%12s\n", pMove->User, pMove->Pwd);
		pMove = pMove->next;
	}*/
	//释放相关空间
	free(temp);
	//返回头节点
	return read_head;
}

/*
* @引用:未引用
* @功能:键入用户名、密码完成注册
* @参数:void
* @返值:void
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
void Adm_Register()
{
	//创建头节点
	struct Administrator* adm_head = (struct Administrator*)malloc(sizeof(struct Administrator));
	adm_head->next = NULL;
	//插入节点
	int Userflag = 1;		//是否退出用户名输入循环
	int Pwdflag = 1;		//是否退出密码输入循环
	do
	{	//创建聊表数据
		struct Administrator* user = (struct Administrator*)malloc(sizeof(struct Administrator));
		char tempUser[20];		//用于判断用户名是否已经被注册的临时变量
		char tempPwd1[20];		//用于判断两次输入密码是否相同
		char tempPwd2[20];

		printf("请输入用户名:\n");
		scanf("%s", tempUser);
		/*写入之前要线确保该用户名没有被注册过*/
		if (!searchAdmUser(tempUser))	//如果返回值不为空
		{	//如果用户名没有被注册过--注册用户名
			strcpy(user->User, tempUser);
			//注册密码
			do
			{
				printf("请输入密码:\n");
				scanf("%s", tempPwd1);
				printf("请再次确认密码:\n");
				scanf("%s", tempPwd2);
				//如果两次输入的密码相同,注册密码
				if (strcmp(tempPwd1, tempPwd2) == 0)
				{
					Pwdflag = 0;
					strcpy(user->Pwd, tempPwd1);
				}
				else
					printf("两次输入的密码不同,请重新输入\n");
			} while (Pwdflag);
		}
		else
			printf("该用户名已经注册\n");
		//连接链表(头插法)
		user->next = adm_head->next;
		adm_head->next = user;
		//user->next = NULL;
		printf("是否继续注册?(0/1)");
		scanf("%d", &Userflag);

	} while (Userflag);
	//注册信息的存档
	saveAdmData(adm_head,"ab+");
	//释放空间
	releaseAdmSpace(adm_head);

}

/*
* @引用:未引用
* @功能:输入用户名查看是否存在该用户如果存在返回该用户的密码
* @参数:char* username---用户名
* @返值:char*--返回用户的密码(非空)
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
char* searchAdmUser(char* username)
{
	//调用读取函数---从本地读取已经注册的用户(链表)
	struct Administrator* read_temp = readAdmUserData();
	//遍历链表
	struct Administrator* pMove = read_temp->next;
	while (pMove)
	{
		//如果有相同的用户名,返回该用户的密码,说明该用户名已经注册过
		if (strcmp(username, pMove->User) == 0)
			return pMove->Pwd;
		pMove = pMove->next;
	}
	//释放空间
	free(read_temp);
	free(pMove);
	return NULL;
}


/*
函数原型:int AdmLogin()
参数:const char* username, char* password
返回值:int
函数作用:输入密码登录到管理员
*/

/*
* @引用:未引用
* @功能:输入用户名和密码完成登录操作
* @参数:无
* @返值:int--返回登录的结果
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
int AdmLogin()
{
	char username[20], password[20];
	printf("请输入管理员用户名\n");
	scanf("%s", &username);
	printf("请输入管理员密码\n");
	scanf("%s", &password);

	//调用查找函数
	if (searchAdmUser(username) != NULL)
	{
		//如果登录的密码,与查询返回来的密码相同---登录成功
		if (strcmp(password, searchAdmUser(username)) == 0)
		{
			printf("登录成功!\n");
			return 1;
			//跳转到相应的界面
		}
		else
		{
			printf("密码错误!\n");
			return 0;
		}
	}
	else
		printf("该用户名尚未注册!\n");
	return 0;
}

/*
* @引用:未引用
* @功能:只用链表以后要及时释放链表的空间防止内存泄露
* @参数:struct Administrator*list---要释放的链表空间
* @返值:无
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
void releaseAdmSpace(struct Administrator* list)
{
	struct Administrator* pFree;
	struct Administrator* pMove = list->next;
	while (pMove)
	{
		pFree = pMove;
		pMove = pMove->next;
		printf("释放用户[%s]所在的空间\n", pFree->User);
		free(pFree);
	}
}

/*
* @引用:未引用
* @功能:修改管理员的相关信息(修改链表的数据)
* @参数:char* _Key--管理员的关键字
* @返值:struct Administrator*--修改后的链表头节点
* @注意:函数内通过调用readAdmUserData()获取要修改的链表
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
struct Administrator* changeAdmData(char* _Key)
{
	struct Administrator* chage_obj = readAdmUserData();
	struct Administrator* pMove = chage_obj->next;
	while (pMove)
	{
		if (strcmp(_Key, pMove->User) == 0)
		{
			char pwd[20];
			printf("请输入密码验证\n");
			scanf("%s", pwd);
			if (strcmp(pwd, pMove->Pwd) == 0)
			{
				printf("验证成功\n");
				printf("账户名修改为:\n");
				scanf("%s", pMove->User);
				printf("密码修改为:\n");
				scanf("%s", pMove->Pwd);

				printf("修改成功\n");
			}
			else
			{
				printf("验证失败\n");
				return NULL;
			}
		}
		pMove = pMove->next;
	}
	//保存
	saveAdmData(chage_obj, "wb+");
	free(pMove);
	return chage_obj;
}

/*
* @引用:未引用
* @功能:保存链表的数据(保存链表的数据)
* @参数:struct Administrator* saveOb, char* saveMode--要保存的链表对象--保存的模式
* @返值:int--返回保存的结果
* @注意:保存的模式和便准C语言文件操作的模式一样
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
int saveAdmData(struct Administrator* saveOb, char* saveMode)
{
	/*注册信息存档*/
	FILE* fp;
	fp = fopen("./admdatas.dat", saveMode);	//打开文件
	//遍历刚才注册信息的链表
	if (fp)		//如果打开文件
	{
		struct Administrator* pMove = saveOb->next;
		while (pMove)
		{	//将链表数据写入文件
			fwrite(pMove, sizeof(struct Administrator), 1, fp);
			//同时打印注册信息
			printf("[%s已注册\t密码为%s]\n", pMove->User, pMove->Pwd);
			pMove = pMove->next;
		}
		fclose(fp);	//关闭文件
	}

	return 0;
}

/*
* @引用:未引用
* @功能:打印管理员的数据(打印链表的数据)
* @参数:struct Administrator* list--要打印的链表对象
* @返值:无
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
void printAllAdm(struct Administrator* list)
{
	struct Administrator* pMove = list->next;
	while (pMove)
	{
		//打印注册信息
		printf("管理员[ %s ]\n", pMove->User);
		pMove = pMove->next;
	}

}

/*
* @引用:未引用
* @功能:注销管理员(删除链表的数据)
* @参数:char* _Key--要注销的管理员的关键字
* @返值:struct Administrator*--返回新的链表头节点
* @注意:通过调用 readAdmUserData()获取要操作的对象--调用saveAdmData()保存新的信息
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
struct Administrator* unRegisterAdm(char* _Key)
{
	struct Administrator* chage_obj = readAdmUserData();
	struct Administrator* pos = chage_obj->next;
	struct Administrator* lastpos = chage_obj;
	if (!pos)
		printf("没有可注销的信息!\n");
	else
	{
		while (pos)
		{
			if (strcmp(_Key, pos->User) == 0)
			{
				lastpos->next = pos->next;
				printf("成功注销管理员用户[%s]\n", pos->User);
				free(pos);
				//保存(覆盖的方式)
				saveAdmData(chage_obj, "wb+");
				return chage_obj;
			}
			lastpos = pos;
			pos = pos->next;
		}
		printf("没有查询到相关信息,注销失败!\n");
	}

	return chage_obj;
}

 3、student.h


#ifndef _STUDENT_H__
#define _STUDENT_H__


#include "administrator.h"


/*键入用户名、密码完成注册*/
void Stu_Register();
/*输入用户名查看是否存在该用户如果存在返回该用户的密码*/
char* searchStuUser(char* username);
/*查询学生的信息*/
struct Student* searchStudent(char* Key);
/*读取学生本地信息返回相应的链表数据*/
struct Student* readStuUserData();
/*录入学生的相关信息*/
struct Student* enteringStudat(struct Student* stu);
/*只用链表以后要及时释放链表的空间防止内存泄露*/
void releaseStuSpace(struct Student* list);
/*修改学生相关信息*/
void changeStuData(char* Key);
/*学生修改密码*/
void changeStuPwd(char* _Key);
/*保存链表的数据(保存链表的数据)*/
void saveStuData(struct Student* saveOb, char* saveMode);
/*学生登录*/
int StuLogin(char* username, char* password);
/*打印单个学生的信息(打印链表的节点的数据)*/
void printStu(struct Student* stu);
/*打印所有学生的信息(打印链表的数据)*/
void PrintAllStuData(struct Student* stu);
/*注销学生的的账户*/
struct Student* unRegisterStu(char* _Key);
/*输出学生的详细信息到本地文件*/
void outputDetail(struct Student* stu);
/*打印学生的的排名*/
void printRanking(struct Student* stu);
/*通过学生的总成绩将学生进行排名(链表的排序)*/
struct Student* sortStudentList(struct Student* list);



/*学生结构体*/
struct Student
{
	char name[10];			//姓名
	char gender[10];		//性别
	char class_[10];		//班级
	char stu_num[15];		//学号
	char level[10];			//总成绩
	char RePu[200];			//奖励或惩罚
	char Leave[200];		//请假信息
	char Gradu[200];		//毕业信息
	char User[12];			//账号和密码12位
	char Pwd[12];
	char ranking[10];

	struct Student* next;

};

#endif // !STUDENT_H__

 4、student.c

#include "student.h"



/*
* @引用:未引用
* @功能:读取学生本地信息返回相应的链表数据
* @参数:void
* @返值:struct Student*--返回学生的链表数据头节点
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
struct Student* readStuUserData()
{
	FILE* fp;
	//读取文件测试
	fp = fopen("./studentdatas.dat", "rb+");	//打开studentdatas文件
	/*创建头节点*/
	struct Student* read_head = (struct Student*)malloc(sizeof(struct Student));
	/*temp变量*/
	struct Student* temp = (struct Student*)malloc(sizeof(struct Student));
	/*让头节点的下一个为空*/
	read_head->next = NULL;
	if (fp)					//如果打开文件
	{
		fseek(fp, 0, 0);	//找到文件开头
		/*
		如果读取到有效字节---循环
		方法二:feof(文件流)判断是否到文件末尾,但是有缺陷:最后一行会多读一次
		*/
		while (fread(temp, sizeof(struct Student), 1, fp))
		{
			//创建节点
			struct Student* read = (struct Student*)malloc(sizeof(struct Student));
			//copy字符串
			strcpy(read->class_, temp->class_);
			strcpy(read->gender, temp->gender);
			strcpy(read->Gradu, temp->Gradu);
			strcpy(read->Leave, temp->Leave);
			strcpy(read->level, temp->level);
			strcpy(read ->name , temp->name);
			strcpy(read ->Pwd , temp->Pwd);
			strcpy(read ->ranking , temp->ranking);
			strcpy(read ->RePu , temp->RePu);
			strcpy(read ->stu_num , temp->stu_num);
			strcpy(read ->User , temp->User);

			//链表链接
			read->next = read_head->next;
			read_head->next = read;
		}
		//关闭文件流
		fclose(fp);
	}
	//遍历链表--打印读取到的信息
	/*struct Student* pMove = read_head->next;
	while (pMove)
	{
		printf("%12s%12s\n", pMove->User, pMove->Pwd);
		pMove = pMove->next;
	}*/
	//释放相关空间
	free(temp);
	//按照成绩排序
	sortStudentList(read_head);
	//返回头节点
	return read_head;
}


/*
* @引用:未引用
* @功能:键入用户名、密码完成注册
* @参数:无
* @返值:无
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
void Stu_Register()
{
	//创建头节点
	struct Student* stu_head = (struct Student*)malloc(sizeof(struct Student));
	stu_head->next = NULL;

	int Userflag = 1;		//是否退出用户名输入循环
	int Pwdflag = 1;		//是否退出密码输入循环
	do
	{	
		char tempUser[20];		//用于判断用户名是否已经被注册的临时变量
		char tempPwd1[20];		//用于判断两次输入密码是否相同
		char tempPwd2[20];

		printf("请输入用户名:\n");
		scanf("%s", tempUser);
		/*写入之前要线确保该用户名没有被注册过*/
		if (!searchStuUser(tempUser))	//如果返回值不为空
		{	//如果用户名没有被注册过--注册用户名
			//插入节点
			struct Student* user = (struct Student*)malloc(sizeof(struct Student));
			strcpy(user->User, tempUser);
			//注册密码
			do
			{
				printf("请输入密码:\n");
				scanf("%s", tempPwd1);
				printf("请再次确认密码:\n");
				scanf("%s", tempPwd2);
				//如果两次输入的密码相同,注册密码
				if (strcmp(tempPwd1, tempPwd2) == 0)
				{
					Pwdflag = 0;
					strcpy(user->Pwd, tempPwd1);
				}
				else
					printf("两次输入的密码不同,请重新输入\n");
			} while (Pwdflag);

			//录入学生相关信息
			/******************************/
			user = enteringStudat(user);
			/******************************/
			//插入节点
			//stu_head = sortStudentList(stu_head, user);

			user->next = stu_head->next;
			stu_head->next = user;

		}
		else
			printf("该用户名已经注册\n");
		//连接链表(按照成绩去插入)

		printf("是否继续注册?(0/1)");
		scanf("%d", &Userflag);

	} while (Userflag);

	/*注册信息存档*/
	saveStuData(stu_head, "ab+");
	//释放链表的空间
	releaseStuSpace(stu_head);
}

/*
* @引用:未引用
* @功能:录入学生的相关信息
* @参数:truct Student* user--要录入信息的学生空节点
* @返值:truct Student* --返回有数据的学生链表节点
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
struct Student* enteringStudat(struct Student* user)
{
	printf("开始录入学生信息!\n");

	printf("录入姓名\n");
	scanf("%s", user->name);
	printf("录入性别\n");
	scanf("%s", user->gender);
	printf("录入班级\n");
	scanf("%s", user->class_);
	printf("录入学号\n");
	scanf("%s", user->stu_num);
	printf("录入总成绩\n");
	scanf("%s", user->level);
	printf("录入奖励或惩罚\n");
	scanf("%s", user->RePu);
	printf("录入请假信息\n");
	scanf("%s", user->Leave);
	printf("录入毕业信息\n");
	scanf("%s", user->Gradu);

	printf("录入完成!\n");

	return user;
}


/*
* @引用:未引用
* @功能:输入用户名查看是否存在该用户如果存在返回该用户的密码
* @参数:char* username---用户名
* @返值:char*--返回用户的密码(非空)
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
char* searchStuUser(char* username)
{
	//调用读取函数---从本地读取已经注册的用户(链表)
	struct Student* read_temp = readStuUserData();
	//遍历链表
	struct Student* pMove = read_temp->next;
	while (pMove)
	{
		//如果有相同的用户名,返回该用户的密码,说明该用户名已经注册过
		if (strcmp(username, pMove->User) == 0)
			return pMove->Pwd;
		pMove = pMove->next;
	}

	return NULL;
}



/*
* @引用:未引用
* @功能:只用链表以后要及时释放链表的空间防止内存泄露
* @参数:struct Student* list---要释放的链表空间
* @返值:无
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
void releaseStuSpace(struct Student* list)
{
	struct Student* pFree;
	struct Student* pMove = list->next;
	while (pMove)
	{
		pFree = pMove;
		pMove = pMove->next;
		printf("释放用户[%s]所在的空间\n", pFree->User);
		free(pFree);
	}
}
/*
* @引用:未引用
* @功能:修改学生相关信息
* @参数:char* _Key---要修改的学生的关键字
* @返值:无
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
void changeStuData(char* _Key)
{
	struct Student* chage_obj = readStuUserData();
	struct Student* pMove = chage_obj->next;
	while (pMove)
	{
		if ((strcmp(_Key, pMove->User) == 0)||(strcmp(_Key, pMove->name) == 0)|| (strcmp(_Key, pMove->stu_num) == 0))
		{
			char pwd[20];
			printf("请输入密码验证\n");
			scanf("%s", pwd);
			if (strcmp(pwd, pMove->Pwd) == 0)
			{
				printf("验证成功\n");

				int changeFlag = 1;
				do
				{
					int select = 0;
					char change[1024];
					printf("[1]-姓名     [2]-性别     [3]-班级     [4]-学号\n");
					printf("[5]-总成绩   [6]-奖惩     [7]-请假信息 [8]-毕业信息\n");
					printf("[9]-账号     [10]-密码\n");

					printf("请输入要修改的项目序号:\n");
					scanf("%d", &select);
					printf("修改为:\n");

					switch (select)
					{
					case 1:scanf("%s", pMove->name); break;
					case 2:scanf("%s", pMove->gender); break;
					case 3:scanf("%s", pMove->class_); break;
					case 4:scanf("%s", pMove->stu_num); break;
					case 5:scanf("%s", pMove->level); break;
					case 6:scanf("%s", pMove->RePu); break;
					case 7:scanf("%s", pMove->Leave); break;
					case 8:scanf("%s", pMove->Gradu); break;
					case 9:scanf("%s", pMove->User); break;
					case 10:scanf("%s", pMove->Pwd); break;
					}
					printf("修改成功\n是否继续修改(1/0)?\n");
					scanf("%d", &changeFlag);
				} while (changeFlag);
				
			}
			else
			{
				printf("验证失败\n");
				return;
			}
		}
		else
		{
			printf("查无结果\n");
			return;
		}
		pMove = pMove->next;
	}
	//保存
	saveStuData(chage_obj, "wb");

}
/*
* @引用:未引用
* @功能:保存链表的数据(保存链表的数据)
* @参数:struct Student* saveOb, char* saveMode--要保存的链表对象--保存的模式
* @返值:无
* @注意:保存的模式和便准C语言文件操作的模式一样
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
void saveStuData(struct Student* saveOb, char* saveMode)
{
	FILE* fp;
	fp = fopen("./studentdatas.dat", saveMode);	//打开文件
	//遍历刚才注册信息的链表
	if (fp)		//如果打开文件
	{
		struct Student* pMove = saveOb->next;
		while (pMove)
		{	//将链表数据写入文件
			fwrite(pMove, sizeof(struct Student), 1, fp);
			//同时打印注册信息
			printf("%12s已注册!密码为%12s\n", pMove->User, pMove->Pwd);
			pMove = pMove->next;
		}
		fclose(fp);	//关闭文件
	}

}
/*
* @引用:未引用
* @功能:学生登录
* @参数:const char* username, char* password
* @返值:int--是否登录成功
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/

int StuLogin(char* username, char* password)
{
	//调用查找函数
	if (searchStuUser(username) != NULL)
	{
		//如果登录的密码,与查询返回来的密码相同---登录成功
		if (strcmp(password, searchStuUser(username)) == 0)
		{
			printf("登录成功!\n");
			return 1;
			//跳转到相应的界面
		}
		else
		{
			printf("密码错误!\n");
			return NULL;
		}
	}
	else
		printf("该用户名尚未注册!\n");
	return 0;
}

/*
* @引用:未引用
* @功能:打印所有学生的信息(打印链表的数据)
* @参数:struct Student* stulist--要打印的链表头节点
* @返值:无
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/

void PrintAllStuData(struct Student* stulist)
{
	struct Student* pMove = stulist->next;
	while (pMove)
	{
		printf("====基本信息====\n");
		printf("用户:%s\n", pMove->User);
		printf("密码:%s\n", pMove->Pwd);
		printf("姓名:%s\n", pMove->name);
		printf("性别:%s\n", pMove->gender);
		printf("班级:%s\n", pMove->class_);
		printf("学号:%s\n", pMove->stu_num);

		printf("====成绩信息====\n");
		printf("总成绩:%s\n", pMove->level);
		printf("总排名:%s\n", pMove->ranking);

		printf("====其他信息====\n");
		printf("毕业信息:%s\n", pMove->Gradu);
		printf("请假信息:%s\n", pMove->Leave);
		printf("奖惩信息:%s\n", pMove->RePu);
		printf("********************************************************\n");

		pMove = pMove->next;
	}
}
/*
* @引用:未引用
* @功能:打印单个学生的信息(打印链表的节点的数据)
* @参数:truct Student* stu--要打印的节点
* @返值:无
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
void printStu(struct Student* stu)
{
	printf("====基本信息====\n");
	printf("用户:%s\n", stu->User);
	printf("密码:%s\n", stu->Pwd);
	printf("姓名:%s\n", stu->name);
	printf("性别:%s\n", stu->gender);
	printf("班级:%s\n", stu->class_);
	printf("学号:%s\n", stu->stu_num);

	printf("====成绩信息====\n");
	printf("总成绩:%s\n", stu->level);
	printf("总排名:%s\n", stu->ranking);

	printf("====其他信息====\n");
	printf("毕业信息:%s\n", stu->Gradu);
	printf("请假信息:%s\n", stu->Leave);
	printf("奖惩信息:%s\n", stu->RePu);
	printf("\n");

}

/*
* @引用:未引用
* @功能:查询学生的信息
* @参数:char* Key--学生的关键信息
* @返值:struct Student*--返回单个学生的结构体
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
struct Student* searchStudent(char* Key)
{
	struct Student* chage_obj = readStuUserData();
	struct Student* pMove = chage_obj->next;
	while (pMove)
	{
		if ((strcmp(Key, pMove->User) == 0) || (strcmp(Key, pMove->name) == 0) || (strcmp(Key, pMove->stu_num) == 0))
		{
			return pMove;
		}
		pMove = pMove->next;
	}

	return NULL;
}

/*
* @引用:未引用
* @功能:注销学生的的账户
* @参数:char* Key--学生的关键信息
* @返值:struct Student*--返回新的链表数据头节点
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
struct Student* unRegisterStu(char* _Key)
{
	struct Student* chage_obj = readStuUserData();
	struct Student* pos = chage_obj->next;
	struct Student* lastpos = chage_obj;
	if (!pos)
		printf("没有可注销的信息!\n");
	else
	{
		while (pos)
		{
			if ((strcmp(_Key, pos->User) == 0) || (strcmp(_Key, pos->name) == 0) || (strcmp(_Key, pos->stu_num) == 0))
			{
				//只会执行一次
				lastpos->next = pos->next;
				printf("成功注销学生用户[%s]\n", pos->User);
				free(pos);
				//保存(覆盖的方式)
				saveStuData(chage_obj, "wb+");
				return chage_obj;
			}
			lastpos = pos;
			pos = pos->next;
		}
		printf("没有查询到相关信息,注销失败!\n");
	}

	return chage_obj;
}

/*
* @引用:未引用
* @功能:打印学生的的排名
* @参数:struct Student* stulist--打印的对象
* @返值:无
* @注意:和void printStu(struct Student* stu)原理一样
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
void printRanking(struct Student* stulist)
{
	struct Student* pMove = stulist->next;
	while (pMove)
	{
		printf("姓名:%5s", pMove->name);
		printf("班级:%5s", pMove->class_);
		printf("总成绩:%5s", pMove->level);
		printf("总排名:%5s", pMove->ranking);
		printf("\n");
		pMove = pMove->next;
	}

}

/*
* @引用:未引用
* @功能:输出学生的详细信息到本地文件
* @参数:struct Student* stulist--输出的对象
* @返值:无
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
void outputDetail(struct Student* stu)
{
	FILE* fp;
	fp = fopen("./ouputstudentdetail.txt", "w+");
	if (fp)
	{
		fprintf(fp, "\t\t\t学生信息\t\t\t\n");
		struct Student* pMove = stu->next;
		while (pMove)
		{
			fprintf(fp, "用户:%s\n", pMove->User);
			fprintf(fp, "====基本信息====\n");
			fprintf(fp, "密码:%s\n", pMove->Pwd);
			fprintf(fp, "姓名:%s\n", pMove->name);
			fprintf(fp, "性别:%s\n", pMove->gender);
			fprintf(fp, "班级:%s\n", pMove->class_);
			fprintf(fp, "学号:%s\n", pMove->stu_num);

			fprintf(fp, "====成绩信息====\n");
			fprintf(fp, "总成绩:%s\n", pMove->level);
			fprintf(fp, "总排名:%s\n", pMove->ranking);

			fprintf(fp, "====其他信息====\n");
			fprintf(fp, "毕业信息:%s\n", pMove->Gradu);
			fprintf(fp, "请假信息:%s\n", pMove->Leave);
			fprintf(fp, "奖惩信息:%s\n", pMove->RePu);
			fprintf(fp, "***************************\n");

			pMove = pMove->next;
		}
		printf("成功导出学生信息!\n");
		fclose(fp);
	}
	else
		printf("因某种原因导出失败!\n");

}

/*
* @引用:https://blog.csdn.net/baidu_30000217/article/details/77823084
* @功能:通过学生的总成绩将学生进行排名(链表的排序)
* @参数:struct mylist* stulist--排序的对象
* @返值:struct Student*--返回新的链表数据
* @注意:无
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/

struct Student* sortStudentList(struct Student* mylist)
{
	if ((mylist->next == NULL) || (mylist->next->next == NULL))
		return NULL;
	int rank = 1;
	struct Student* head, * pre, * cur, * next, * end, * temp;
	head = mylist;
	end = NULL;
	//从链表头开始将较大值往后沉
	while (head->next != end)
	{
		for (pre = head, cur = pre->next, next = cur->next; next != end; pre = pre->next, cur = cur->next, next = next->next)
		{
			//相邻的节点比较
			if (atoi(cur->level) < atoi(next->level))
			{
				cur->next = next->next;
				pre->next = next;
				next->next = cur;
				temp = next;
				next = cur;
				cur = temp;
			}
		}
		end = cur;
	}
	struct Student* pos = mylist->next;
	while (pos)
	{
		itoa(rank++, pos->ranking, 10);
		pos = pos->next;
	}

	return mylist;
}

/*
* @引用:未引用
* @功能:学生修改密码
* @参数:char* _Key--修改对象的关键字
* @返值:无
* @注意:和void changeStuData(char* Key)原理相同
* @作者:江小鱼
* @日期:2022/08/15
* @版本:v1.0
* @修改信息:
*	版本v1.0: 江小鱼, 2022/08/15, 未修改
*/
void changeStuPwd(char* _Key)
{
	struct Student* chage_obj = readStuUserData();
	struct Student* pMove = chage_obj->next;
	while (pMove)
	{
		if ((strcmp(_Key, pMove->User) == 0) || (strcmp(_Key, pMove->name) == 0) || (strcmp(_Key, pMove->stu_num) == 0))
		{
			char pwd[20];
			printf("请输入密码验证\n");
			scanf("%s", pwd);
			if (strcmp(pwd, pMove->Pwd) == 0)
			{
				printf("验证成功\n");
				printf("你将把密码修改为:\n");
				scanf("%s", pMove->Pwd);
				printf("修改成功!退出后生效\n");
				break;
			}
		}
		pMove = pMove->next;
	}
	//保存
	saveStuData(chage_obj, "wb");
	printf("保存成功!\n");
}

5、ui.h

#ifndef _UI_H__
#define _UI_H__


#include <stdio.h>
#include <time.h>


/*主界面*/
void index();
/*登录界面*/
void LoginDesk();
/*管理员界面*/
void AdmDesk();
/*学生界面*/
void StuDesk();
/*学生管理界面*/
void student();
/*管理管理员界面*/
void adm();
/*获取现在的时间*/
struct tm* now();


#endif // !1

6、ui.c



#include "ui.h"



/*主界面*/
void index()
{
	printf("***********************************************************\n");
	printf("*                 欢迎使用学生管理系统2.0                 *\n");
	printf("*                                                         *\n");
	printf("*                                                         *\n");
	printf("*                      [1]管理员登录                      *\n");
	printf("*                      [2]学生登录                        *\n");
	printf("*                                                         *\n");
	printf("*                      [0]退出                            *\n");
	printf("*                                                         *\n");
	printf("*                                                         *\n");
	printf("*   %4d/%2d/%2d                                    %2d:%2d   *\n", now()->tm_year + 1900, now()->tm_mon + 1, now()->tm_mday, now()->tm_hour, now()->tm_min);
	printf("***********************************************************\n");
	printf(">>>");
}

/*管理管理员界面*/
void adm()
{
	printf("***********************************************************\n");
	printf("*                      ==管理员界面==                     *\n");
	printf("*                                                         *\n");
	printf("*                     [1]注册管理员账号                   *\n");
	printf("*                     [2]查找管理员账户密码               *\n");
	printf("*                     [3]修改管理员账户密码               *\n");
	printf("*                     [4]查看所有管理员账户               *\n");
	printf("*                     [5]注销管理员账户                   *\n");
	printf("*                                                         *\n");
	printf("*                     [0]退出当前页面                     *\n");
	printf("*                                                         *\n");
	printf("*                                                         *\n");
	printf("*   %4d/%2d/%2d                                    %2d:%2d   *\n", now()->tm_year + 1900, now()->tm_mon + 1, now()->tm_mday, now()->tm_hour, now()->tm_min);
	printf("***********************************************************\n");
	printf(">>>");

}

/*学生管理界面*/
void student()
{
	printf("***********************************************************\n");
	printf("*                    ==学生管理界面==                     *\n");
	printf("*                                                         *\n");
	printf("*                     [1]注册学生用户                     *\n");
	printf("*                     [2]查找学生                         *\n");
	printf("*                     [3]修改学生信息                     *\n");
	printf("*                     [4]注销学生用户                     *\n");
	printf("*                     [5]查看所有学生信息                 *\n");
	printf("*                     [6]查看排行耪                       *\n");
	printf("*                     [7]打印所有学生信息                 *\n");
	printf("*                                                         *\n");
	printf("*                     [0]退出当前页面                     *\n");
	printf("*                                                         *\n");
	printf("*                                                         *\n");
	printf("*   %4d/%2d/%2d                                    %2d:%2d   *\n", now()->tm_year + 1900, now()->tm_mon + 1, now()->tm_mday, now()->tm_hour, now()->tm_min);
	printf("***********************************************************\n");
	printf(">>>");
}

/*管理员界面*/
void AdmDesk()
{
	printf("***********************************************************\n");
	printf("*                      ==管理员界面==                     *\n");
	printf("*                                                         *\n");
	printf("*                                                         *\n");
	printf("*                     [1]管理员管理                       *\n");
	printf("*                     [2]学生管理                         *\n");
	printf("*                                                         *\n");
	printf("*                     [0]退出当前页面                     *\n");
	printf("*                                                         *\n");
	printf("*                                                         *\n");
	printf("*   %4d/%2d/%2d                                    %2d:%2d   *\n", now()->tm_year + 1900, now()->tm_mon + 1, now()->tm_mday, now()->tm_hour, now()->tm_min);
	printf("***********************************************************\n");
	printf(">>>");

}

/*学生界面*/
void StuDesk()
{
	printf("***********************************************************\n");
	printf("*                       ==学生界面==                      *\n");
	printf("*                                                         *\n");
	printf("*                                                         *\n");
	printf("*                       [1]查看信息                       *\n");
	printf("*                       [2]查看排行耪                     *\n");
	printf("*                       [3]修改密码                       *\n");
	printf("*                                                         *\n");
	printf("*                       [0]退出                           *\n");
	printf("*                                                         *\n");
	printf("*                                                         *\n");
	printf("*   %4d/%2d/%2d                                    %2d:%2d   *\n", now()->tm_year + 1900, now()->tm_mon + 1, now()->tm_mday, now()->tm_hour, now()->tm_min);
	printf("***********************************************************\n");
	printf(">>>");

}
/*登录界面*/
void LoginDesk()
{
	printf("**********************************************************\n");
	printf("*                                                        *\n");
	printf("*                        欢迎登录                        *\n");
	printf("*                                                        *\n");
	printf("*                                                        *\n");
	printf("*   %4d/%2d/%2d                                   %2d:%2d   *\n", now()->tm_year+1900,now()->tm_mon+1,now()->tm_mday,now()->tm_hour,now()->tm_min);
	printf("**********************************************************\n");

}

/*获取现在的时间*/
struct tm* now()
{
	time_t timep;
	struct tm* p;
	time(&timep);
	p = localtime(&timep); //取得当地具体时间

	return p;
}

7、main.c

请私信我

注释很详细就不用唠叨了!

三、总结

        用来一天时间完成了以上项目,值得注意的是过程中会遇到很多不可思议的事情,当然检查以后就是一个很小很小的不细心导致的,又因为代码太多,如果一不注意犯了一个小错误,回去检查真的很难查,通过这个项目又认识了两个新函数:atoi()、itoa() 分别是字符串转整形和整形转字符串(看百度说的是这两个函数是非标准C语言函数属于C、C++的扩展函数),不得不说很方便,因为全篇变量使用的是char*所以当时还在想怎么比较大小,有了他不是手到擒来?

[欢迎指正!!!]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小鱼爱码士

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值