C语言学生管理系统(文件、链表)-(1)管理员


前言

本系统核心是使用链表和文件,可以实现基本功能,并且可以实现多次复用,文件内的内容相当于数据库,可以保存运行多次程序中的内容,再次登录也可以访问或修改之前的数据。

一、功能介绍

1.管理员功能介绍
(1)管理员登陆:
若是第一次登陆,管理员文件无数据会自动进入注册页面,将管理员数据保存至文件;
管理员有唯一性,以后只能使用这个管理员账号登录;
输出错误提示是否重新输入。

(2)管理员信息修改:
修改管理员信息可以通过直接修改文件的内容或者系统里修改。

(3)添加新教师:
分为两步:加入链表,加入文件(会在原有数据后继续添加)
在添加中设置了常规的输入限制

(4)显示教师信息:
访问文件读取教师信息(这次登录和之前保存的教师信息都可以显示)

(5)删除教师信息:
由于教师工号做了不重复的功能(不和工号和学号重复),所以教师工号具有唯一性,这里使用工号作为删除的条件,且删除会删除文件和并释放链表中的结点。

(6)修改教师信息:
这里同时实现修改链表结点和文件内容的操作。

注:在这里链表发挥的作用不大,但是为了系统完备还是进行了链表的操作。

缺点:
在进行修改的时候对除了工号的全部信息做了修改,未做指定;

二、main函数和管理员模块

建立目录:
在这里插入图片描述
inc目录文件
在这里插入图片描述
src目录文件
在这里插入图片描述

1.main函数模块

(1)相关头文件
相关函数在函数前有相关注释
admin.h头文件

//admin.h头文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<stdbool.h>
#include<unistd.h>
#include"teacher.h"
#include"student.h"
#define CN 15//账户最高的字长
#define PN 15//密码最高的字长
#define RN 3//最高重输次数
struct admin//管理员信息
{
	char count[CN];
	char password[PN];
};
void in_link_t(struct node1*head_t);
void in_link_s(struct node2*head_s);
void enroll_admin();
int read_admin_judge(struct admin *adm,struct admin adm1);
void read_admin(struct admin *adm);
void free_teacher(struct node1 *head);

bool login();
void modify_admin();

student.h头文件

//student.h头文件
#pragma once
typedef struct Birth
{
	unsigned int year;
	unsigned int month;
	unsigned int day;
}Birth1;
typedef struct student
{
	long id;
	char name[20];
	char gender[4];
	Birth1 birth;
	double Math;
	double Chinese;
	double English;
	char password[15];
}Stu;
struct node2
{
	Stu stu;
	struct node2 *next;
};

void read_student(Stu*s,long id);
bool login_student(long *id);
void modify_student_password_file(long id,char password[]);
void modify_student_password(struct node2*head, long id);
void show_s_info(long id);

teacher.h头文件

//teacher.h头文件
#pragma once
#include"admin.h"
#include"student.h"

typedef struct Birthday
{
	unsigned int year;
	unsigned int month;
	unsigned int day;
}Birth;
typedef struct teacher
{
	long badge;
	char name[20];
	char gender[4];
	Birth birth;
	char password[15];
}Teacher;
struct node1
{
	Teacher t;
	struct node1 *next;	
};
//教师信息的操作函数
struct node1* create_t_node();
int search_t_info_id(struct node1 *head,long badge);
void input_teacher(Teacher *t,struct node1 *head_t,struct node2 *head_s);
bool into_file_t(Teacher t);
void add_teacher_link(struct node1 *head1,struct node2 *head2);
void show_teacher();
void delete_file_teacher(struct node1*p);
void delete_teacher(struct node1 *head,long badge);

//教师的权限
bool login_teacher(long *id);
void modify_teacher_password_file(long id,char password[]);
void modify_teacher_password(struct node1*head, long id);
struct node2* create_s_node();
int search_s_info_id(struct node2 *head,long id);
void input_student(Stu *s,struct node1 *head_t,struct node2 *head_s);
bool into_file_s(Stu s);
void add_student_link(struct node1 *head1,struct node2 *head2);
void seacher_student_id_link(struct node2*head,long id);
void show_student();
void delete_file_student(struct node2*p);
void delete_student(struct node2 *head,long id);
void modify_student(struct node2*head_s,long id);
struct node2*student_order_id(struct node2*head_s);
struct node2*s_max_id(struct node2*head_s);
void delete_max(struct node2*head_s,struct node2*pmax);
void create_newlink(struct node2*new_head,struct node2*pmax);
struct node2* show_by_id(struct node2*head_s);
struct node2* show_by_math(struct node2*head_s);
struct node2* show_by_Chinese(struct node2*head_s);
struct node2* show_by_English(struct node2*head_s);
struct node2* show_by_sum(struct node2*head_s);

