前言
本系统核心是使用链表和文件,可以实现基本功能,并且可以实现多次复用,文件内的内容相当于数据库,可以保存运行多次程序中的内容,再次登录也可以访问或修改之前的数据。
一、功能介绍
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;
}
总结
- 这里使用了链表和文件的相关知识,代码写的不够简洁,有些代码多次重复,没有做好独立性,但是基本的功能是可以完全实现的。
- 关于教师文件内容更新的方法其实可以改进,既然使用了链表其实可以在将文件数据传链表之后,让文件每次以"w"的形式打开,然后增删改查都用链表来实现,只要在操作结束后将链表中的内容传给文件即可。这样也可以保证文件的类“数据库”功能,而且也极大的缩短了代码。
- 本人使用这种方式也是为了更多的应用自己学过的知识,不追求代码的简洁性,有兴趣的伙伴,可以试试2的思路。