C++程序设计基础实践:学生信息管理系统

目录

[1 系统介绍](#1 系统介绍)

[2 系统设计](#2 系统设计)

[3 设计结果](#3 设计结果)

[4 源代码](#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 学生管理系统的功能结构图

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)文件读写
图2 文件操作

头文件:#include <fstream>

文件写操作,内存写入存储设备 :ofstream

文件读操作,存储设备读区到内存中:ifstream

读写操作,对打开的文件可进行读写操作:fstream

(2)定义文件指针

cpp 复制代码
FILE*

(3)打开文件

cpp 复制代码
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 程序流程图
图3 文件读写程序流程图

2.2学生记录数据录入、增加

2.2.1 具体设计过程

(1)输入学生姓名

cpp 复制代码
cin >> s[student_number++].name;

(2)输入学生学号

①输入

cpp 复制代码
strcmp(s[student_number].num, s[i].num) == 0
cpp 复制代码
cin >> s[student_number].num;

②定义字符串aa,将const char*类型的s[student_number].num 转为字符串

cpp 复制代码
 string aa(s[student_number].num);

③定义临时变量 string temp(aa, 0, 4);

④for遍历链表,使用 strcmp() 函数判断该学号是否存在,保证记录唯一性

⑤使用 函数 strlen() 和 atoi(temp.c_str())截取用户输入学号的前四位,判断学号是否由12个数字字符组成,且前四个字符是否是合常理的年份

(3)输入用户性别

①输入

cpp 复制代码
cin >> s[student_number].sex;

②将const char* 类型的s[student_number].sex赋值给 char*类型的 c,并具体赋值输入的性别

③使用 strcmp() 函数判断该性别是否存在

(4)输入用户年龄

①输入

cpp 复制代码
cin >> s[student_number].age;

②使用 if 判断用户输入的年龄是否是数字字符且范围介于一个合理的区间

(5)输入学生籍贯

cpp 复制代码
cin >> s[student_number].hometown;

(6)输入学生专业

cpp 复制代码
cin >> s[student_number].major;

2.2.2 存储结构

先将用户输入的学生信息存储在内存中,然后询问用户输入的信息是否保存,如果保存,将内存中的学生信息写入文件中。

2.2.3 功能算法描述

(1)定义临时变量temp

cpp 复制代码
string temp(aa, 0, 4);

(2)字符串比较

cpp 复制代码
 int strcmp(const char *str1, const char *str2) 

把 str1 所指向的字符串和 str2 所指向的字符串进行比较。

如果返回值小于 0,则表示 str1 小于 str2。

如果返回值大于 0,则表示 str1 大于 str2。

如果返回值等于 0,则表示 str1 等于 str2。

(3)goto 语句:把控制无条件转移到同一函数内的被标记的语句
图4 goto语句

(4)计算字符串的长度

cpp 复制代码
size_t strlen(const char *str) 

(5)把参数所指向的字符串转换为int型

cpp 复制代码
int atoi(const char *str)

(6)从标准输入 stdin 获取一个字符(一个无符号字符)

cpp 复制代码
int getchar(void)

2.2.4 程序流程图
图5 学生记录增加程序流程图

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() 函数进行模糊查找

cpp 复制代码
char* result=strstr(s[w].num, num1)

若result不等于nullptr,则找到;

③循环一次v++,最后输出满足条件的学生人数为v。

(5)按性别查询函数 search_by_sex()

①定义 char sex1[max] 保存用户输入的学生性别;

②使用 for 循环遍历链表, strcmp() 判断,若存在该性别,则输出该学生信息

cpp 复制代码
strcmp(num1, s[i].num);

(6)多条件查询

①定义用户想要查询的多个条件

用户输入学生的性别 char sex1[max];

用户输入学生年龄 int chinese1;

用户输入学生籍贯 char mathematic1[max];

②使用for循环遍历链表,使用strcmp() 判断符合三条件的信息是否存在

cpp 复制代码
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()

cpp 复制代码
char *strstr(const char *haystack, const char *needle) 

在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 '\0'。

2.3.4 程序流程图
图6 数据查询流程图

2.4数据删除

2.4.1 具体设计过程

(1)定义 char num4[max] 存储输入的学号

(2)for 循环遍历链表,看学号是否存在,若 strcmp(num4, s[i].num)== 0,则存在。

(3)将链表中该节点指向下一节点以实现删除操作

cpp 复制代码
    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()函数

cpp 复制代码
strcpy_s(char *strDestination , size_t numberOfElements , const char *strSource);

参数:[out] strDestination:拷贝完成之后的字符串

in\] numberOfElements: strDestination目标缓冲区长度 \[in\] strSource:需要拷贝的字符串 (2)清屏函数system("cls") 2.4.4 程序流程图 ![](https://img-blog.csdnimg.cn/direct/ab4b19d81d2f4d26a0bb0eb2e52b0c02.png) 图7 数据删除流程图 #### ****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 程序流程图 ![](https://img-blog.csdnimg.cn/direct/836da8b5a02943319fa95b22d7b4373f.png) 图8 数据更新流程图 #### ****2.6易用性:有"进入"和"退出"机制,符合使用习惯的流程控制过程**** 2.6.1 具体设计过程 (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 程序流程图 ![](https://img-blog.csdnimg.cn/direct/ad65706deb9a47b5beac20ed1097b037.png) 图9 易用性流程图 ## ******3**** ****设计结果****** #### ****3.1学生信息的存储方式:文件存储**** 3.1.1 当使用"增加学生信息"操作时,输入学生信息并选择保存后,将会显示"file write sucess",则学生信息写入文件成功。 ![](https://img-blog.csdnimg.cn/direct/1cce85c62f3c47cb910f84297e7f4539.png) 图10 保存增加的学生信息成功 可以看见txt文件中存储的信息增加了刚刚添加的学生信息: ![](https://img-blog.csdnimg.cn/direct/fda5234d833b419688fddf6a78b0944d.png) 图11 增加学生信息之前的txt文件 ![](https://img-blog.csdnimg.cn/direct/66efcc35332d47bb900952c87dfe8914.png) 图12 增加学生信息之后的txt文件 3.1.2当使用"更新学生信息"操作时,输入更新后学生信息并选择保存后,将会显示"file write sucess",则学生信息写入文件成功。 ![](https://img-blog.csdnimg.cn/direct/616693215bc742f9810a5cc2f1edb178.png) 图13 更新学生信息成功 可以看见txt文件中刚才更新的学生的姓名信息已经发生了改变: ![](https://img-blog.csdnimg.cn/direct/7dccee7fd24644199740897777610cd3.png) 图14 更新学生信息之前的txt文件 ![](https://img-blog.csdnimg.cn/direct/709401c0557f4b99981f71f717182aed.png) 图15 更新学生信息之后的txt文件 3.1.3当使用"删除学生信息"操作时,输入想要删除的学生的学号,确定删除后,将会显示"file write sucess",则学生信息删除文件成功。 ![](https://img-blog.csdnimg.cn/direct/96f6e6aa91d94e7192439ec8eb2c0b52.png) 图16 删除学生信息成功 可以看见txt文件中刚才删除的学生信息已经被删除了: ![](https://img-blog.csdnimg.cn/direct/65d8003e991a495ab0dffa8760b6ed85.png) 图17 删除学生信息之前的txt文件 ![](https://img-blog.csdnimg.cn/direct/91118cf8be6d4372b108d24629255b19.png) 图18 删除学生信息之后的txt文件 #### ****3.2学生记录数据录入、增加**** ![](https://img-blog.csdnimg.cn/direct/64336b86aa8f40a5a438a626330d37dc.png) 图19 增加学生信息 由图可见,当输入学号已被录入时,让用户重新输入;当输入学号不是12位时,让用户重新输入;当输入学号前四个字符不是合理年份时,让用户重新输入;当输入性别不是"男"或"女"时,让用户重新输入;当输入年龄不是合法年龄时,让用户重新输入。 保存后可以看见增加的学生信息可以显示: ![](https://img-blog.csdnimg.cn/direct/84902d75f4034103b05207a5990cd253.png) 图20 显示增加学生信息之后的所有学生信息 #### ****3.3数据查询**** 3.3.1 按学号查询 (1)精准查询 ①当输入学号不存在时,让用户选择是否重新输入。 ![](https://img-blog.csdnimg.cn/direct/828ad1b75a2a4061b2e2edddaa8768d2.png) 图21 学号精准查询用户不存在 ②当输入学号存在时,打印该学生信息。 ![](https://img-blog.csdnimg.cn/direct/7c0401671ede4de7a81bca8eda454344.png) 图22 学号精准查询用户存在 (2)模糊查询 输入一段想查询的学号,如"1104",则找到学号为"202211701104"的学生,打印该学生信息。 ![](https://img-blog.csdnimg.cn/direct/956e61e9b9654fbea38a1272b69c3d97.png) 图23 学号模糊查询 3.3.2 按姓名查询 (1)精准查询 用户输入学生的姓名,若找到,则打印该学生信息。 ![](https://img-blog.csdnimg.cn/direct/1f6ab1fe7161409f91733057b40d215b.png) 图24 姓名精准查询 (2)模糊查询 输入一段想查询的姓名字符,如"王",则找到姓名中有"王"字的"王一五",打印该学生信息。 ![](https://img-blog.csdnimg.cn/direct/ed89aa2c23f64a2c9e26a18b1b2b2c82.png) 图25 姓名模糊查询 3.3.3 按性别查询 (1)输入为"男",若找到性别为"男"的学生,则打印信息。 ![](https://img-blog.csdnimg.cn/direct/aa51db2cc820488aab95369889f12182.png) 图26 性别查询"男" (2)输入为"女",若找到性别为"女"的学生,则打印信息。 ![](https://img-blog.csdnimg.cn/direct/a803aeee73cb4333be534811b5daaac0.png) 图27 性别查询"女" 3.3.4 多条件查询 逐次输入学生的性别、年龄、籍贯,如下图搜索的是"18岁的广东省广州市女生信息"。 ![](https://img-blog.csdnimg.cn/direct/bd9bba21799245ffac67e5827636d01d.png) 图28 多条件查询 #### ****3.4数据删除**** (1)当输入学号不存在时,让用户选择是否继续删除。 ![](https://img-blog.csdnimg.cn/direct/4a0f549891734366ba5bdb5ced6a4667.png) 图29 数据删除用户不存在 (2)当输入学号存在时,打印该学生信息,询问是否确定删除。 ![](https://img-blog.csdnimg.cn/direct/ba0e8de985084df196722682d70c8444.png) 图30 数据删除成功 #### ****3.5数据更新**** (1)当输入学号不存在时,让用户选择是否继续更新。 ![](https://img-blog.csdnimg.cn/direct/d3f05df38cde478aaa9e61e46ac46ac0.png) 图31 数据更新用户不存在 (2) 当输入学号存在时,打印该学生信息,让用户一一输入修改的信息,最后若保存修改,打印该学生修改后的信息。 ![](https://img-blog.csdnimg.cn/direct/9ac55f93ad10458d8f59197d32768223.png) 图32 数据更新成功 #### ****3.6易用性:有"进入"和"退出"机制,符合使用习惯的流程控制过程**** 3.6.1 管理员"进入"机制 (1)若输入管理员账号密码正确,则进入主菜单界面。 ![](https://img-blog.csdnimg.cn/direct/bf36fe26357d4e48a616b6b0255b86bf.png) 图33 正确输入管理员账号密码 (2)若输入管理员账号密码错误,则重新输入。 ![](https://img-blog.csdnimg.cn/direct/f86bc616140743e5baaddb0b05b11299.png) 图34 管理员账号密码输入错误 若连续三次输入错误,则自动退出程序。 ![](https://img-blog.csdnimg.cn/direct/fd4bc4dfdc8b4133a650e99351768fdf.png) 图35 管理员账号密码连续三次输入错误 3.6.2 "退出"机制 在主菜单界面输入"6",正常退出程序。 ![](https://img-blog.csdnimg.cn/direct/57cf385af9974213b9fcb1e05811a9d6.png) 图36 退出程序 ## 4 源代码 ```cpp //头文件 #include //数据流输入/输出 #include //standard library标准库 #include //关于字符数组的函数定义 #include //字符串类 #include //C++ STL中对文件操作 #include //字符串流,用于格式转换 #include // 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); } ```

相关推荐
别来无恙20210 分钟前
算法设计学习4
c++·学习
wuqingshun31415913 分钟前
蓝桥杯 切割
数据结构·c++·算法·职场和发展·蓝桥杯
艾妮艾妮16 分钟前
C语言常见3种排序
java·c语言·开发语言·c++·算法·c#·排序算法
小王努力学编程18 分钟前
动态规划学习——回文子串系列问题【C++】
c++·学习·算法·leetcode·动态规划
划水哥~42 分钟前
创建QMainWindow菜单栏
开发语言·c++·qt
饕餮ing1 小时前
C++的UDP连接解析域名地址错误
开发语言·c++·udp
小林熬夜学编程1 小时前
【高并发内存池】第八弹---脱离new的定长内存池与多线程malloc测试
c语言·开发语言·数据结构·c++·算法·哈希算法
曦月逸霜2 小时前
蓝桥杯高频考点——高精度(含C++源码)
c++·算法·蓝桥杯
敲上瘾2 小时前
高并发内存池(二):Central Cache的实现
linux·服务器·c++·缓存·哈希算法
SNAKEpc121383 小时前
在MFC中使用Qt(五):MFC和Qt的共存和交互
c++·qt·mfc