viewer.h头文件

//viewer.h
#pragma once
void admin_menu(struct node1*head_t,struct node2*head_s);
void student_menu(long id,struct node2*head_s);
void teacher_menu(long id,struct node1*head_t,struct node2*head_s);

(2)主函数菜单

#include"../inc/admin.h"//引用inc目录内的admin.h头文件
#include"../inc/teacher.h"
#include"../inc/student.h"
#include"../inc/viewer.h"
void main_menu()
{
	int flag=1,code;//循环标志变量和模式变量
	struct node1 *head_t=NULL;
	struct node2 *head_s=NULL;
	head_t=create_t_node();
	head_s=create_s_node();
	while(flag)
	{
		in_link_t(head_t);
		in_link_s(head_s);
		printf("**欢迎进入学生信息管理系统**\n");
		printf("1.管理员登陆.\n");
		printf("2.教师登陆.\n");
		printf("3.学生登陆.\n");
		printf("0.退出系统.\n");
		printf("****************************\n");
		printf("请输入你想登陆的方式:");
		scanf("%d",&code);
		while(getchar()!='\n');
		switch(code)
		{
			case 1:{
					int ret;
					ret=login();
					if(ret==1)
					{
						admin_menu(head_t,head_s);
					}
					break;
				}
			case 2:{
				       long id;
				       int ret;
				       ret=login_teacher(&id);
				       if(ret==1)
				       {
					       teacher_menu(id,head_t,head_s);
				       }
				       break;

			       }
			case 3:{
			       		long id;
					int ret;
					ret=login_student(&id);
					if(ret==1)
					{
						student_menu(id,head_s);
					}
					break;
			       }
			case 0: flag=0;
			        break;
			default:{
					printf("输入有误,请重新输入:");
					scanf("%d",&code);
					while(getchar()!='\n');
				}
		}

	}

}
int main()
{
	main_menu();

}

2.管理员模块

头文件包含:

#include"../inc/admin.h"
#include"../inc/teacher.h"
#include"../inc/student.h"

(2)管理员菜单

/*
 函数功能:管理员菜单
 函数参数:无
 返回值:无
 */
void admin_menu(struct node1*head_t,struct node2*head_s)
{
        int flag=1;
        int code;

        while(flag)
        {
                printf("**欢迎进入管理员界面**\n");
                printf("1.修改管理员信息.\n");
                printf("2.添加新教师.\n");
                printf("3.显示教师信息.\n");
                printf("4.删除教师.\n");
                printf("5.修改教师信息.\n");
                printf("0.返回上一级.\n");
                printf("**********************\n");
                printf("请输入你的选择:");
                scanf("%d",&code);
                while(getchar()!='\n');
                switch(code)
                {
                        case 1:{
                                        modify_admin();
                                        break;
                               }
                        case 2:{
                                        add_teacher_link(head_t,head_s);
                                        break;
                               }
                        case 3:{
                                        show_teacher(head_t);
                                        break;
                               }
                        case 4:{
                                       int flag1=1;
                                       int code1;
                                       while(flag1)
                                       {
                                               printf("1.全部删除.\n");
                                               printf("2.按工号删除.\n");
                                               printf("0.返回上一级.\n");
                                               printf("请输入你的选择:");
                                               scanf("%d",&code1);
                                               while(getchar()!='\n');
                                               switch(code1)
                                               {
                                                       case 1:{
                                                                      char ch;
                                                                      printf("确定要全部删除?(y/n)\n");
                                                                      scanf("%c",&ch);
                                                                      while(getchar()!='\n')
                                                                      if(ch=='Y'||ch=='y')
                                                                      {
                                                                                free_teacher(head_t);
                                                                      }
                                                                        break;
                                                              }
                                                       case 2:{
                                                                        long id;
                                                                        printf("请输入你想删除的教师的工号:");
                                                                        scanf("%ld",&id);
                                                                        while(getchar()!='\n');
                                                                        delete_teacher(head_t,id);
                                                                        break;
                                                              }
                                                       case 0:{
                                                                      flag1=0;
                                                                      break;
                                                              }
                                                       default:{
                                                                        printf("输入有误,请重新输入:");
                                                                        scanf("%d",&code1);
                                                                        while(getchar()!='\n');
                                                                        break;
                                                               }

                                               }
                                       }
                                       break;
                               }
                        case 5:{
                                       long id;
                                       printf("请输入你想修改的教师的工号:");
                                       scanf("%ld",&id);
                                       while(getchar()!='\n');
                                       modify_teacher(head_t,head_s,id);
                                       break;
                               }
                        case 0:{
                                       flag=0;
                                       break;
                               }
                        default:{
                                        printf("输入有误,请重新输入:");
                                        scanf("%d",&code);
                                        while(getchar()!='\n');
                                        break;
                                }

                }
        }
}

