目录
1 系统介绍
2 系统设计
3 设计结果
4 源代码
近来有空闲,把前几个学期做的实验上传上来。如有错误的地方欢迎大佬批评指正,有更好的方法也期待您的分享~
实验要求
本课程要完成一个学生信息管理系统的设计与实现,可实现对于学生信息的录入、增加,修改和删除,以及学生信息浏览和特定条件的学生查询
1.学生信息的存储方式:文件存储
可以文本文件方式存储(txt)或其他文件形式
文本文件存储示例:
201611701208,张三,男,19,广东省xxx,软件工程
201611701209,张小明,男,18,浙江省xxx,软件工程
201611701201,白小云,女,18,广东省xx,软件工程
201611301107,赵晓飞,男,19,广东省xx,自动控制
2.学生记录数据录入、增加
能逐条添加单个学生记录,要求保证学生记录的学号唯一性,并且学号值不允许为空值
能判断对每个字段的输入值是否符合格式要求,比如学号是由12个数字字符组成,前四个字符是合常理的年份;性别只能输入男或者女;年龄是数字字符,范围介于一个合理的区间
要求能接收缺少某个字段值的学生记录
3.数据查询
能够通过给定条件查询学生的信息,给定的条件如学号、姓名、地址等
查询要求能够支持同时指定多个条件的查询:例如查询“18岁的浙江省男生信息”
能进行模糊查询,比如查询名字中包含“小”字的学生;
能统计满足某个条件的学生人数;
因为学生文件中的学生信息的排列顺序是按照添加的顺序排列的,因此需要结合数据结构知识,考虑如何提高查询效率。
4.数据删除
可以删除指定条件的学生信息
需要考虑删除后的文件应如何处理删除的信息
5.数据更新
可以更新指定条件的学生信息
需要考虑如何处理更新后的文件
6.支持学生信息结构的改变
支持增加字段: 比如增加一个“身份证号”,相应的所有记录必须增加相应的值,应考虑如何处理文件比较合理。
同理支持减少字段
7.其他需求
可看性:界面符合一般人的审美观;
易用性:操作便利,有符合使用习惯的流程控制过程,有很好的“进入”和“退出”机制;
健壮性:能够应对处理非法输入和非法操作;
性能:时间和空间复杂度要求;
1 系统介绍
1.1本系统总介绍
学生信息管理系统,是针对学校人事处的大量业务处理工作而开发的管理软件,是典型的管理信息系统。作为计算机应用的一部分,使用计算机对学生信息进行管理,具有着手工管理所无法比拟的优点。例如:检索迅速、查找方便、易修改、存储量大、数据处理快捷等。这些优点能够极大地提高学生信息管理的效率,也是学校实现科学化、正规化管理的重要条件。因此,开发这样一套管理软件是很有必要的事情。
1.2 需求分析
1.2.1学生信息的存储方式:文件存储
可以文本文件方式存储(txt)和二进制文件形式存储。
1.2.2学生记录数据录入、增加
(1)能逐条添加单个学生记录,保证学生记录的学号唯一性,并且学号值不允许为空值;
(2)能判断对每个字段的输入值是否符合格式要求,比如学号是由12个数字字符组成,前四个字符是合常理的年份;性别只能输入男或者女;年龄是数字字符,范围介于一个合理的区间;
(3)能接收缺少某个字段值的学生记录。
1.2.3数据查询
(1)能够通过给定条件查询学生的信息,给定的条件如学号、姓名、性别等;
(2)支持同时进行性别、年龄、籍贯多个条件的查询:例如查询“18岁的浙江省男生信息”;
(3)能进行模糊查询,比如查询名字中包含“小”字的学生;
(4)能统计满足某个条件的学生人数。
1.2.4数据删除
(1)可以删除指定条件的学生信息;
(2)删除后的文件只保留剩下学生的信息。
1.2.5数据更新
(1)可以更新指定条件的学生信息;
(2)更新后文件其他学生信息不变,指定更新的学生信息改变。
1.2.6其他需求
(1)可看性:界面符合一般人的审美观;
(2)易用性:操作便利,有符合使用习惯的流程控制过程,有很好的“管理员进入”和“退出”机制;
(3)健壮性:能够应对处理非法输入和非法操作;
1.3学生管理系统的功能结构图
1.4系统技术平台、标准的相应介绍
Visual Studio 2022主要用于软件开发和应用程序的创建、测试和部署。该版本是Visual Studio 2019的后继版本,带来了一系列改进和新功能,包括:改进了性能,Visual Studio 2022在启动时间和代码编译速度方面都进行了优化,大大提高了开发效率;改进了调试功能,Visual Studio 2022提供了更好的调试工具,包括改进的性能问题分析器和调试查看器等等。
2 系统设计
2.1学生信息的存储方式:文件存储
2.1.1 具体设计过程
(1)采用二进制方式对文件进行写操作
①用 FILE* 定义一个文件指针 fp;
②调用 fopen() 函数,使用给定的模式 mode 打开 filename 所指向的文件,若无法打开,则输出"cannot open file",返回,若打开成功,首先调用 fwrite() 函数将学生人数写入文件,然后使用for循环将学生信息写入,进行出错处理。
③使用fclose() 函数关闭文件指针。
(2)采用txt方式对文件进行写操作
①调用 ofstream() 文件打开txt文件。
②使用for循环用“ << ”将学生信息写入txt文件。
③使用 .close() 关闭文件。
(3)采用二进制方式对文件进行读操作
①用 FILE* 定义一个文件指针 fp;
②调用 fopen() 函数,使用给定的模式 mode 打开 filename 所指向的文件,若无法打开,则输出"cannot open file",返回,若打开成功,首先调用 fread() 函数读取学生人数,然后使用for循环将学生信息写入,进行出错处理。
③使用fclose() 函数关闭文件指针。
2.1.2 存储结构
学生信息既以二进制方式读写又以文本形式存储在文件夹中。
2.1.3 功能算法描述
(1)文件读写
头文件:#include <fstream>
文件写操作,内存写入存储设备 :ofstream
文件读操作,存储设备读区到内存中:ifstream
读写操作,对打开的文件可进行读写操作:fstream
(2)定义文件指针
FILE*
(3)打开文件
FILE *fopen(const char *filename, const char *mode)
使用给定的模式 mode 打开 filename 所指向的文件。
(4)二进制写文件
函数 size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) 把 ptr 所指向的数组中的数据写入到给定流 stream 中。
(5)二进制读文件
函数 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) 从给定流 stream 读取数据到 ptr 所指向的数组中。
2.1.4 程序流程图
2.2学生记录数据录入、增加
2.2.1 具体设计过程
(1)输入学生姓名
cin >> s[student_number++].name;
(2)输入学生学号
①输入
strcmp(s[student_number].num, s[i].num) == 0
cin >> s[student_number].num;
②定义字符串aa,将const char*类型的s[student_number].num 转为字符串
string aa(s[student_number].num);
③定义临时变量 string temp(aa, 0, 4);
④for遍历链表,使用 strcmp() 函数判断该学号是否存在,保证记录唯一性
⑤使用 函数 strlen() 和 atoi(temp.c_str())截取用户输入学号的前四位,判断学号是否由12个数字字符组成,且前四个字符是否是合常理的年份
(3)输入用户性别
①输入
cin >> s[student_number].sex;
②将const char* 类型的s[student_number].sex赋值给 char*类型的 c,并具体赋值输入的性别
③使用 strcmp() 函数判断该性别是否存在
(4)输入用户年龄
①输入
cin >> s[student_number].age;
②使用 if 判断用户输入的年龄是否是数字字符且范围介于一个合理的区间
(5)输入学生籍贯
cin >> s[student_number].hometown;
(6)输入学生专业
cin >> s[student_number].major;
2.2.2 存储结构
先将用户输入的学生信息存储在内存中,然后询问用户输入的信息是否保存,如果保存,将内存中的学生信息写入文件中。
2.2.3 功能算法描述
(1)定义临时变量temp
string temp(aa, 0, 4);
(2)字符串比较
int strcmp(const char *str1, const char *str2)
把 str1 所指向的字符串和 str2 所指向的字符串进行比较。
如果返回值小于 0,则表示 str1 小于 str2。
如果返回值大于 0,则表示 str1 大于 str2。
如果返回值等于 0,则表示 str1 等于 str2。
(3)goto 语句:把控制无条件转移到同一函数内的被标记的语句
(4)计算字符串的长度
size_t strlen(const char *str)
(5)把参数所指向的字符串转换为int型
int atoi(const char *str)
(6)从标准输入 stdin 获取一个字符(一个无符号字符)
int getchar(void)
2.2.4 程序流程图
2.3数据查询
2.3.1 具体设计过程
(1)定义一个int类型变量来获取用户的输入
1 按学号查询search_by_num()
2 按姓名查询search_by_name()
3 按性别查询search_by_sex()
4 多条件查询search_by_mult()
5 返回上一级search_by_exit()
(2)打印学生信息表格的表头函数 print_table()
(3)按学号查询函数 search_by_num(),询问用户进行精准查询还是模糊查询
1.按学号精准查询search_by_num1()
①定义 char num1[max] 保存用户输入的学生学号,预定义整型 v = 0;;
②使用 for 循环和 strcmp() 判断该学号是否存在 strcmp(num1, s[i].num);
③循环一次v++,最后输出满足条件的学生人数为v。
2.按学号模糊查询search_by_num2()
①定义 char num1[max] 保存用户输入的学生学号,预定义整型 v = 0;
②使用 for 循环遍历链表,使用 strstr() 函数进行模糊查找
char* result=strstr(s[w].num, num1),若result不等于nullptr,则找到;
③循环一次v++,最后输出满足条件的学生人数为v。
(4)按姓名查询函数 search_by_name(),询问用户进行精准查询还是模糊查询
1.按姓名精准查询search_by_name1()
①定义 char num1[max] 保存用户输入的学生学号,预定义整型 v = 0;;
②使用 for 循环和 strcmp() 判断该学号是否存在 strcmp(num1, s[i].num);
③循环一次v++,最后输出满足条件的学生人数为v。
2.按姓名模糊查询search_by_name2()
①定义 char num1[max] 保存用户输入的学生学号,预定义整型 v = 0;
②使用 for 循环遍历链表,使用 strstr() 函数进行模糊查找
char* result=strstr(s[w].num, num1)
若result不等于nullptr,则找到;
③循环一次v++,最后输出满足条件的学生人数为v。
(5)按性别查询函数 search_by_sex()
①定义 char sex1[max] 保存用户输入的学生性别;
②使用 for 循环遍历链表, strcmp() 判断,若存在该性别,则输出该学生信息
strcmp(num1, s[i].num);
(6)多条件查询
①定义用户想要查询的多个条件
用户输入学生的性别 char sex1[max];
用户输入学生年龄 int chinese1;
用户输入学生籍贯 char mathematic1[max];
②使用for循环遍历链表,使用strcmp() 判断符合三条件的信息是否存在
strcmp(sex1,s[i].sex)==0 && (chinese1 == s[i].age) && strcmp(mathematic1, s[i].hometown) == 0
2.3.2 存储结构
预先将文件存储的学生信息读入链表,在链表中查询学生信息。
2.3.3 功能算法描述
(1)菜单栏: if 语句。
(2)模糊查找 strstr()
char *strstr(const char *haystack, const char *needle)
在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 '\0'。
2.3.4 程序流程图
2.4数据删除
2.4.1 具体设计过程
(1)定义 char num4[max] 存储输入的学号
(2)for 循环遍历链表,看学号是否存在,若 strcmp(num4, s[i].num)== 0,则存在。
(3)将链表中该节点指向下一节点以实现删除操作
strcpy_s(s[j].num, s[j + 1].num);
strcpy_s(s[j].name, s[j + 1].name);
strcpy_s(s[j].sex, s[j + 1].sex);
s[j].age = s[j + 1].age;
strcpy_s(s[j].hometown, s[j + 1].home
strcpy_s(s[j].major, s[j + 1].major);
(4)将删除后的信息保存到文件中 save_record()。
2.4.2 存储结构
在链表中遍历用户输入的学号,若找到,则在链表中删除该学生信息,保存链表剩下的信息至文件。
2.4.3 功能算法描述
(1)char 字符串拷贝:strcpy_s()函数
strcpy_s(char *strDestination , size_t numberOfElements , const char *strSource);
参数:[out] strDestination:拷贝完成之后的字符串
[in] numberOfElements: strDestination目标缓冲区长度
[in] strSource:需要拷贝的字符串
(2)清屏函数system("cls")
2.4.4 程序流程图
2.5数据更新
2.5.1 具体设计过程
(1)定义 char name2[max], sex2[max], hometown2[max], major2[max],char numbefor[max],int age2存储用户输入的信息;
(2)for 循环遍历链表,看学号是否存在,若 strcmp(numbefor, s[i].num) == 0,则存在。
(3)让用户一一输入修改后的信息
(4)使用 strcpy() 函数将用户输入的信息覆盖原信息
(5)更新后的信息保存到文件中 save_record()。
2.5.2 存储结构
在链表中遍历用户输入的学号,若找到,则在链表中更新该学生信息,最后保存链表的所有信息至文件。
2.5.3 程序流程图
2.6易用性:有“进入”和“退出”机制,符合使用习惯的流程控制过程
(1)管理员“进入”机制
①定义管理员结构体,char username[20]和char password[20]存储登录账号和密码
②定义登入函数 login(),主函数一开始调用一次 login() 函数,用户输入管理员账号和密码,使用 for 循环遍历预定义的管理员的信息,如果strcmp(id,user[i].username) ==0 && strcmp(password, user[i].password) == 0,则输入的信息在初始化的信息中存在,则登录成功。
③ 如果遍历完一轮管理员信息,此时i=5且未找到符合的管理员信息,说明账号密码输入错误,让用户重新输入账号密码。
④定义全局变量 g ,用户每次登录都遍历一次user结构体且g++。若g >= 3,则三次机会都用完,退出系统。
(2)“退出”机制
①定义函数exit_record(),exit(0)。
②若用户在主菜单输入“6”,则调用一次 exit_record()函数,退出系统。
2.6.2 功能算法描述
(1)全局变量
一般是定义或者声明在全局位置,也就是 “{ }” 外面
(2)关闭所有文件,终止正在执行的进程,正常退出:exit(0)
2.6.3 程序流程图
3 设计结果
3.1学生信息的存储方式:文件存储
3.1.1 当使用“增加学生信息”操作时,输入学生信息并选择保存后,将会显示“file write sucess”,则学生信息写入文件成功。
可以看见txt文件中存储的信息增加了刚刚添加的学生信息:
3.1.2当使用“更新学生信息”操作时,输入更新后学生信息并选择保存后,将会显示“file write sucess”,则学生信息写入文件成功。
可以看见txt文件中刚才更新的学生的姓名信息已经发生了改变:
3.1.3当使用“删除学生信息”操作时,输入想要删除的学生的学号,确定删除后,将会显示“file write sucess”,则学生信息删除文件成功。
可以看见txt文件中刚才删除的学生信息已经被删除了:
3.2学生记录数据录入、增加
由图可见,当输入学号已被录入时,让用户重新输入;当输入学号不是12位时,让用户重新输入;当输入学号前四个字符不是合理年份时,让用户重新输入;当输入性别不是“男”或“女”时,让用户重新输入;当输入年龄不是合法年龄时,让用户重新输入。
保存后可以看见增加的学生信息可以显示:
3.3数据查询
3.3.1 按学号查询
(1)精准查询
①当输入学号不存在时,让用户选择是否重新输入。
②当输入学号存在时,打印该学生信息。
(2)模糊查询
输入一段想查询的学号,如“1104”,则找到学号为“202211701104”的学生,打印该学生信息。
3.3.2 按姓名查询
(1)精准查询
用户输入学生的姓名,若找到,则打印该学生信息。
(2)模糊查询
输入一段想查询的姓名字符,如“王”,则找到姓名中有“王”字的“王一五”,打印该学生信息。
3.3.3 按性别查询
(1)输入为“男”,若找到性别为“男”的学生,则打印信息。
(2)输入为“女”,若找到性别为“女”的学生,则打印信息。
3.3.4 多条件查询
逐次输入学生的性别、年龄、籍贯,如下图搜索的是“18岁的广东省广州市女生信息”。
3.4数据删除
(1)当输入学号不存在时,让用户选择是否继续删除。
(2)当输入学号存在时,打印该学生信息,询问是否确定删除。
3.5数据更新
(1)当输入学号不存在时,让用户选择是否继续更新。
(2) 当输入学号存在时,打印该学生信息,让用户一一输入修改的信息,最后若保存修改,打印该学生修改后的信息。
3.6易用性:有“进入”和“退出”机制,符合使用习惯的流程控制过程
3.6.1 管理员“进入”机制
(1)若输入管理员账号密码正确,则进入主菜单界面。
(2)若输入管理员账号密码错误,则重新输入。
若连续三次输入错误,则自动退出程序。
3.6.2 “退出”机制
在主菜单界面输入“6”,正常退出程序。
4 源代码
//头文件
#include<iostream> //数据流输入/输出
#include<stdlib.h> //standard library标准库
#include<string.h> //关于字符数组的函数定义
#include <cstring> //字符串类
#include<fstream> //C++ STL中对文件操作
#include <sstream> //字符串流,用于格式转换
#include <algorithm> // std::find,用于模糊查找
using namespace std;
#pragma warning(disable:996)
#define _CRT_SECURE_NO_WARNINGS
#define max 100 //数组定义统一大小
//定义全局变量
int g = 0; //g为登录时输入密码次数
int student_number = 5; //student_number为学生的人数
//管理员结构体
struct user
{ //存储用户登录账号和密码
char username[20];
char password[20];
}user[2] = { //初始化五个管理员的信息
{"ZQY", "0000"},
{"zqy", "0000"},
};
//学生信息结构体
struct student
{
char name[max]; //姓名
char num[max]; //学号
char sex[max]; //性别
int age; //年龄
char hometown[max];//籍贯
char major[max];//专业
}s[5] = { //初始化五个学生的信息
{ "张一三", "202211701100", "男", 18,"广东省湛江市","软件工程"},
{ "李一四", "202211701101", "男", 17,"广东省广州市","计算科学"},
{ "王一五", "202211701102", "女", 17,"广东省深圳市","计算科学"},
{ "赵一六", "202211701103", "男", 19,"广东省茂名市","软件工程"},
{ "孙一七", "202211701104", "女", 18,"广东省河源市","软件工程"}
};
struct student* p; //定义一个结构体指针
//主菜单函数声明
void login(); //登入函数
void main_menu(); //主界面函数
void input_record(); //输入学生成绩处理 1
void show_record(); //显示学生成绩处理 2
void search_record(); //查询学生成绩处理 3
void change_record(); //更新学生成绩处理 4
void delete_record(); //删除学生信息 5
void save_record(); //保存处理
void exit_record(); //退出 6
//查询子函数声明
void search_by_num(); //学号查询
void search_by_num1(); //按学号精准查找
void search_by_num2(); //按学号模糊查找
void search_by_name(); //姓名查询
void search_by_name1(); //按姓名精准查找
void search_by_name2(); //按姓名模糊查找
void search_by_sex(); //性别查询
void search_by_mult(); //多条件查询
void search_by_exit(); //返回上一级
//自定义函数
void print_table(); //表头
void read(); //将文件中的数据读入到结构体数组中
//主函数
int main()
{
login(); //首先进行管理员登录
main_menu(); //显示主界面
return 0;
}
//登录函数,管理员使用该系统前需进行登录(“进入”机制);定义密码只允许输错三次
void login()
{
int i;
char id[20], password[20];//id为管理员账号,password为管理员密码
cout << "****登录界面****" << endl;
cout << "请输入账号名:";
cin >> id;
cout << "请输入密码:";
cin >> password;
for (i = 0; i < 5; i++) //遍历五个管理员的信息,如果输入的信息在初始化的信息中存在则登录成功
{
/* strcmp() 函数:int strcmp(const char* str1, const char* str2)
如果返回值小于 0,则表示 str1 小于 str2。
如果返回值大于 0,则表示 str1 大于 str2。
如果返回值等于 0,则表示 str1 等于 str2。*/
if (strcmp(id, user[i].username) == 0 && strcmp(password, user[i].password) == 0)
{
cout << "登录成功!" << endl;
system("cls"); //清屏函数
main_menu(); //登录成功,打印主界面
break;
}
}
//遍历完一轮管理员信息,此时i=5且未找到符合的管理员信息,说明账号密码输入错误
if (i == 5)
{
system("cls");
cout << "登录失败!" << endl << endl;
g++; //第11行定义了全局变量g,有三次登录机会,每次登录都遍历一次user结构体
if (g >= 3) //若三次机会都用完,则退出系统
{
cout << "你已经输错三次,将自动退出系统" << endl;
exit(1);
}
else
{
login(); //否则,登陆成功,进入主界面
}
}
}
//展示主菜单,并对用户的请求做出对应响应
void main_menu()
{
read(); //将文件中的学生信息读取到链表中
save_record();
system("cls"); //清屏函数
int x;
//主菜单
cout << "*************************************************" << endl;
cout << "*\t欢迎使用高校学生信息管理系统\t*" << endl;
cout << "*************************************************" << endl;
cout << "*\t\t1.输入学生信息\t\t\t*" << endl;
cout << "*\t\t2.显示学生信息\t\t\t*" << endl;
cout << "*\t\t3.查询学生信息\t\t\t*" << endl;
cout << "*\t\t4.更新学生信息\t\t\t*" << endl;
cout << "*\t\t5.删除学生信息\t\t\t*" << endl;
cout << "*\t\t6.退出系统\t\t\t*" << endl;
cout << "*************************************************" << endl;
cout << "请输入你要执行的操作:";
cin >> x;
if (x == 1) //输入学生信息
input_record();
if (x == 2) //显示学生信息
show_record();
if (x == 3) //查询学生信息
search_record();
if (x == 4) //更新学生信息
change_record();
if (x == 5) //删除学生信息
delete_record();
if (x == 6) //退出系统
exit_record();
else
{
cout << "输入错误,即将重新进入主界面" << endl;
main_menu();//重新打印主界面
}
}
//1 输入学生成绩函数
void input_record() //输入学生成绩函数 1
{
//在开头位置做一个标记
aa:
{
system("cls"); //清屏函数
//姓名
cout << "请输入学生姓名:";
cin >> s[student_number].name;
bb:
//学号
while (1) {
cout << "请输入学生学号(十二位):";
cin >> s[student_number].num;
string aa(s[student_number].num);
string temp(aa, 0, 4);
for (int i = 0; i < student_number; i++) { //遍历链表,看该学号是否存在,保证记录唯一性
//int strcmp(const char *str1, const char *str2)
if (strcmp(s[student_number].num, s[i].num) == 0) {
cout << ("该学生已录入,请重新输入!\n");
goto bb;
}
}
if ((strlen(s[student_number].num) == 12) && (atoi(temp.c_str()) == 2022)) { //学号是由12个数字字符组成,前四个字符是合常理的年份
break;
}
else {
cout << "您的学号输入有误,请重新输入!" << endl;
}
}
//性别
while (1) {
cout << ("请输入学生性别(男/女):");
cin >> s[student_number].sex;
char* c = s[student_number].sex; //初始化char* 类型,并具体赋值输入的性别
if (strcmp(c, "男") == 0 || strcmp(c, "女") == 0 || '\0') {//性别只能输入男或者女,允许为空值
break;
}
else {
cout << "您的性别输入有误,请重新输入!" << endl;
}
}
//年龄
while (1) {
cout << ("请输入学生年龄:");
cin >> s[student_number].age;
if (s[student_number].age >= 0 && s[student_number].age <= 100)//年龄是数字字符,范围介于一个合理的区间
{
break;
}
else
{
cout << "您的年龄输入有误,请重新输入!" << endl;
}
}
//籍贯
cout << ("请输入学生籍贯(xx省xx市):");
cin >> s[student_number].hometown;
//专业
cout << ("请输入学生专业:");
cin >> s[student_number].major;
cout << "请选择是否保存(y或n):";
getchar();
//数据输入完毕,询问是否保存
if (getchar() == 'y') //若输入为y,则保存信息到文件中
{
student_number++;//输入后一位学生信息
save_record();//调用保存信息的save_record函数
}
cout << "是否继续添加,请选择(y或n)(否会回到主界面):" << endl;//询问是否继续添加
getchar();
if (getchar() == 'y') //若输入为y,则跳转至开头标记aa处
{
goto aa;//继续添加
}
if (getchar() == 'n')
{
main_menu();//返回主界面
}
}
}
//2 显示学生信息函数
void show_record() //显示学生信息函数 2
{
system("cls"); //清屏函数
//定义两个int类型变量来获取用户的输入
int x;
char get = 0;
x = student_number;
print_table(); //打印表头
for (int i = 0; i < x; i++) //打印表格数据
{
cout << "| " << s[i].name << " | " << s[i].num << " | " << s[i].sex << " | " << s[i].age << " | " << s[i].hometown << " | " << s[i].major << " |" << endl;
}
cout << endl << "1.返回主界面" << endl << "2.返回上一级" << endl;//询问返回哪里
cout << "请输入:";
getchar();//获取用户回答
if (getchar() == 1)//若输入为1,返回主界面
{
main_menu();
}
else if (getchar() == 2)//若输入为2,返回上一级
{
main_menu();
}
}
//3 查询学生成绩函数
void search_record() //查询学生成绩函数 3
{
system("cls"); //清屏函数
//定义一个int类型变量来获取用户的输入
int z;
//打印菜单
cout << "1 按学号查询" << endl;
cout << "2 按姓名查询" << endl;
cout << "3 按性别查询" << endl;
cout << "4 多条件查询" << endl;
cout << "5 返回上一级" << endl;
cout << "请输入:";
cin >> z;
//给定条件查询
if (z == 1)
search_by_num(); //按学号查询函数
if (z == 2)
search_by_name(); //按姓名查询函数
if (z == 3)
search_by_sex(); //按性别查询查询
if (z == 4)
search_by_mult(); //多条件查询
if (z == 5)
search_by_exit(); //返回主界面
else
{
cout << ("输入错误\n");
search_record(); //重新查询
}
}
void print_table() //打印学生信息表格的表头函数
{
cout << "+----------+----------------+------+------+----------------+------------+" << endl;
cout << "| 姓名 | 学号 | 性别 | 年龄 | 籍贯 | 专业 |" << endl;
cout << "+----------+----------------+------+------+----------------+------------+" << endl;
}
void search_by_num() //查询学生信息函数的子函数——按学号查询函数
{
system("cls"); //清屏函数
//定义一个int类型变量来获取用户的输入
int z;
//打印菜单
cout << "1 精准查询" << endl;
cout << "2 模糊查询" << endl;
cout << "3 返回上一级" << endl;
cout << "请输入:";
cin >> z;
//给定条件查询
if (z == 1)
search_by_num1(); //精准查询
if (z == 2)
search_by_num2(); //模糊查询
if (z == 3)
search_by_exit(); //返回主界面
else
{
cout << ("输入错误\n");
search_record(); //重新查询
}
}
void search_by_num1() {
//定义两个int型变量来获取用户的输入
int i;
int v = 0;
char num1[max]; //用户输入学生学号
system("cls"); //清屏函数
cout << "请输入要查找的学号:";//询问用户
cin >> num1;//获取用户输入数据
for (i = 0; i < student_number; i++) //遍历链表,寻找是该学号是否存在
{
if (strcmp(num1, s[i].num) == 0)
{
print_table();//打印学生信息表格的表头函数
cout << "| " << s[i].name << " | " << s[i].num << " | " << s[i].sex << " | " << s[i].age << " | " << s[i].hometown << " | " << s[i].major << " |" << endl;
v++;
break;
}
}
cout << endl << "满足条件的学生人数为:" << v << "人" << endl;//统计满足条件的学生人数
if (i == student_number) //student_number为全局变量学生的人数,即找到最后了
{
cout << "不存在这个学号!" << endl << endl;
}
cout << endl << "1.返回主界面" << endl << "2.继续查询";//询问返回哪里
cout << "请输入:";
getchar();//获取用户回答
if (getchar() == 1)
{
main_menu();
}
else
{
search_record();
}
}
void search_by_num2() {
//定义两个int型变量来获取用户的输入
int w = 0, v = 0;
int x = student_number;
char num1[max]; //用户输入学生姓名
system("cls"); //清屏函数
cout << "请输入查找的学号:";
cin >> num1;
print_table();//打印学生信息表格的表头函数
for (w = 0; w < student_number; w++) {
char* result = strstr(s[w].num, num1);
// 如果找到,则打印对应学生信息
if (result != nullptr) {
cout << "| " << s[w].name << " | " << s[w].num << " | " << s[w].sex << " | " << s[w].age << " | " << s[w].hometown << " | " << s[w].major << " |" << endl;
v++;
}
}
cout << endl << "满足条件的学生人数为:" << v << "人" << endl;//统计满足条件的学生人数
v = 0;
cout << endl << "1.返回主界面" << endl << "2.继续查询";//询问返回哪里
cout << "请输入:";
getchar();//获取用户回答
if (getchar() == 1)
{
main_menu();
}
else
{
search_record();
}
}
void search_by_name() { //查询学生信息函数的子函数——按姓名查询函数
system("cls"); //清屏函数
//定义一个int类型变量来获取用户的输入
int z;
//打印菜单
cout << "1 精准查询" << endl;
cout << "2 模糊查询" << endl;
cout << "3 返回上一级" << endl;
cout << "请输入:";
cin >> z;
//给定条件查询
if (z == 1)
search_by_name1(); //按学号查询函数
if (z == 2)
search_by_name2(); //按姓名查询函数
if (z == 3)
search_by_exit(); //返回主界面
else
{
cout << ("输入错误\n");
search_record(); //重新查询
}
}
void search_by_name1() { //按名字查找——精准查找
//定义两个int型变量来获取用户的输入
int i;
int v = 0;
int x = student_number;
char name1[max]; //用户输入学生姓名
system("cls"); //清屏函数
cout << "请输入查找的姓名:";
cin >> name1;
for (i = 0; i < student_number; i++) //遍历链表,看该名字是否存在
{
if (strcmp(name1, s[i].name) == 0)
{
print_table();//打印学生信息表格的表头函数
cout << "| " << s[i].name << " | " << s[i].num << " | " << s[i].sex << " | " << s[i].age << " | " << s[i].hometown << " | " << s[i].major << " |" << endl;
v++;
break;
}
}
cout << endl << "满足条件的学生人数为:" << v << "人" << endl;//统计满足条件的学生人数
if (i == student_number) {
cout << "不存在这个姓名" << endl;
}
cout << endl << "1.返回主界面" << endl << "2.继续查询";//询问返回哪里
cout << "请输入:";
getchar();//获取用户回答
if (getchar() == 1)
{
main_menu();
}
else
{
search_record();
}
}
void search_by_name2() { //按名字查找——模糊查找
//定义两个int型变量来获取用户的输入
int w = 0, v = 0;
int x = student_number;
char name1[max]; //用户输入学生姓名
system("cls"); //清屏函数
cout << "请输入查找的姓名:";
cin >> name1;
print_table();//打印学生信息表格的表头函数
for (w = 0; w < student_number; w++) {
char* result = strstr(s[w].name, name1);
// 如果找到,则打印对应学生信息
if (result != nullptr) {
cout << "| " << s[w].name << " | " << s[w].num << " | " << s[w].sex << " | " << s[w].age << " | " << s[w].hometown << " | " << s[w].major << " |" << endl;
v++;
}
}
cout << endl << "满足条件的学生人数为:" << v << "人" << endl;//统计满足条件的学生人数
v = 0;
cout << endl << "1.返回主界面" << endl << "2.继续查询";//询问返回哪里
cout << "请输入:";
getchar();//获取用户回答
if (getchar() == 1)
{
main_menu();
}
else
{
search_record();
}
}
void search_by_sex() //查询学生信息函数的子函数——按性别查询函数
{
//定义两个int型变量来获取用户的输入
int i;
char sex1[max]; //用户输入学生的性别
system("cls"); //清屏函数
cout << "请输入查找的性别(男/女):";
cin >> sex1;
print_table(); //表格
for (i = 0; i < student_number; i++) //遍历链表,看该性别是否存在
{
if (strcmp(sex1, s[i].sex) == 0)
cout << "| " << s[i].name << " | " << s[i].num << " | " << s[i].sex << " | " << s[i].age << " | " << s[i].hometown << " | " << s[i].major << " |" << endl;
}
if (i == student_number)
{
cout << ("1.返回主界面\n2.继续查询\n");
}
cout << "请输入:";
getchar();//获取用户回答
if (getchar() == 1)
{
main_menu();
}
else
{
search_record();
}
}
void search_by_mult() { //多条件查询
//定义两个int型变量来获取用户的输入
int i;
//定义用户想要查询的多个条件
char sex1[max]; //用户输入学生的性别
int chinese1; //用户输入学生年龄
char mathematic1[max]; //用户输入学生籍贯
system("cls"); //清屏函数
//打印菜单
cout << "请输入学生性别:";
cin >> sex1;
cout << "请输入学生年龄:";
cin >> chinese1;
cout << "请输入学生籍贯:";
cin >> mathematic1;
print_table(); //表格
for (i = 0; i < student_number; i++) //遍历链表,看符合三条件的信息是否存在
{
if (strcmp(sex1, s[i].sex) == 0 && (chinese1 == s[i].age) && strcmp(mathematic1, s[i].hometown) == 0)
cout << "| " << s[i].name << " | " << s[i].num << " | " << s[i].sex << " | " << s[i].age << " | " << s[i].hometown << " | " << s[i].major << " |" << endl;
}
if (i == student_number)
{
cout << ("1.返回主界面\n2.继续查询\n");
}
cout << "请输入:";
getchar();//获取用户回答
if (getchar() == 1)
{
main_menu();
}
else
{
search_record();
}
}
void search_by_exit() //返回上一级(返回主菜单)的函数
{
main_menu();
}
//4 更新学生成绩函数
void change_record() //更新学生成绩函数 4
{
//输入学生学号修改学生信息并保持
system("cls"); //清屏函数
int i;
char name2[max], sex2[max], hometown2[max], major2[max];
int age2;
char numbefor[max];
cout << "请输入要修改的学生的学号:"; //用户输入学生学号
cin >> numbefor;
for (i = 0; i < student_number; i++) //遍历链表,看该学号是否存在
{
if (strcmp(numbefor, s[i].num) == 0) //存在
{
//先给出修改前的该学生信息
cout << "修改前:" << endl;
print_table(); //打印表格表头
cout << "| " << s[i].name << " | " << s[i].num << " | " << s[i].sex << " | " << s[i].age << " | " << s[i].hometown << " | " << s[i].major << " |" << endl;
//一一输入修改后的信息(可以再次优化,只修改部分信息,如给出选项:1.全部修改 2.部分修改)
cout << "请分别输入修改后信息" << endl;
cout << "请输入学生姓名:";
cin >> name2;
cout << "请输入学生性别:";
cin >> sex2;
cout << "请输入学生年龄:";
cin >> age2;
cout << "请输入学生籍贯:";
cin >> hometown2;
cout << "请输入学生专业:";
cin >> major2;
cout << "请选择是否保存(y或n):";
getchar();
if (getchar() == 'y') //修改学生信息
{
strcpy(s[i].name, name2);
strcpy(s[i].sex, sex2);
s[i].age = age2;
strcpy(s[i].hometown, hometown2);
strcpy(s[i].major, major2);
save_record(); //保存学生信息到文件中
//将修改后的学生信息打印展示
cout << "修改后:" << endl;
cout << "| " << s[i].name << " | " << s[i].num << " | " << s[i].sex << " | " << s[i].age << " | " << s[i].hometown << " | " << s[i].major << " |" << endl;
cout << endl;
}
break;
}
}
if (i == student_number--)//遍历到最后一位学生了
{
cout << "很抱歉!没有这位学生" << endl;
}
cout << "是否继续更新学生信息,请选择(y/n):";
getchar();
if (getchar() == 'y')
{
change_record(); //继续修改
}
if (getchar() == 'n')
{
main_menu(); //返回主界面
}
}
void delete_record() //删除学生信息函数 5
{
//输入学生学号删除学生信息并保存
system("cls");//清屏函数
char num4[max];//存储输入的学号
char a;
cout << "请输入要删学生的学号:" << endl;
cin >> num4;
//定义用于for循环的两个变量
int i, j;
for (i = 0; i < student_number; i++) //遍历链表,看学号是否存在
{
if (strcmp(num4, s[i].num) == 0) //存在,执行删除操作
{
cout << "你将要删除该学生信息" << endl;
cout << "| " << s[i].name << " | " << s[i].num << " | " << s[i].sex << " | " << s[i].age << " | " << s[i].hometown << " | " << s[i].major << " |" << endl;
cout << endl;
cout << "y 确认删除" << endl << "n 取消" << endl;
cout << "请输入:";
cin >> a;
if (a == 'y')
{
for (j = i; j < student_number; j++) //将链表中该节点指向下一节点以实现删除操作
{
strcpy_s(s[j].num, s[j + 1].num);
strcpy_s(s[j].name, s[j + 1].name);
strcpy_s(s[j].sex, s[j + 1].sex);
s[j].age = s[j + 1].age;
strcpy_s(s[j].hometown, s[j + 1].hometown);
strcpy_s(s[j].major, s[j + 1].major);
}
cout << "删除成功!" << endl;
student_number--; //全局变量,student_number-1
save_record(); //将删除后的信息保存到文件中
}
//取消删除
else
{
cout << "已取消操作" << endl;
}
}
}
if (i == student_number) //该学号不存在
{
cout << "没有这个学号的学生" << endl;
}
cout << "1.继续删除" << endl << "2.返回主界面" << endl;
cout << "请输入:" << endl;
getchar();
if (getchar() == 1)
{
delete_record();
}
else
{
main_menu();
}
}
//文件读写
//写文件
void save_record()
{
//文本文件方式存储(txt)
int q = 0;
ofstream file("D:\\Student Management2\\Student Management\\Student Management\\student message.txt", ios::out);
for (q = 0; q < student_number; q++) //将学生信息写入文件
{
file << s[q].name << " " << s[q].num << " " << s[q].sex << " " << s[q].age << " " << s[q].hometown << " " << s[q].major << endl; //按“ ”隔开字符串写入文件
}
file.close();//关闭文件
//二进制方式对文件进行写
FILE* fp; //定义一个文件指针
int i;
//若文件打开失败
if ((fp = fopen("student-list", "wb")) == NULL)
{
cout << "cannot open file" << endl;
return;
}
//size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
fwrite(&student_number, 4, 1, fp); //将学生人数写入文件
for (i = 0; i < student_number; i++) //二进制写
{
if (fwrite(&s[i], sizeof(struct student), 1, fp) != 1)
{
cout << "file write error" << endl; //出错处理
}
else
{
cout << "file write sucess" << endl; //文件写入成功
}
}
fclose(fp); //关闭文件指针
}
//读文件
void read() //将文件中的数据读入到结构体数组中
{
FILE* fp; //定义一个文件指针
int i;
//若文件打开失败
if ((fp = fopen("student-list", "rb")) == NULL) //以二进制方式读取文件
{
cout << "cannot open file" << endl;
return;
}
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
fread(&student_number, 4, 1, fp); //读取学生人数
for (i = 0; i < student_number; i++) //二进制写
{
if (fread(&s[i], sizeof(struct student), 1, fp) != 1)
{
cout << "file read error" << endl; //出错处理
}
else
{
cout << "file read sucess" << endl; //文件读取成功
}
}
fclose(fp); //关闭文件指针
}
//8 退出系统(退出”机制)
void exit_record() //退出系统函数 8
{
cout << "感谢您的使用,已退出!";
exit(0);
}