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 程序流程图
图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 程序流程图
图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 程序流程图
图9 易用性流程图

3 设计结果

3.1学生信息的存储方式:文件存储

3.1.1 当使用"增加学生信息"操作时,输入学生信息并选择保存后,将会显示"file write sucess",则学生信息写入文件成功。
图10 保存增加的学生信息成功

可以看见txt文件中存储的信息增加了刚刚添加的学生信息:
图11 增加学生信息之前的txt文件
图12 增加学生信息之后的txt文件

3.1.2当使用"更新学生信息"操作时,输入更新后学生信息并选择保存后,将会显示"file write sucess",则学生信息写入文件成功。
图13 更新学生信息成功

可以看见txt文件中刚才更新的学生的姓名信息已经发生了改变:
图14 更新学生信息之前的txt文件
图15 更新学生信息之后的txt文件

3.1.3当使用"删除学生信息"操作时,输入想要删除的学生的学号,确定删除后,将会显示"file write sucess",则学生信息删除文件成功。
图16 删除学生信息成功

可以看见txt文件中刚才删除的学生信息已经被删除了:
图17 删除学生信息之前的txt文件
图18 删除学生信息之后的txt文件

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

图19 增加学生信息

由图可见,当输入学号已被录入时,让用户重新输入;当输入学号不是12位时,让用户重新输入;当输入学号前四个字符不是合理年份时,让用户重新输入;当输入性别不是"男"或"女"时,让用户重新输入;当输入年龄不是合法年龄时,让用户重新输入。

保存后可以看见增加的学生信息可以显示:
图20 显示增加学生信息之后的所有学生信息

3.3数据查询

3.3.1 按学号查询

(1)精准查询

①当输入学号不存在时,让用户选择是否重新输入。
图21 学号精准查询用户不存在

②当输入学号存在时,打印该学生信息。
图22 学号精准查询用户存在

(2)模糊查询

输入一段想查询的学号,如"1104",则找到学号为"202211701104"的学生,打印该学生信息。
图23 学号模糊查询

3.3.2 按姓名查询

(1)精准查询

用户输入学生的姓名,若找到,则打印该学生信息。
图24 姓名精准查询

(2)模糊查询

输入一段想查询的姓名字符,如"王",则找到姓名中有"王"字的"王一五",打印该学生信息。
图25 姓名模糊查询

3.3.3 按性别查询

(1)输入为"男",若找到性别为"男"的学生,则打印信息。
图26 性别查询"男"

(2)输入为"女",若找到性别为"女"的学生,则打印信息。
图27 性别查询"女"

3.3.4 多条件查询

逐次输入学生的性别、年龄、籍贯,如下图搜索的是"18岁的广东省广州市女生信息"。
图28 多条件查询

3.4数据删除

(1)当输入学号不存在时,让用户选择是否继续删除。
图29 数据删除用户不存在

(2)当输入学号存在时,打印该学生信息,询问是否确定删除。
图30 数据删除成功

3.5数据更新

(1)当输入学号不存在时,让用户选择是否继续更新。
图31 数据更新用户不存在

(2) 当输入学号存在时,打印该学生信息,让用户一一输入修改的信息,最后若保存修改,打印该学生修改后的信息。
图32 数据更新成功

3.6易用性:有"进入"和"退出"机制,符合使用习惯的流程控制过程

3.6.1 管理员"进入"机制

(1)若输入管理员账号密码正确,则进入主菜单界面。
图33 正确输入管理员账号密码

(2)若输入管理员账号密码错误,则重新输入。
图34 管理员账号密码输入错误

若连续三次输入错误,则自动退出程序。
图35 管理员账号密码连续三次输入错误

3.6.2 "退出"机制

在主菜单界面输入"6",正常退出程序。
图36 退出程序

4 源代码

cpp 复制代码
//头文件
#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);
}
相关推荐
@小博的博客6 分钟前
C++初阶学习第十弹——深入讲解vector的迭代器失效
数据结构·c++·学习
爱吃喵的鲤鱼1 小时前
linux进程的状态之环境变量
linux·运维·服务器·开发语言·c++
7年老菜鸡2 小时前
策略模式(C++)三分钟读懂
c++·qt·策略模式
Ni-Guvara2 小时前
函数对象笔记
c++·算法
似霰2 小时前
安卓智能指针sp、wp、RefBase浅析
android·c++·binder
芊寻(嵌入式)2 小时前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
獨枭2 小时前
C++ 项目中使用 .dll 和 .def 文件的操作指南
c++
霁月风2 小时前
设计模式——观察者模式
c++·观察者模式·设计模式
橘色的喵2 小时前
C++编程:避免因编译优化引发的多线程死锁问题
c++·多线程·memory·死锁·内存屏障·内存栅栏·memory barrier
何曾参静谧3 小时前
「C/C++」C/C++ 之 变量作用域详解
c语言·开发语言·c++