信息存取实现
信息类型
我设计的学生信息管理系统有三种类型的信息,分别是教师信息、学生信息和账户信息,所以我设计了三种结构体类型和他们各自的结点类型。学生有姓名、学号和成绩这些信息,教师有姓名、工号、班级这些信息,账户有姓名和密码。(学生的学号和教师的工号是为了防止重名的情况导致查找错误)
typedef struct Student {
char name[20];
char number[20];
char class[20];
int chinese;
int math;
int english;
int sum;
}student;
typedef struct Snode {
student student;
struct node* next;
}snode;
typedef struct Account {
char name[20];
char keyword[20];
}account;
typedef struct Accountnode {
account account;
struct Accountnode* next;
}accountnode;
typedef struct Teacher {
char name[20];
char class[20];
char number[20];
}teacher;
typedef struct Tnode {
teacher teacher;
struct Tnode* next;
}tnode;
读取和写入文件
因为我有六个结构体类型,三个结点类型,所以我需要分别写三对从文件中读取信息保存到链表中和从链表中读取信息保存到文件里的函数。
void save(snode* head) {
FILE* fp = fopen("student.txt", "w");
if (fp == NULL) {
printf("打开文件失败\n");
return;
}
snode* move = head->next;
while (move != NULL)
{
if (fwrite(&move->student, sizeof(student), 1, fp) != 1)
{
printf("写入数据失败!\n");
return;
}
move = move->next;
}
fclose(fp);
fp = NULL;
return;
} //写入学生信息
void savet(tnode* head) {
FILE* fp = fopen("teacher.txt", "w");
if (fp == NULL) {
printf("打开文件失败\n");
return;
}
tnode* move = head->next;
while (move != NULL)
{
if (fwrite(&move->teacher, sizeof(teacher), 1, fp) != 1)
{
printf("写入数据失败!\n");
return;
}
move = move->next;
}
fclose(fp);
fp = NULL;
return;
} //写入教师信息
void savea(accountnode* head) {
FILE* fp = fopen("account.txt", "w");
if (fp == NULL) {
printf("打开文件失败\n");
return;
}
accountnode* move = head->next;
while (move != NULL)
{
if (fwrite(&move->account, sizeof(account), 1, fp) != 1)
{
printf("写入数据失败!\n");
return;
}
move = move->next;
}
fclose(fp);
fp = NULL;
return;
} //写入账户信息
void load(snode* head) {
FILE* file = fopen("student.txt", "r");
if (!file) {
printf("未找到学生信息文件,跳过读取\n");
return;
}
snode* new = malloc(sizeof(snode));
new->next = NULL;
snode* move = head;
while (fread(&new->student, sizeof(student), 1, file) == 1) {
move->next = new;
move = new;
new = malloc(sizeof(snode));
new->next = NULL;
}
free(new);
fclose(file);
printf("读取成功!\n");
} //加载学生信息
void loadt(tnode* head) {
FILE* file = fopen("teacher.txt", "r");
if (!file) {
printf("未找到老师信息文件,跳过读取\n");
return;
}
tnode* new = malloc(sizeof(tnode));
new->next = NULL;
tnode* move = head;
while (fread(&new->teacher, sizeof(teacher), 1, file) == 1) {
move->next = new;
move = new;
new = malloc(sizeof(tnode));
new->next = NULL;
}
free(new);
fclose(file);
printf("读取成功!\n");
} //加载教师信息
void loada(accountnode* head) {
FILE* file = fopen("account.txt", "r");
if (!file) {
printf("未找到账号信息文件,跳过读取\n");
return;
}
accountnode* new = malloc(sizeof(accountnode));
new->next = NULL;
accountnode* move = head;
while (fread(&new->account, sizeof(account), 1, file) == 1) {
move->next = new;
move = new;
new = malloc(sizeof(accountnode));
new->next = NULL;
}
free(new);
fclose(file);
printf("读取成功!\n");
} //加载账户信息
登录与注册
注册账号
按照实验室要求,账号注册是在管理员端完成的。管理员端可以进行新增学生信息、注册学生账号、注册教师账号等操作,但并没有新增教师信息的操作,注册教师信息时要添加教师的工号和班级等信息,所以要将注册学生账号、注册教师账号分开来实现。
注册学生账号:
void sregister(accountnode* head,tnode* thead,snode* shead) {
printstudents(shead);
accountnode* cur = head;
char name[20], keyword[2000];
while (cur->next != NULL) {
cur = cur->next;
}
printf("\n请输入学生姓名!\n");
scanf("%s", name);
do {
printf("请输入学生密码\n");
scanf("%s", keyword);
} while (strlen(keyword) < 0 || strlen(keyword) > 15);
accountnode* new = (accountnode*)malloc(sizeof(accountnode));
new->next = NULL;
strcpy(new->account.name, name);
strcpy(new->account.keyword, keyword);
cur->next = new;
savea(head);
printf("注册成功!\n");
aregister(head, thead, shead);
}
注册老师账号:
void tregister(accountnode* head, tnode* thead, snode* shead) {
printteachers(thead);
accountnode* cur = head;
char name[20], keyword[20], class[20], num[20];
while (cur->next != NULL) {
cur = cur->next;
}
tnode* curt = thead;
while (curt->next != NULL) {
curt = curt->next;
}
printf("\n请输入老师姓名!\n");
scanf("%s", name);
printf("请输入老师班级!\n");
scanf("%s", class);
printf("请输入老师密码!\n");
do {
printf("请输入老师密码\n");
scanf("%s", keyword);
} while (strlen(keyword) < 0 || strlen(keyword) > 15);
printf("请输入老师工号!\n");
tnode* curt1 = thead;
while (curt1 != NULL) {
while (strcmp(curt1->teacher.number, num) == 0) {
printf("该工号已存在!\n");
printf("请重新输入工号!\n");
scanf("%s", num);
}
curt1 = curt1->next;
}
accountnode* new = (accountnode*)malloc(sizeof(accountnode));
new->next = NULL;
strcpy(new->account.name, name);
strcpy(new->account.keyword, keyword);
cur->next = new;
savea(head); //保存账户信息
tnode* newt = (tnode*)malloc(sizeof(tnode));
newt->next = NULL;
strcpy(newt->teacher.name, name);
strcpy(newt->teacher.class, class);
strcpy(newt->teacher.number, num);
curt->next = newt;
savet(thead); //保存教师信息
system("pause");
system("cls");
aregister(head, thead, shead);
}
账号登录
账号登陆要分别实现三端登录,所以要写三个登录函数,分别是学生端,教师端和管理员登录,其中,管理应该只有一套账密并且不可更改密码,因此不需要设计新的文件来保存管理员信息,只需在设计时先假设好管理员的密码即可。
学生登录
void slogin(accountnode* head, snode* shead, tnode* thead, account* ahead) {
accountnode* move = head->next;
snode* node = shead->next;
char name[20];
char keyword[20];
printf("请输入学生的姓名!\n");
scanf("%s", name);
while (move != NULL) {
if (strcmp(move->account.name, name) == 0) {
int cnt = 5;
printf("请输入密码!\n");
while (cnt--) {
int i;
char p = 0;
for (i = 0; i < 15; i++) {
p = _getch();
if (p == 13) {
break;
}
if (p != '\b') {
keyword[i] = p;
printf("*");
}
else {
printf("\b \b");
i -= 2;
}
} //密码隐式输入
if (i == 15) {
printf("\n密码输入过长!\n");
}
keyword[i] = '\0';
if (strcmp(keyword, move->account.keyword) == 0) {
printf("登陆成功!\n");
system("pause");
system("cls");
snode* cur = shead->next;
while (cur != NULL) {
if (strcmp(cur->student.name, move->account.name) == 0) {
node = cur;
break;
}
cur = cur->next;
}
smenu(move, node, shead, thead, ahead);
return;
}
else {
printf("密码错误!\n");
}
printf("你还有%d次机会输入密码!\n", cnt);
}
exit(0);
}
else {
move = move->next;
}
}
printf("未找到该学生!\n");
}
教师登录
void tlogin(accountnode* head, snode* shead, tnode* thead) {
accountnode* move = head->next;
tnode* node = thead->next;
char name[20];
char keyword[20];
printf("请输入老师的姓名!\n");
scanf("%s", name);
while (move != NULL) {
if (strcmp(move->account.name, name) == 0) {
tnode* cur = thead->next;
while (cur != NULL) {
if (strcmp(cur->teacher.name, move->account.name) == 0) {
break;
}
else {
cur = cur->next;
}
if (cur == NULL) {
printf("该账号为学生账号!\n");
return;
}
}
printf("请输入密码!\n");
int cnt = 5;
while (cnt--) {
int i;
char p = 0;
for (i = 0; i < 15; i++) {
p = _getch();
if (p == 13) {
break;
}
if (p != '\b') {
keyword[i] = p;
printf("*");
}
else {
printf("\b \b");
i -= 2;
}
}
if (i == 15) {
printf("\n密码输入过长!\n");
}
keyword[i] = '\0';
if (strcmp(keyword, move->account.keyword) == 0) {
printf("登陆成功!\n");
system("pause");
system("cls");
tnode* cur = thead->next;
while (cur != NULL) {
if (strcmp(cur->teacher.name, move->account.name) == 0) {
node = cur;
break;
}
cur = cur->next;
}
tmenu(move, node, shead);
loginmenu(shead, thead, head);
}
else {
printf("密码错误!\n");
}
printf("你还有%d次输入密码的机会\n", cnt);
}
}
else {
move = move->next;
}
exit(0);
}
printf("未找到该老师!\n");
}
管理员登录
void tlogin(accountnode* head, snode* shead, tnode* thead) {
accountnode* move = head->next;
tnode* node = thead->next;
char name[20];
char keyword[20];
printf("请输入老师的姓名!\n");
scanf("%s", name);
while (move != NULL) {
if (strcmp(move->account.name, name) == 0) {
tnode* cur = thead->next;
while (cur != NULL) {
if (strcmp(cur->teacher.name, move->account.name) == 0) {
break;
}
else {
cur = cur->next;
}
if (cur == NULL) {
printf("该账号为学生账号!\n");
return;
}
}
printf("请输入密码!\n");
int cnt = 5;
while (cnt--) {
int i;
char p = 0;
for (i = 0; i < 15; i++) {
p = _getch();
if (p == 13) {
break;
}
if (p != '\b') {
keyword[i] = p;
printf("*");
}
else {
printf("\b \b");
i -= 2;
}
}
if (i == 15) {
printf("\n密码输入过长!\n");
}
keyword[i] = '\0';
if (strcmp(keyword, move->account.keyword) == 0) {
printf("登陆成功!\n");
system("pause");
system("cls");
tnode* cur = thead->next;
while (cur != NULL) {
if (strcmp(cur->teacher.name, move->account.name) == 0) {
node = cur;
break;
}
cur = cur->next;
}
tmenu(move, node, shead);
loginmenu(shead, thead, head);
}
else {
printf("密码错误!\n");
}
printf("你还有%d次输入密码的机会\n", cnt);
}
}
else {
move = move->next;
}
exit(0);
}
printf("未找到该老师!\n");
}
管理员菜单界面
管理员可以实现的功能有:增加学生、删除学生、修改学生、查询年纪总成绩、注册教师和学生的账号、修改账号密码、注销账号、删除教师信息、返回上一层菜单。
增删改查学生信息都是对学生信息链表做操作,注册和修改账号密码是对账户链表做操作,删除教师信息是对教师信息链表做操作。
增加学生
void addstudent(snode* head) {
snode* cur = head;
char name[20], class[20], num[20];
int chinese, math, english, m;
while (cur->next != NULL) {
cur = cur->next;
}
printf("\n请输入学生姓名!\n");
scanf("%s", name);
printf("请输入学生班级\n");
scanf("%s", class);
printf("请输入学号\n");
scanf("%s", num);
snode* cur1;
cur1 = head->next;
while (cur1 != NULL) {
while (strcmp(cur1->student.number, num) == 0) {
printf("该学号已存在!\n");
printf("请重新输入学号!\n");
scanf("%s", num);
}
cur1 = cur1->next;
}
printf("请输入学生语文成绩!\n");
do {
m = scanf("%d", &chinese);
if (m != 1) {
while (getchar() != '\n');
printf("请重新输入!\n");
}
} while (m != 1 || chinese > 100 || chinese < 0);
printf("请输入学生数学成绩!\n");
do {
m = scanf("%d", &math);
if (m != 1) {
while (getchar() != '\n');
printf("请重新输入!\n");
}
} while (m != 1 || math > 100 || math < 0);
printf("请输入学生英语成绩!\n");
do {
m = scanf("%d", &english);
if (m != 1) {
while (getchar() != '\n');
printf("请重新输入!\n");
}
} while (m != 1 || english > 100 || english < 0);
snode* new = (snode*)malloc(sizeof(snode));
new->next = NULL;
strcpy(new->student.name, name);
strcpy(new->student.class, class);
strcpy(new->student.number, num);
new->student.sum = chinese + math + english;
new->student.chinese = chinese;
new->student.math = math;
new->student.english = english;
cur->next = new;
save(head);
return;
}
删除学生
void deleteastudent(snode* head) {
list(head);
char name[20];
printf("请输入要删除的学生姓名!\n");
scanf("%s", name);
snode* ser = head->next;
int cnt = 0;
while (ser != NULL) {
if (strcmp(ser->student.name, name) == 0)
cnt++;
}
if (cnt > 0) {
printf("存在重名学生 请输入学号查找!\n");
deleteastudentnum(head);
}
snode* cur = head;
while (cur != NULL && cur->next != NULL) {
snode* move = cur->next;
if (strcmp(move->student.name, name) == 0) {
snode* temp = cur->next;
cur->next = temp->next;
free(temp);
}
cur = cur->next;
}
save(head);
}
修改学生信息
void modifyastudent(snode* head, tnode* thead, accountnode* ahead) {
char name[20], class[20], num[20];
int chinese, math, english, m;
printstudents(head);
printf("请输入要修改的学生姓名!\n");
scanf("%s", name);
snode* ser = head->next;
int cnt = 0;
while (ser != NULL) {
if (strcmp(ser->student.name, name) == 0)
cnt++;
}
if (cnt > 0) {
printf("存在重名学生 请输入学号查找!\n");
modifyastudentnum(head, thead, ahead);
}
snode* move = head->next;
while (move != NULL) {
if (strcmp(move->student.name, name) == 0) {
printf("%s %s %s %d %d %d\n", move->student.name, move->student.class, move->student.number, move->student.chinese, move->student.math, move->student.english);
printf("请输入新的学生信息!\n");
printf("\n请输入学生姓名!\n");
scanf("%s", name);
printf("请输入学生班级\n");
scanf("%s", class);
printf("请输入学号\n");
snode* cur = head;
while (cur != NULL) {
while (strcmp(cur->student.number, num) == 0) {
printf("该学号已存在!\n");
printf("请重新输入学号!\n");
scanf("%s", num);
}
cur = cur->next;
}
printf("请输入学生语文成绩!\n");
do {
m = scanf("%d", &chinese);
if (m != 1) {
while (getchar() != '\n');
printf("请重新输入!\n");
}
} while (m != 1 || chinese > 100 || chinese < 0);
printf("请输入学生数学成绩!\n");
do {
m = scanf("%d", &math);
if (m != 1) {
while (getchar() != '\n');
printf("请重新输入!\n");
}
} while (m != 1 || math > 100 || math < 0);
printf("请输入学生英语成绩!\n");
do {
m = scanf("%d", &english);
if (m != 1) {
while (getchar() != '\n');
printf("请重新输入!\n");
}
} while (m != 1 || english > 100 || english < 0);
strcpy(move->student.name, name);
strcpy(move->student.class, class);
strcpy(move->student.number, num);
move->student.sum = chinese + math + english;
move->student.chinese = chinese;
move->student.math = math;
move->student.english = english;
move->student.sum = move->student.chinese + move->student.math + move->student.english;
save(head);
printf("修改成功!\n");
modifystudent(head, thead, ahead);
}
move = move->next;
}
printf("未找到该学生!\n");
return;
}
查询年级学生成绩
对保存学生信息的链表遍历再将信息输出即可
void list(snode* head) {
snode* move = head->next;
while (move != NULL) {
printf("姓名%s 班级:%s 学号:%s 语文:%d 数学:%d 英语:%d 总分:%d\n", move->student.name, move->student.class, move->student.number, move->student.chinese, move->student.math, move->student.english, move->student.sum);
move = move->next;
}
printf("1.按成绩升序排列\n");
printf("2.按成绩降序排列\n");
printf("3.按学号排列\n");
printf("4.返回上一级菜单\n");
int tmp;
scanf("%d", &tmp);
switch (tmp) {
case 1: {//升序
for (snode* turn = head->next; turn->next != NULL; turn = turn->next)
{
for (snode* move = head->next; move->next != NULL; move = move->next) {
snode* temp = move->next;
if (move->student.sum > temp->student.sum) {
student temps = move->student;
move->student = temp->student;
temp->student = temps;
}
}
}
printstudents(head);
system("pause");
break;
}
case 2: {//降序
for (snode* turn = head->next; turn->next != NULL; turn = turn->next)
{
for (snode* move = head->next; move->next != NULL; move = move->next) {
snode* temp = move->next;
if (move->student.sum > temp->student.sum) {
student temps = move->student;
move->student = temp->student;
temp->student = temps;
}
}
}
printstudents(head);
system("pause");
break;
}
case 3: {//重置
for (snode* turn = head->next; turn->next != NULL; turn = turn->next)
{
for (snode* move = head->next; move->next != NULL; move = move->next) {
snode* temp = move->next;
if (strcmp(move->student.number, temp->student.number) > 0) {
student temps = move->student;
move->student = temp->student;
temp->student = temps;
}
}
}
printstudents(head);
system("pause");
break;
}
case 4: {
return;
}
default: {
printf("非法排序!\n");
break;
}
}
}
对账户的新增和注销等操作与对学生信息操作类似,在此就不多加赘述了。
学生界面
学生登陆后有查询成绩和修改密码两种功能,修改密码与管理员类似,查询成绩直接输出登录结点的信息即可
void print(snode* node) {
printf("语文:%d\n",node->student.chinese);
printf("数学:%d\n", node->student.math);
printf("英语:%d\n", node->student.english);
printf("总分:%d\n", node->student.sum);
}
教师界面
教师界面有查询本班成绩和修改密码两种功能,查询本班成绩要先对学生遍历找到与教师班级对应的学生,再将学生成绩一一打印。
void listclass(tnode* node, snode* shead, accountnode* move) {
snode* cur = shead->next;
snode* newhead = (snode*)malloc(sizeof(snode));
newhead->next = NULL;
snode* newcur = newhead;
tnode* des = NULL;
tnode* curt = node;//老师对应账户
while (curt != NULL) {
if (strcmp(curt->teacher.name, move->account.name) == 0) {
des = curt;
break;
}
else {
curt = curt->next;
}
}
if (curt == NULL) {
printf("未找到该老师信息!\n");
return;
}//学生对应老师
while (cur != NULL && des != NULL) {
if (strcmp(cur->student.class, des->teacher.class) == 0) {
snode* newnode = (snode*)malloc(sizeof(snode));
newnode->student = cur->student;
newnode->next = NULL;
newcur->next = newnode;
newcur = newnode;
}
cur = cur->next;
}
newcur = newhead->next;
while (newcur != NULL) {
printf("%s %d %d %d %d\n", newcur->student.name,newcur->student.chinese, newcur->student.math, newcur->student.english, newcur->student.sum);
newcur = newcur->next;
}
system("pause");
system("cls");
list(newhead);
deletealist(newhead);
tmenu(move, node, shead);
}