前言:学生管理系统中需要实现的功能大体都很相似且需要频繁调用功能相似的函数,所以大体思路是将功能函数全部定义在最前面,功能函数之后依次是菜单界面函数和主函数
一、登录/注册
要实现这个功能,首先要定义一个存放学生账号密码的结构体且这个功能用链表实现会很方便
typedef struct user {
char username[LEN2];//用户名
char password[LEN2];//密码
struct user* next;//链表该节点指向下一个节点的指针
} Linklist1;
注册时先要判断要注册的账号是否注册过,此时需要先从存已注册的账号密码信息的文件中读取所有已注册的账号密码信息并存放到一个新建链表中,然后让用户输入想要注册的账号密码,再判断用户输入的账号是否与链表中的某个账号相同,若有相同的则提示用户注册失败,若没有相同的则将用户输入的新账号密码添加到存已注册的账号密码信息的文件中,然后提示用户注册成功。
登录时先要判断用户所输入的账号密码是否正确,此时需要先从存已注册的账号密码信息的文件中读取所有已注册的账号密码信息并存放到一个新建链表中,然后让用户输入想要登录的账号密码,再判断用户输入的账号密码是否与链表中的某个账号及其密码相同,若有相同的则提示登录成功并进入学生菜单界面,若没有相同的则提示登录失败请重新登录。
用户在登录时所输入的密码需要用 ‘ * ’ 加密,加密代码如下:
int n;
//下面这个for循环使登录输入密码时屏幕上显示的是“* ”号
for (n = 0; ; ++n) {
password1[n] = getch();
if (password1[n] == '\r') {
break;
}
printf("*");
}
password1[n] = '\0';//在已输入的密码的字符串后加终止符‘\0’
二、文件的读取与存储
首先定义一个存学生基本信息的链表,便于后续的一切增、删、查、改等功能
//定义存学生信息的链表的结构体
typedef struct student {
char name[LEN1];//学生姓名
char number[LEN1];//学生学号
char Class[LEN1];//学生班级
int Chinese;//语文成绩
int Math;//数学成绩
int English;//英语成绩
struct student* next;//链表该节点指向下一个节点的指针
} Linklist;
第一次需要将学生信息手动输入,创建基本信息单链表的代码如下:
//建立链表并输入学生基本信息
Linklist* create() {
Linklist* head, *end, *stu;
int i = 0;
char choice;
head = (Linklist*) malloc (sizeof(Linklist));
head -> next = NULL;
end = head;
do {
stu = (Linklist*) malloc (sizeof(Linklist));
printf("\n\n请输入第%d个人的信息:\n", ++i);
printf("\n姓名 学号 班级 语文成绩 数学成绩 英语成绩:\n");
scanf("%s%s%s%d%d%d", stu -> name, stu -> number, stu -> Class, &stu -> Chinese, &stu -> Math, &stu -> English);
end -> next = stu;
end = stu;
printf("Continue?(Y/N)");//输入y或Y以继续输入下一个同学的基本信息
choice = getch();
} while (choice == 'Y' || choice == 'y');
end -> next = NULL;
return head;
}
将存学生基本信息的链表中的信息存入指定文件的代码如下:
//将存学生基本信息的单链表中的信息保存到指定的磁盘文件中
void save(Linklist* head) {
Linklist* stu;
FILE* fp;
char filename[40];
printf("\n请输入要保存的文件名:");
scanf("%s", filename);
if ((fp = fopen(filename, "wt")) == NULL) {
printf("写入文件出错,请按任意键退出!");
getch();
exit(1);
}
for (stu = head -> next; stu != NULL; stu = stu -> next) {
fprintf(fp,"%s %s %s %d %d %d\n", stu -> name, stu -> number, stu -> Class, stu -> Chinese, stu -> Math, stu -> English);
}
printf("\n文件已成功保存,请按任意键返回!");
getch();
fclose(fp);
}
将存学生基本信息的指定文件中的信息读入到新建链表的代码如下:
//从指定的磁盘文件中读取信息并存入存学生基本信息的单链表
Linklist* read() {
Linklist* head, *end, *stu;
FILE* fp;
char filename[40];
printf("\n请输入要打开的文件名:");
scanf("%s", filename);
if ((fp = fopen(filename, "rt")) == NULL) {
printf("读文件出错,按任意键退出!");
getch();
exit(1);
}
head = (Linklist*) malloc (sizeof(Linklist));
head -> next = NULL;
end = head;
while (!feof(fp)) {
stu = (Linklist*) malloc (sizeof(Linklist));
fscanf(fp, "%s %s %s %d %d %d", stu -> name, stu -> number, stu -> Class, &stu -> Chinese, &stu -> Math, &stu -> English);
end -> next = stu;
end = stu;
}
end -> next = NULL;
fclose(fp);
printf("\n文件中信息已正确读出,按任意键返回!");
getch();
return head;
}
将已存放学生基本信息的链表中的信息输出到屏幕上的代码如下:
//将存学生基本信息的链表中的信息打印输出
void print(Linklist* head) {
Linklist* stu;
printf("\n所有学生的数据为:\n");
printf("姓名 学号 班级 语文成绩 数学成绩 英语成绩\n");
for (stu = head -> next; stu != NULL; stu = stu -> next) {
printf("%s %s %s %d %d %d\n", stu -> name, stu -> number, stu -> Class, stu -> Chinese, stu -> Math, stu -> English);
}
}
三、菜单界面
(下文代码注释中的“相应的实现功能的代码块”主要就是对已经写好的功能函数的相应合理调用)
主菜单界面代码如下:
//主菜单界面
void menu() {
system("cls");
fflush(stdin);//很重要,用来清除键盘的缓冲区,不然会导致下面的scanf无法正常运行 (因为被上一次的代码执行后时的键盘缓存自动填入,导致程序运行错误)
char num[LEN1];
Linklist1* head1;
printf(" \n\n==================== 学 生 信 息 管 理 系 统 ====================\n\n");
printf("******************** 请选择登录方式 ********************\n\n");
printf(" 1. 学 生 登 录\n\n");
printf(" 2. 教 师 登 录\n\n");
printf(" 3. 管 理 员 登 录\n\n");
printf(" 4. 学 生 注 册\n\n");
printf(" 5. 教 师 注 册\n\n");
printf(" 0. 退 出\n\n");
printf(" 请选择:");
scanf("%s", num);
while (num[1] != '\0' || (num[0] - '0' != 1 && num[0] - '0' != 2 && num[0] - '0' != 3 && num[0] - '0' != 4 && num[0] - '0' != 5)) {
fflush(stdin);//很重要,用来清除键盘的缓冲区,不然会导致下面的scanf无法正常运行 (因为被上一次的代码执行后时的键盘缓存自动填入,导致程序运行错误)
system("cls");
printf("\n输入了错误的指令(请输入0~5的指令)\n");
printf("******************** 请选择登录方式 ********************\n\n");
printf(" 1. 学 生 登 录\n\n");
printf(" 2. 教 师 登 录\n\n");
printf(" 3. 管 理 员 登 录\n\n");
printf(" 4. 学 生 注 册\n\n");
printf(" 5. 教 师 注 册\n\n");
printf(" 0. 退 出\n\n");
printf("\n请重新输入:");
scanf("%s", num);
}
if (num[0] - '0' == 0) {
system("cls");
printf("您已成功退出");
}
if (num[0] - '0' == 1) {
//相应的实现功能的代码块
}
if (num[0] - '0' == 2) {
//相应的实现功能的代码块
}
if (num[0] - '0' == 3) {
//相应的实现功能的代码块
}
if (num[0] - '0' == 4) {
//相应的实现功能的代码块
}
if (num[0] - '0' == 5) {
//相应的实现功能的代码块
}
}
学生菜单界面代码如下:
//登录成功后显示的菜单(此处为学生菜单)
int studentmenu(char username1[], char password1[]) {
fflush(stdin);//很重要,用来清除键盘的缓冲区,不然会导致下面的scanf无法正常运行 (因为被上一次的代码执行后时的键盘缓存自动填入,导致程序运行错误)
int flag = 0;
char num1[LEN1];
Linklist1* head1;
Linklist* head;
head1 = read4();//从用来自动将存学生账号密码信息的文件中的信息存放到一个链表中(此处是存学生账号密码的文件)
printf("请选择指令:\n\n");
printf(" 1. 成 绩 查 询\n\n");
printf(" 2. 查 询 本 班 成 绩\n\n");
printf(" 3. 成 绩 分 析\n\n");
printf(" 4. 成 绩 申 诉\n\n");
printf(" 5. 返 回 上 一 层\n\n");
printf(" 0. 退 出\n\n");
printf("请输入指令:");
scanf("%s", num1);
while (num1[1] != '\0' || (num1[0] - '0' != 1 && num1[0] - '0' != 2 && num1[0] - '0' != 3 && num1[0] - '0' != 4 && num1[0] - '0' != 5 && num1[0] - '0' != 0)) {
fflush(stdin);//很重要,用来清除键盘的缓冲区,不然会导致下面的scanf无法正常运行 (因为被上一次的代码执行后时的键盘缓存自动填入,导致程序运行错误)
system("cls");
printf("\n输入了错误的指令(请输入0~5的指令)\n");
printf("请选择指令:\n\n");
printf(" 1. 成 绩 查 询\n\n");
printf(" 2. 查 询 本 班 成 绩\n\n");
printf(" 3. 成 绩 分 析\n\n");
printf(" 4. 成 绩 申 诉\n\n");
printf(" 5. 返 回 上 一 层\n\n");
printf(" 0. 退 出\n\n");
printf("\n请重新输入:");
scanf("%s", num1);
}
if (num1[0] - '0' == 0) {
system("cls");
printf("\n您已退出成功!\n");
flag = 0;
return flag;
}
if (num1[0] - '0' == 1) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 2) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 3) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 4) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 5) {
system("cls");
flag = 1;
return flag;
}
}
教师菜单界面代码如下:
//登录成功后显示的菜单(此处为教师端菜单)
int teachermenu(char username1[], char password1[]) {
fflush(stdin);//很重要,用来清除键盘的缓冲区,不然会导致下面的scanf无法正常运行 (因为被上一次的代码执行后时的键盘缓存自动填入,导致程序运行错误)
int flag = 0;
char num1[LEN1];
Linklist1* head1;
Linklist* head;
head1 = read4();//从指定文件中读取已注册的账号密码信息存入存账号密码的单链表 // **********此处的read是通用的,需要另写一个专一文件用的
printf("请选择指令:\n\n");
printf(" 1. 增 加 新 的 学 生 信 息\n\n");
printf(" 2. 删 除 学 生 信 息\n\n");
printf(" 3. 修 改 学 生 信 息\n\n");
printf(" 4. 查 询 学 生 信 息\n\n");
printf(" 5. 输 出 本 班 成 绩\n\n");
printf(" 6. 下 载 到 文 件 中\n\n");
printf(" 7. 成 绩 分 析\n\n");
printf(" 8. 提 醒 管 理 员 进 行 成 绩 的 更 新\n\n");
printf(" 9. 返 回 上 一 层\n\n");
printf(" 0. 退 出\n\n");
printf("请输入指令:");
scanf("%s", num1);
while (num1[1] != '\0' || (num1[0] - '0' != 1 && num1[0] - '0' != 2 && num1[0] - '0' != 3 && num1[0] - '0' != 4 && num1[0] - '0' != 5 && num1[0] - '0' != 6 && num1[0] - '0' != 7 && num1[0] - '0' != 8 && num1[0] - '0' != 9 && num1[0] - '0' != 0)) {
fflush(stdin);//很重要,用来清除键盘的缓冲区,不然会导致下面的scanf无法正常运行 (因为被上一次的代码执行后时的键盘缓存自动填入,导致程序运行错误)
system("cls");
printf("\n输入了错误的指令(请输入0~9的指令)\n");
printf("请选择指令:\n\n");
printf(" 1. 增 加 新 的 学 生 信 息\n\n");
printf(" 2. 删 除 学 生 信 息\n\n");
printf(" 3. 修 改 学 生 信 息\n\n");
printf(" 4. 查 询 学 生 信 息\n\n");
printf(" 5. 输 出 本 班 成 绩\n\n");
printf(" 6. 下 载 到 文 件 中\n\n");
printf(" 7. 成 绩 分 析\n\n");
printf(" 8. 提 醒 管 理 员 进 行 成 绩 的 更 新\n\n");
printf(" 9. 返 回 上 一 层\n\n");
printf(" 0. 退 出\n\n");
printf("\n请重新输入:");
scanf("%s", num1);
}
if (num1[0] - '0' == 0) {
system("cls");
printf("\n您已退出成功!\n");
flag = 0;
return flag;
}
if (num1[0] - '0' == 1) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 2) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 3) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 4) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 5) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 6) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 7) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 8) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 9) {
system("cls");
flag = 1;
return flag;
}
}
管理员菜单界面的代码如下:
//登录成功后显示的菜单(此处为管理员端菜单)
int managemenu(char username1[], char password1[]) {
fflush(stdin);//很重要,用来清除键盘的缓冲区,不然会导致下面的scanf无法正常运行 (因为被上一次的代码执行后时的键盘缓存自动填入,导致程序运行错误)
int flag = 0;
char num1[LEN1];
Linklist1* head1;
Linklist* head;
printf("请选择指令:\n\n");
printf(" 1. 查 看 代 办 选 项\n\n");
printf(" 2. 进 入 教 师 端 进 行 信 息 修 改\n\n");
printf(" 3. 增 加 账 号 及 密 码\n\n");
printf(" 4. 删 除 账 号 及 密 码\n\n");
printf(" 5. 修 改 账 号 及 密 码\n\n");
printf(" 6. 查 找 账 号 及 密 码\n\n");
printf(" 7. 录 入 所 有 账 号 及 密 码\n\n");
printf(" 8. 输 出 所 有 账 号 及 密 码\n\n");
printf(" 9. 手 动 录 入 学 生 信 息\n\n");
printf(" a. 返 回 到 上 一 层\n\n");
printf(" 0. 退 出\n\n");
printf("请输入指令:");
scanf("%s", num1);
while (num1[1] != '\0' || (num1[0] - '0' != 1 && num1[0] - '0' != 2 && num1[0] - '0' != 3 && num1[0] - '0' != 4 && num1[0] - '0' != 5 && num1[0] - '0' != 6 && num1[0] - '0' != 7 && num1[0] - '0' != 8 && num1[0] - '0' != 9 && num1[0] - '0' != 0 && num1[0] != 'a')) {
fflush(stdin);//很重要,用来清除键盘的缓冲区,不然会导致下面的scanf无法正常运行 (因为被上一次的代码执行后时的键盘缓存自动填入,导致程序运行错误)
system("cls");
printf("\n输入了错误的指令(请输入0~9及a的指令)\n");
printf("请选择指令:\n\n");
printf(" 1. 查 看 代 办 选 项\n\n");
printf(" 2. 进 入 教 师 端 进 行 信 息 修 改\n\n");
printf(" 3. 增 加 账 号 及 密 码\n\n");
printf(" 4. 删 除 账 号 及 密 码\n\n");
printf(" 5. 修 改 账 号 及 密 码\n\n");
printf(" 6. 查 找 账 号 及 密 码\n\n");
printf(" 7. 录 入 所 有 账 号 及 密 码\n\n");
printf(" 8. 输 出 所 有 账 号 及 密 码\n\n");
printf(" 9. 手 动 录 入 学 生 信 息\n\n");
printf(" a. 返 回 到 上 一 层\n\n");
printf(" 0. 退 出\n\n");
printf("\n请重新输入:");
scanf("%s", num1);
}
if (num1[0] - '0' == 0) {
system("cls");
printf("\n您已退出成功!\n");
flag = 0;
return flag;
}
if (num1[0] - '0' == 1) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 2) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 3) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 4) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 5) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 6) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 7) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 8) {
//相应的实现功能的代码块
}
if (num1[0] - '0' == 9) {
//相应的实现功能的代码块
}
if (num1[0] == 'a') {
system("cls");
flag = 1;
return flag;
}
}
主函数代码:
由于功能函数及菜单函数全部是以函数形式模块化,所以主函数会十分简洁
//主函数
int main(void) {
menu();//主菜单界面
return 0;
}
一些注意事项
- 管理系统中教师的权限要低于管理员的权限,比如一个教师只能管理一个班,但是管理员则可以管理所有的班级
- 输出的学生信息等要对齐
- 同学们输入文件中的申请信息中若有空格,在管理员界面中要将空格前后的内容全部打印出来
总结:
学生管理系统的主要难点就是对于文件的相关操作,主要思路就是通过调用需要的(已经写好的)功能函数,去实现想要的结果,具体操作就是对链表的建立、增、删、查、改、及输出,整体过程就是需要信息时从文件中读取,然后对读取到链表中的信息进行操作,操作完之后如果需要保存信息则将链表中信息写入文件,如果仅需输出则只在屏幕上输出所需信息即可。