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

目录

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  学生管理系统的功能结构图

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)定义文件指针

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 程序流程图

图3  文件读写程序流程图

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  goto语句

        (4)计算字符串的长度

size_t strlen(const char *str) 

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

int atoi(const char *str)

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

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

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 程序流程图

图6  数据查询流程图

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].homestrcpy_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 程序流程图

图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 源代码

//头文件
#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-1save_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);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/32278.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

“三巫日”大结局:标普500尾盘成交量飙升,英伟达“过山车”终以下跌收盘

内容提要 隔夜“美股三巫日”&#xff0c;美国证券交易所迎来了180亿股的换手&#xff0c;较过去三个月的平均水平激增55%&#xff0c;标普500尾盘成交量比平日激增30%。在周五到期的5.5万亿美元各类证券衍生品里&#xff0c;与英伟达相关的衍生品合约价值高居第二&#xff0c…

upload-labs实验过程中遇到的问题

第6题问题&#xff1a;500异常码 发现500异常码&#xff0c;这个应该是apache版本问题&#xff0c;可更换其他版本&#xff0c;或者更换为nginx 12题问题&#xff1a;上传出错 出现上传错误&#xff0c;大概率是php版本问题&#xff0c;需要下载php5.2.17版本的php或者更换其他…

编程书籍的枯燥真相:你也有同样的感受吗?

讲动人的故事,写懂人的代码 我得实话实说,你可能已经发现市面上的大部分编程入门书籍有些枯燥。这个问题的根源在于许多作者把本应该充满乐趣和吸引力的入门指南,写得就像一本沉闷的参考手册。这就好比把一本充满冒险和乐趣的旅行日记,写成了一本单调乏味的字典。 我完全理…

开放式耳机有什么好处?推荐几款开放式蓝牙耳机

现在开放式蓝牙耳机面市,迅速占领了市场一席之地后。各大品牌商纷纷参与研制,开放蓝牙耳机与的竞争日趋激烈。这种开放式耳机崛起的速度,连我作为一个数码博主都得感叹一句绝了&#xff0c;所以我花了大几千块&#xff0c;又买了现在很热门的五款开放式耳机&#xff0c;这篇收集…

揭秘古代手术工具与技术:从中国起源的医疗奇迹

在人类历史的长河中&#xff0c;医学的发展一直是推动社会进步的重要力量。而手术作为医学的一个重要分支&#xff0c;其发展历程同样充满了传奇色彩。今天&#xff0c;我们将带您走进古代手术的世界&#xff0c;揭秘那些令人惊叹的手术工具和技术。 这把手术刀出土于河北西村遗…

【SkiaSharp绘图09】SKBitmap属性详解

文章目录 SKBitmap与Bitmap性能对比对比结果 构造函数SKBitmap()SKBitmap(SKImageInfo)SKBitmap(Int32, Int32, SKColorType, SKAlphaType, SKColorSpace) SKBitmap属性AlphaTypeByteCountBytesBytesPerPixelColorSpaceColorTypeDrawsNothingInfoIsEmptyIsImmutableIsNullPixel…

“脏读”、“幻读”、“不可重复读”

“脏读”、“幻读”、“不可重复读” 1.概念说明 “脏读”、“幻读”、“不可重复读”是数据库事务的概念。 “脏读”是指一个事务中访问到了另外一个事务未提交的数据。 “不可重复读”是指在一个事务内根据同一个条件对数据进行多次查询&#xff0c;但是结果却不一致&…

C++ Vector的模拟实现

vector的介绍 1. vector是表示可变大小数组的序列容器。 2. 就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问&#xff0c;和数组一样高效。但是又不像数组&#xff0c;它的大小是可以动态改变的&#xff0c;而…

人形机器人背后的关键技术之一:人体姿态估计WHAM与手势估计HaMeR

前言 本文一开始是属于此文的&#xff0c;但由于人体姿态估计WHAM与手势估计HaMeR比较重要&#xff0c;故导致越写越长&#xff0c;故独立抽取出来成为本文了 第一部分 姿态估计之 WHAM 1.1 WHAM的整体架构 根据arXiv的记录&#xff0c;此篇论文WHAM: Reconstructing World-…