(3)读取文件里的数据入链表


```c
/*
 函数功能:将文件中的内容录入链表
 函数参数:教师头结点地址
 返回值:无
 */
void in_link_t(struct node1*head_t)
{
	//打开文件读取数据,预存至结构体
	FILE *ft=NULL;
	struct node1*p=head_t;
	struct node1*pnew=NULL;

	Teacher t;
        int ret1;//保存fscanf的返回值
        ft=fopen("teacher.txt","r");//打开文件读取预存的账户和密码
        assert(ft!=NULL);//判断文件是否已经打开
	while(1)
	{
		ret1=fscanf(ft,"%ld %s %s %u-%u-%u %s\n",&(t.badge),t.name,t.gender,&((t.birth).year),&((t.birth).month),&((t.birth).day),t.password);
		if(ret1<=0)
		{
			break;
		}
		pnew=create_t_node();//创建新结点
		pnew->t=t;
		p->next=pnew;
		p=p->next;

	}
	fclose(ft);
	return ;

}

/*
 函数功能:将文件中的内容录入链表
 函数参数:学生头结点地址
 返回值:无
 */
void in_link_s(struct node2*head_s)
{
        //打开文件读取数据,预存至结构体
        FILE *fs=NULL;
        struct node2*p=head_s;
        struct node2*pnew=NULL;

        Stu s;
        int ret2;//保存fscanf的返回值
        fs=fopen("student.txt","r");//打开文件读取预存的账户和密码
        assert(fs!=NULL);//判断文件是否已经打开
        while(1)
        {
                ret2=fscanf(fs,"%ld %s %s %u-%u-%u %s %lf %lf %lf\n",&(s.id),s.name,s.gender,&((s.birth).year),&((s.birth).month),&((s.birth).day),s.password,&(s.Math),&(s.Chinese),&(s.English));
		if(ret2<=0)
                {
                        break;
                }
                pnew=create_s_node();//创建新结点
                pnew->stu=s;
                p->next=pnew;
                p=p->next;

        }
        fclose(fs);
        return;

}

(4)管理员登录与注册函数组(main菜单功能1)

/*
 函数功能:管理员注册
 函数参数:无
 返回值:无
 */
void enroll_admin()
{
	//读文件数据
	FILE *fp=NULL;
	fp=fopen("admin.txt","w");//打开文件写入账户和密码
	assert(fp!=NULL);//判断文件是否已经打开
	//输入
	struct admin adm;
	printf("**欢迎进入注册界面**\n");
	printf("\n");
	printf("请输入新账户:");//登陆,输入账户和密码
        scanf("%s",adm.count);//记录到结构体变量中
        while(getchar()!='\n');
        printf("请输入密码:");
        scanf("%s",adm.password);
        while(getchar()!='\n');
	fprintf(fp,"%s %s",adm.count,adm.password);//写入账户和密码
	printf("注册成功!\n");
	printf("\n");

	fclose(fp);//关闭文件
	return;
}

/*
 函数功能:读取管理员并判断
 函数参数:管理员结构体变量,用户输入的管理员结构体
 返回值:无
 函数说明:循环读取文件内容,找到符合的数据退出
 */
int read_admin_judge(struct admin *adm,struct admin adm1)
{
	FILE *fp=NULL;
	fp=fopen("admin.txt","r");//打开文件读取预存的账户和密码
	assert(fp!=NULL);//判断文件是否已经打开
	int ret;//保存fscanf的返回值
	ret=fscanf(fp,"%s %s",adm->count,adm->password);//读出文件中的账户和密码
	if(ret<=0)//如果未读取到数据,遇到错误或者读到文件末尾
	{
		printf("无账户信息\n");//测试
		fclose(fp);
		return -1;
	}
	if((strcmp(adm->count,adm1.count)==0)&&(strcmp(adm->password,adm1.password)==0))
	{
		fclose(fp);
		return 1;
	}else
	{
		fclose(fp);
		return 0;
	}
}

/*
 函数功能:管理员登陆
 函数参数:预定义的管理员结构体
 返回值:登陆成功返回1,失败返回0
 */
bool login()
{
	struct admin adm;//读输入
	struct admin adm1;//读文件
	int n=RN;//最高重新输入的次数
	char ch;//是否重新输入
	int ret;

	FILE *fp=NULL;
	fp=fopen("admin.txt","r");//打开文件读取预存的账户和密码
	assert(fp!=NULL);//判断文件是否已经打开
	ret=fscanf(fp,"%s %s",adm1.count,adm1.password);//读出文件中的账户和密码
	if(ret<=0)
	{
		fclose(fp);
		printf("库中无管理员信息!\n");
		printf("第一次登陆,请建立新的管理员!\n");
		printf("正在跳转注册界面,请稍等.........\n");
		sleep(3);
		printf("\n\n");
		enroll_admin();
	}
	printf("**管理员登陆界面**\n");
	printf("请输入账户:");//登陆,输入账户和密码
	scanf("%s",adm.count);//记录到结构体变量中
	while(getchar()!='\n');
	printf("请输入密码:");
	scanf("%s",adm.password);
	while(getchar()!='\n');
	//fclose(fp);

	ret=read_admin_judge(&adm1,adm);//读取文件中的账户名和密码,并判断
	if(ret==0)
	{
		while(1)
		{	
			printf("登陆失败!\n");
			printf("您还有%d次重新输入的机会!\n",n);
			printf("是否重新输入(y/n):");
			scanf("%c",&ch);
			while(getchar()!='\n');
			if(ch=='n'||ch=='N')//判断是否重新输入
			{
				return false;
			}
			if(n==0)
			{
				return false;
			}
	
			printf("请重新输入账户:");
			scanf("%s",adm.count);
			while(getchar()!='\n');
	
			printf("请重新输入密码:");
			scanf("%s",adm.password);
			while(getchar()!='\n');
			ret=read_admin_judge(&adm1,adm);//读取文件中的账户名和密码,并判断
			if(ret==1)
			{
				break;
			}
			n--;
		}
	}
	return true;
	
}

(5)管理员信息修改函数(admin菜单功能1)

/*
 函数功能:读取管理员
 函数参数:管理员结构体变量
 返回值:无
 */
void read_admin(struct admin *adm)
{
	FILE *fp=NULL;
	fp=fopen("admin.txt","r");//打开文件读取预存的账户和密码
	assert(fp!=NULL);//判断文件是否已经打开
	int ret;//保存fscanf的返回值
	ret=fscanf(fp,"%s %s",adm->count,adm->password);//读出文件中的账户和密码
	if(ret<=0)//如果未读取到数据,遇到错误或者读到文件末尾
	{
		printf("文件读取失败!\n");
		fclose(fp);
		assert(ret>0);//结束进程
	}
	fclose(fp);//关闭文件
	return ;
}
/*
 函数功能:修改管理员信息
 函数参数:无
 返回值:无
 */
void modify_admin()
{
        FILE *fp=NULL;
	struct admin adm;
	int flag=1;
	int code;

 	read_admin(&adm);//读取文件中的管理员信息
	while(flag)
	{
		printf("\n");
		printf("**欢迎进入管理员界面**\n");
		printf("1.修改管理员账户名.\n");
		printf("2.修改管理员密码.\n");
		printf("0.返回上一级.\n");
		printf("**********************\n");
		printf("请输入你的选择:");
		scanf("%d",&code);
		while(getchar()!='\n');
		switch(code)
		{
			case 1: {
					printf("请输入新的管理员账户名:");
					scanf("%s",adm.count);
					while(getchar()!='\n');
        				fp=fopen("admin.txt","w");//以重写的方式打开文件
       					 assert(fp!=NULL);
					int ret;
					ret=fprintf(fp,"%s %s",adm.count,adm.password);
					if(ret<=0)
					{
						printf("修改失败!\n");
						fclose(fp);//关闭文件
						break;
					}
					printf("修改成功!\n");
					fclose(fp);//关闭文件
					break;
				}
			case 2: {	
					printf("请输入新的管理员密码:");
					scanf("%s",adm.password);
					while(getchar()!='\n');
        				fp=fopen("admin.txt","w");//以重写的方式打开文件
       					 assert(fp!=NULL);
					int ret;
					ret=fprintf(fp,"%s %s",adm.count,adm.password);
					if(ret<=0)
					{
						printf("修改失败!\n");
						fclose(fp);//关闭文件
						break;
					}
					printf("修改成功!\n");
					fclose(fp);//关闭文件
					break;
				}
			case 0: {	
					flag=0;
					break;
				}
			default:{
					printf("输入有误,请重新输入:");
					scanf("%d",&code);
					while(getchar()!='\n');
					break;
				}

		}
	}
	return;
}
/*

(6)添加教师(admin功能2)
内部包含链表操作和文件操作

/*
 函数功能:创造教师结点
 函数参数:无
 返回值:结点的地址
 */
struct node1* create_t_node()
{
        struct node1*pnew=NULL;
        pnew=(struct node1*)malloc(sizeof(struct node1));
        assert(pnew!=NULL);
        pnew->next=NULL;
        return pnew;
}
/*
 函数功能:通过学号查找教师
 函数参数:教师链表的头结点地址,搜索学号
 返回值:int型数据
 函数说明:(辅助教师信息添加函数)
          若未找到返回0,若找到了返回1
 */
int search_t_info_id(struct node1 *head,long badge)
{
        struct node1 *p=head->next;//p指针指向第一个教师结点
        if(head->next==NULL)//判断是否为空链表
        {
                return 0;
        }
        while(((p->t).badge)!=badge)//如果未找到
        {
                p=p->next;
                if(p==NULL)//如果遍历链表都未找到
                {
                        return 0;//未找到
                }
        }
        return 1;//找到了

}

/*
 函数功能:输入教师的信息
 函数参数:教师信息结构体地址,教师链表的头结点地址,学生链表的头结点地址
 返回值:无
 函数说明:只录入一个教师信息
 */
void input_teacher(Teacher *t,struct node1 *head_t,struct node2 *head_s)
{
	int ret1;//接收老师id查找返回值
	int ret2;//接收学生id查找返回值
	long badge;//工号
	char name[20];//姓名
	char gender[4];//性别
	char password[15];//密码
	unsigned int year,month,day;//出生年月日
	unsigned int DAY_p[12]={31,28,31,30,31,30,31,31,30,31,30,31};
	unsigned int DAY_r[12]={31,29,31,30,31,30,31,31,30,31,30,31};

	//工号重复判断
	printf("请输入教师的工号:");
	scanf("%ld",&badge);
	while(getchar()!='\n');
	ret1=search_t_info_id(head_t,badge);//教师链表查找
	ret2=search_s_info_id(head_s,badge);//学生链表查找
	//printf("工号重复检测:\n");
	//如果工号重复
	while(ret1==1||ret2==1)
	{
		printf("工号重复,请重新输入:");
		scanf("%ld",&badge);
		while(getchar()!='\n');
		ret1=search_t_info_id(head_t,badge);//重新查找
		ret2=search_s_info_id(head_s,badge);
	}
		//输入姓名
		printf("请输入教师的姓名:");
		scanf("%s",name);
		while(getchar()!='\n');
		//输入性别
		printf("请输入教师的性别(男或女):");
		scanf("%s",gender);
		while(getchar()!='\n');
		while(strcmp("男",gender)!=0&&strcmp("女",gender)!=0)
		{
			printf("性别有误,请重新输入性别:");
			scanf("%s",gender);
			while(getchar()!='\n');

		}
		//输入年
		printf("请输入教师的生日的年份(1953-2023):");
		scanf("%u",&year);
		while(getchar()!='\n');
		while(year>2023||year<1953)
		{
			printf("年份有误,请重新输入年份:");
			scanf("%d",&year);
			while(getchar()!='\n');
		}
		//输入月
		printf("请输入教师的生日的月份(1-12):");
		scanf("%u",&month);
		while(getchar()!='\n');
		while(month>12||month<1)
		{
			printf("月份有误,请重新输入月份:");
			scanf("%u",&month);
			while(getchar()!='\n');
		}
		//输入日
		printf("请输入教师的生日的日(1-12):");
		scanf("%u",&day);
		while(getchar()!='\n');
		//判断是否是闰年
		if((year%4==0&&year%100!=0)||year%400==0)//是闰年
		{
			while(day>DAY_r[month-1]||day<1)
			{
				printf("日期有误,请重新输入日期:");
				scanf("%u",&day);
				while(getchar()!='\n');
			}
		}else//不是闰年
		{
			while(day>DAY_p[month-1]||day<1)
			{
				printf("日期有误,请重新输入日期:");
				scanf("%u",&day);
				while(getchar()!='\n');
			}
		}
		//输入密码
		printf("请输入教师的登陆密码(最高15字符):");
		scanf("%s",password);
		while(getchar()!='\n');
		
		//将合法的数据输入教师信息的结构体
		t->badge=badge;
		strcpy(t->name,name);
		strcpy(t->gender,gender);
		(t->birth).year=year;
		(t->birth).month=month;
		(t->birth).day=day;
		strcpy(t->password,password);
		return ;
	
}

/*
 函数功能:将教师信息录入文件中
 函数参数:教师信息结构体
 返回值:布尔类型
 函数说明:若是写入文件成功返回1,不成功返回0
 */
bool into_file_t(Teacher t)
{
	FILE *fp=NULL;
	fp=fopen("teacher.txt","a");
	assert(fp!=NULL);
	int ret;
	ret=fprintf(fp,"%ld %s %s %u-%u-%u %s\n",t.badge,t.name,t.gender,(t.birth).year,(t.birth).month,(t.birth).day,t.password);
	if(ret>0)
	{
		fclose(fp);
		return true;
	}else
	{
		fclose(fp);
		return false;
	}
}
/*
 函数功能:循环添加新教师
 函数参数:教师链表的头结点地址,学生头结点地址(用于防止工号重复)
 返回值:无
 函数说明:使用尾插法实现结点的添加
 */
void add_teacher_link(struct node1 *head1,struct node2 *head2)
{
	struct node1 *tail=NULL;
	struct node1 *pnew=NULL;
	int ret2;//接收文件录入返回值
	char ch;//判断是否继续录入信息

	//找到链表中的尾部
	if(head1->next!=NULL)//如果链表不为空
	{
		tail=head1->next;//尾指针指向第一个结点
		while(tail->next!=NULL)//尾指针的next不是空
		{
			tail=tail->next;//尾指针移动
		}
	}

	//创造并用尾插法插入结点
	while(1)
	{
		pnew=create_t_node();
		//printf("创建结点成功!\n");//测试
		input_teacher(&(pnew->t),head1,head2);
		printf("录入成功!\n");
		ret2=into_file_t(pnew->t);
		if(ret2==0)//测试是否成功读入文件
		{
			printf("录入文件失败!\n");
			break;
		}
		//printf("录入文件成功!\n");
		//如果是空链表
		if(head1->next==NULL)
		{
			head1->next=pnew;
			tail=pnew;
		}else
		{
			tail->next=pnew;
			tail=pnew;
		}

		printf("是否继续录入教师信息(y/n):");
		scanf("%c",&ch);
		while(getchar()!='\n');
		if((ch!='y'||ch!='Y')&&(ch=='n'||ch=='N'))
		{
			break;
		}
	}
	return;
}

(7)显示教师信息(admin功能3)

/*
 函数功能:显示教师信息
 函数参数:无
 返回值:无
 函数说明:打开文件读取数据
 */
void show_teacher()
{
	FILE *fp=NULL;
	int ret;
	Teacher t;
	fp=fopen("teacher.txt","r");
	assert(fp!=NULL);
	printf("工号\t姓名\t性别\t出生日期\t登陆密码\n");
	while(1)
	{
		ret=fscanf(fp,"%ld %s %s %u-%u-%u %s\n",&(t.badge),t.name,t.gender,&((t.birth).year),&((t.birth).month),&((t.birth).day),t.password);
		if(ret<=0)
		{
			break;
		}
		printf("%ld\t%s\t%s\t%u-%u-%u\t%s\n",t.badge,t.name,t.gender,(t.birth).year,(t.birth).month,(t.birth).day,t.password);
	}
	fclose(fp);
	return;
}

(8)删除教师信息(admin功能4)
这里包含删除文件和链表的操作,包含清空和根据工号删除两种操作。

/*
 函数功能:删除文件中的教师信息
 函数参数:要删除的结点的位置
 返回值:无
 函数说明:建立另一个文件接收与欲删除数据不同的数据,
          然后删除源文件重命名新文件
 */
void delete_file_teacher(struct node1*p)
{
	FILE *fp=NULL,*ft=NULL;
	int ret1;
	Teacher set;
	fp=fopen("teacher.txt","rt+");
	ft=fopen("temp.txt","wt");
	assert(fp!=NULL&&ft!=NULL);
	while(1)
	{
		ret1=fscanf(fp,"%ld %s %s %u-%u-%u %s\n",&(set.badge),set.name,set.gender,&((set.birth).year),&((set.birth).month),&((set.birth).day),set.password);
		if(ret1<=0)
		{
			break;
		}
		//printf("%ld %s %s %u-%u-%u\n",set.badge,set.name,set.gender,(set.birth).year,(set.birth).month,(set.birth).day);//测试
		if((p->t).badge!=set.badge)
		{
			fprintf(ft,"%ld %s %s %u-%u-%u %s\n",set.badge,set.name,set.gender,(set.birth).year,(set.birth).month,(set.birth).day,set.password);
		}
	}
	rewind(fp);
	fclose(fp);
	fclose(ft);
	remove("teacher.txt");
	rename("temp.txt","teacher.txt");
	printf("文件删除成功!\n");//测试
	return;
}

/*
 函数功能:通过工号删除教师信息
 函数参数:无
 返回值:无
 */
void delete_teacher(struct node1 *head,long badge)
{
	//找到工号对应的结点地址
        struct node1 *p=head->next;
        if(head->next==NULL)//判断是否为空链表
        {
		printf("有误,无教师信息!\n");
                return;
        }
        while(((p->t).badge)!=badge)//如果未找到
        {
                head=head->next;
		p=p->next;
                if(p==NULL)//如果遍历链表都未找到
                {
			printf("工号错误!\n");
                        return;
                }
        }
	head->next=p->next;
	delete_file_teacher(p);
	free(p);
	printf("删除成功!\n");
	return;

}

/*
 函数功能:清空教师信息
 函数参数:教师头结点地址
 返回值:无
 */
void free_teacher(struct node1 *head)
{
	//free除头结点以外的结点
	struct node1*p=head->next;
	struct node1*q=p;
	while(p!=NULL)
	{
		p=p->next;
		free(q);
		q=p;
	}
	head->next=NULL;
	//删除文件内容
	FILE *fp=NULL;
	fp=fopen("./teacher.txt","w");
	assert(fp!=NULL);
	fclose(fp);
	printf("删除成功!\n");
	return;
}

(9)修改教师信息(admin功能5)
这里文件和链表操作放在一个函数里了。

/*
 函数功能:修改教师信息
 函数参数:教师头结点地址,学生头结点地址,修改的工号
 返回值:无
 */
void modify_teacher(struct node1*head_t,struct node2*head_s,long badge)
{
	//找到工号对应的结点地址
        struct node1 *p=head_t->next;
        if(head_t->next==NULL)//判断是否为空链表
        {
                printf("有误,无教师信息!\n");
                return;
        }
        while(((p->t).badge)!=badge)//如果未找到
        {
                p=p->next;
                if(p==NULL)//如果遍历链表都未找到
                {
                        printf("工号错误!\n");
                        return;
                }
        }
	//修改链表中的信息
	char name[20];//姓名
	char gender[4];//性别
	char password[15];//密码
	unsigned int year,month,day;//出生年月日
	unsigned int DAY_p[12]={31,28,31,30,31,30,31,31,30,31,30,31};
	unsigned int DAY_r[12]={31,29,31,30,31,30,31,31,30,31,30,31};
//输入姓名
		printf("请输入教师的姓名:");
		scanf("%s",name);
		while(getchar()!='\n');
		//输入性别
		printf("请输入教师的性别(男或女):");
		scanf("%s",gender);
		while(getchar()!='\n');
		while(strcmp("男",gender)!=0&&strcmp("女",gender)!=0)
		{
			printf("性别有误,请重新输入性别:");
			scanf("%s",gender);
			while(getchar()!='\n');

		}
		//输入年
		printf("请输入教师的生日的年份(1953-2023):");
		scanf("%u",&year);
		while(getchar()!='\n');
		while(year>2023||year<1953)
		{
			printf("年份有误,请重新输入年份:");
			scanf("%d",&year);
			while(getchar()!='\n');
		}
		//输入月
		printf("请输入教师的生日的月份(1-12):");
		scanf("%u",&month);
		while(getchar()!='\n');
		while(month>12||month<1)
		{
			printf("月份有误,请重新输入月份:");
			scanf("%u",&month);
			while(getchar()!='\n');
		}
		//输入日
		printf("请输入教师的生日的日(1-12):");
		scanf("%u",&day);
		while(getchar()!='\n');
		//判断是否是闰年
		if((year%4==0&&year%100!=0)||year%400==0)//是闰年
		{
			while(day>DAY_r[month-1]||day<1)
			{
				printf("日期有误,请重新输入日期:");
				scanf("%u",&day);
				while(getchar()!='\n');
			}
		}else//不是闰年
		{
			while(day>DAY_p[month-1]||day<1)
			{
				printf("日期有误,请重新输入日期:");
				scanf("%u",&day);
				while(getchar()!='\n');
			}
		}
		//输入密码
		printf("请输入教师的登陆密码(最高15字符):");
		scanf("%s",password);
		while(getchar()!='\n');
		
		//将合法的数据输入教师信息的结构体
		(p->t).badge=badge;
		strcpy((p->t).name,name);
		strcpy((p->t).gender,gender);
		((p->t).birth).year=year;
		((p->t).birth).month=month;
		((p->t).birth).day=day;
		strcpy((p->t).password,password);
	
	//修改文件中的信息
		FILE *fp=NULL,*ft=NULL;
       	 	int ret1;
        	Teacher set;
        	fp=fopen("teacher.txt","rt+");
        	ft=fopen("temp.txt","wt");
        	assert(fp!=NULL&&ft!=NULL);
        	while(1)
        	{
                	ret1=fscanf(fp,"%ld %s %s %u-%u-%u %s\n",&(set.badge),set.name,set.gender,&((set.birth).year),&((set.birth).month),&((set.birth).day),set.password);
                if(ret1<=0)
                {
                        break;
                }
                if((p->t).badge==set.badge)
                {
			strcpy(set.name,name);
			strcpy(set.gender,gender);
			(set.birth).year=year;
			(set.birth).month=month;
			(set.birth).day=day;
			strcpy(set.password,password);
                }
                        fprintf(ft,"%ld %s %s %u-%u-%u %s\n",set.badge,set.name,set.gender,(set.birth).year,(set.birth).month,(set.birth).day,set.password);
        }
        rewind(fp);
        fclose(fp);
        fclose(ft);
        remove("teacher.txt");
        rename("temp.txt","teacher.txt");
        //printf("文件删除成功!\n");//测试

	printf("修改成功!\n");
	return;


}

总结

  1. 这里使用了链表和文件的相关知识,代码写的不够简洁,有些代码多次重复,没有做好独立性,但是基本的功能是可以完全实现的。
  2. 关于教师文件内容更新的方法其实可以改进,既然使用了链表其实可以在将文件数据传链表之后,让文件每次以"w"的形式打开,然后增删改查都用链表来实现,只要在操作结束后将链表中的内容传给文件即可。这样也可以保证文件的类“数据库”功能,而且也极大的缩短了代码。
  3. 本人使用这种方式也是为了更多的应用自己学过的知识,不追求代码的简洁性,有兴趣的伙伴,可以试试2的思路。
  • 3
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言学生成绩管理系统(以包含文件的形式写的),结构体,链表,数组,以下是main.c #include #include #include #define m 3/*宏定义m的值为3*/ struct node/*链表初始化*/ { char name[20]; int no; float score[m]; float sum; float avg; struct node *next; }; char ch[m+4][20]={{"学号"},{"姓名"},{"语文"},{"数学"},{"英语"},{"总分"},{"平均分"}};/*定义并初始化一个全局二维字符数组*/ #include "save.c"/*包含保存文件*/ #include "read.c"/*包含读取文件*/ #include "output.c"/*包含打印文件*/ #include "set.c"/*包含录入文件*/ #include "demand.c"/*包含查询文件*/ #include "sort.c"/*包含排序文件*/ #include "modified.c"/*包含修改文件*/ #include "add.c"/*包含添加文件*/ #include "del.c"/*包含删除文件*/ void main() { int n; printf("\n\t\t\t欢迎使用学生成绩管理系统\n\n"); printf("\t\t\t\t\t\t制 作: XIA XIA\n"); do { printf("\n\n1:学生成绩录入,并保存\n"); printf("2:学生成绩查询\n"); printf("3:学生成绩的排序\n"); printf("4:学生成绩的修改\n"); printf("5:学生成绩的打印\n"); printf("6:学生信息的添加\n"); printf("7:学生信息的删除\n"); printf("0:退出学生成绩管理系统\n\n\n"); printf("输入你要执行操作的相应序号\n"); scanf("%d",&n);/*输入相就的操作的序号*/ switch (n) { case 1: set();break;/*调用录入函数*/ case 2: demand();break;/*调用查询函数*/ case 3: sort();break;/*调用排序函数*/ case 4: modified();break;/*调用修改函数*/ case 5: output();break;/*调用打印函数*/ case 6: add();break;/*调用添加函数*/ case 7: del();break;/*调用删除函数*/ case 0: printf("正在退出学生成绩管理系统......\n");exit(0);/*直到输入“0”退出学生成绩管理系统*/ default:printf("输入错误码,请重新输入\n"); } }while(1); }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值