Apple - Advanced Memory Management Programming Guide 内存管理

翻译整理自&#xff1a;Advanced Memory Management Programming Guide&#xff08;Updated: 2012-07-17 https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html#//apple_ref/doc/uid/10000011i 文章目录 一、关于…

异步FIFO

目录 描述 输入描述&#xff1a; 输出描述&#xff1a; 参考代码 描述 请根据题目中给出的双口RAM代码和接口描述&#xff0c;实现异步FIFO&#xff0c;要求FIFO位宽和深度参数化可配置。 电路的接口如下图所示。 双口RAM端口说明&#xff1a; 端口名 I/O 描述 wclk i…

LQR 控制算法应用分析

参考 Optimization Based Control 从基础到复杂地介绍最优控制理论 麻省理工大学机器人算法第八章 LQR 大概说了 lqr 的推导过程&#xff0c;主页有更多算法介绍 wiki LQR 控制器 LQR 多种公式说明 Formulas for discrete time LQR, LQG, LEQG and minimax LQG optimal con…

Springboot项目ES报异常query_shard_exception

详细异常信息如下&#xff1a; {"error": {"root_cause": [{"type": "query_shard_exception","reason": "failed to create query: {\n \"bool\" : {\n \"filter\" : [\n {\n \…

换电脑后导入git本地仓库记录

导入本地仓库tig记录 换了新电脑&#xff0c;将旧电脑的数据盘查到新的笔记本之后发现&#xff0c;使用pycharm 读取不到本地的git提交记录了&#xff0c;我没有将本地git上传到远程仓库的习惯&#xff0c;这可抓马了&#xff0c;硬盘插回去的话也太麻烦了。试了 vscode 提示设…

Vue77-编程式路由

一、需求 不写<router-link>实行路由的跳转。 因为<router-link>的本质是<a>&#xff0c;但是&#xff0c;有时&#xff0c;导航不一定是a标签&#xff01;或者&#xff0c;有时需要等一段时间&#xff0c;页面才跳转。 二、代码实现 三、小结

Wakelocks 框架设计与实现

Wakelocks 框架是基于Wakeup Source实现的为Android系统上层提供投票机制&#xff0c;以阻止系统进入休眠。 1.功能说明 该模块的支持受宏CONFIG_PM_WAKELOCKS控制。在使能该宏的情况下&#xff0c;PM Core初始化过程中会在sysfs下创建两个属性节点&#xff1a; /sys/power/w…

Gradle学习-1

1、APK构建流程 2、Gradle的安装 &#xff08;1&#xff09;安装Java JDK JAVA JDK 下载地址下载安装后需要配置环境变量gradle是运行在Java虚拟机上的&#xff0c;所以需要配置Java JDK &#xff08;2&#xff09;安装 Gradle Gradle下载官网下载安装后需要配置环境变量 …

vscode创建编辑markdown文件

Markdown 是一种轻量级标记语言, 它允许人们使用易读易写的纯文本格式编写文档&#xff0c;然后转换成有效的 XHTML&#xff08;或者HTML&#xff09;文档。 由于 Markdown 的轻量化、易读易写特性&#xff0c;并且对于图片&#xff0c;图表、数学式都有支持&#xff0c;许多网…

[保姆级教程]uniapp配置vueX

文章目录 注意新建文件简单的使用 注意 uniapp是支持vueX的只需配置一下就好 新建文件 在src文件中&#xff0c;新建一个store&#xff08;如果有的话跳过&#xff09; 在store中新建一个js文件&#xff0c;修改js文件名称和选择模板为default 在 uni-app 项目根目录下&…

Vue80-全局路由守卫:前置、后置

一、路由守卫的定义 二、需求 在第三步&#xff0c;做校验&#xff01; 三、代码实现 3-1、前置路由守卫 注意&#xff0c;此时就不能将router一开始就暴露出去了&#xff01; to和from是路由组件的信息。 写法一&#xff1a; 写法二&#xff1a; 缺点&#xff1a;若是路由…