C++学生信息和考试成绩管理系统

第一章 工程介绍

第二章 用户登陆准备和登陆

第三章 用户的增删查改

第四章 考试创建&成绩的增改

第五章 成绩查询


第三章 用户的增删查改

  • C++学生信息和考试成绩管理系统
  • 一、创建用户
  • 二、删除用户

一、创建用户

继续,回到刚才管理员菜单界面,假设这时候我要创建一个用户,那就进入第1个菜单选项(第0个是结束程序,别以为我不知道)。这个是有点长,不过还能接受。
当前位置:manage_admin.cpp

void print_menu_admin_account_create(menu& menus)
{while (true){CLEAN;// ---------- Start ----------// 自定义函数:选择判断,输入非Y即N,否则返回-1并提示错误信息switch (input_judgment(true, true, "Do you want to create an account? (Y/N): ")) {case -1:continue;case 0:return;case 1:default:break;}// ---------- Print Menu & Select Privilege ----------// 前面介绍了这个函数,打印菜单并提示内容print_menu(true, 1, menus.vector_menu_create_account, "Please set a privilege or back: ");// 前面介绍了这个函数,输入选项,不在范围内就要求重新输入const int option = input_option(static_cast<int>(menus.vector_menu_create_account.size())); switch (option){case 0:break;case 1:case 2:{auto* student = new student_info();// 新建并初始化一个学生类对象// ---------- Select ----------// 输入要注册的用户名student->user_id = input(MAXSIZE_INPUT_USER_ID, true, "Please set account(user) name: "); // 自定义函数:查找用户名是否存在,返回的是一个template_operation类对象,有成员info_flag为bool型if (user_select(student->user_id)->info_flag){print_wait("Cancelled because the user already exists!");break;}// ---------- Input Information ----------// 输入要注册的用户密码student->user_password = input(MAXSIZE_INPUT_USER_PASSWORD, true, "Please set account(user) password: ");// 输入权限student->user_privilege = option;// 输入学生姓名student->name = input(MAXSIZE_STUDENT_NAME, true, "Please set administrator/student true name: ");while (true){// 输入学号student->id = input(MAXSIZE_STUDENT_ID, true, "Please set it administrator/student id: ");// 自定义函数:看看输入的是不是纯数字,我推荐用正则表达式,后面我大都是用正则,前面因为懒就随便写了下这个if (is_positive_integer(student->id)){if (!user_select(student->id, 2)->info_flag){break;}// 自定义函数:停止等待并提示print_wait("Cancelled because the user already exists!");free_ptr(student->id, true);// 自定义函数:释放学生类对象continue;}free_ptr(student->id, true);print_wait("Please input integer.");}while (true){// 输入班级号student->class_id = input(MAXSIZE_CLASS_ID, true, "Please set it administrator/student class id: ");if (is_positive_integer(student->class_id)) // 看看输入的是不是纯数字,这个可以自己完成{break;}free_ptr(student->class_id, true);print_wait("Please input integer.");}while (true){// 输入性别std::cout << "Please set administrator/student gender (0:Female, 1:Male): ";student->gender = input_option(2);// 仅限输入0或1,分别代表女或男if (0 == student->gender || 1 == student->gender){break;}print_wait("Please input integer.");}// ---------- Reconfirm ----------// 再次确认是不是输入对了switch (input_judgment(true, true, "Are you sure you've filled in the information? (Y/N): ")){case -1:free_ptr(student);continue;case 0:print_wait("Canceled.");free_ptr(student);return;case 1:default:break;}// ---------- Store Information ----------if (!user_store(student))// 存储信息{print_wait("Canceled because save errors!");free_ptr(student);return;}// ---------- Print Information ----------student->print_information();// 调用类对象的输出打印成员函数print_wait("Created Successfully! Press any key to back...\n", false);// ---------- Finish ----------free_ptr(student);// 释放类对象return;}default:print_wait("Please input a correct option! ");break;}}
}

介绍下里面提到的这些自定义函数。首先是input_judgment(),这个函数用于判断输入的是Y还是N或者回车,不分大小写,提示内容,并返回结果,代码如下。
当前位置:format_input.cpp

int input_judgment(const bool is_print_hint, const bool is_default_error, ...)
{if (is_print_hint){va_list ap; // 这个读取变长参数操作也就这样,不停指针指向下一个地址,具体网上查查,这里不详细讲了va_start(ap, is_default_error);std::cout << va_arg(ap, const char*);va_end(ap);}const char choice = input_char(); // 输入一个字符,自定义函数,其实也就是只读一个字符,避免换行符干扰if (choice == 'Y' || choice == 'y' || choice == '\n'){return 1;}if (choice == 'N' || choice == 'n'){return 0;}if (is_default_error == true){print_wait("Please input a correct option! ");}return -1;
}

上面那个应该不难,下面这个是学生类对象,其实下面这些本来是很多注释的,考虑到实际,所以都删了,只留了主要的。
当前位置:student_info.h

class student_info
{public:// 打印学生信息void print_information();// 设置账户前三要素void set_student_account(const int get_user_privilege, char* get_user_password, char* get_user_id);// 设置账户后四要素void set_student_info(int get_gender, char* get_student_class, char* get_student_id, char* get_student_name, char* get_user_id);// 用户名char* user_id = nullptr;// 密码char* user_password = nullptr;// 权限int user_privilege = -1;// 姓名char* name = nullptr;// 学号char* id = nullptr;// 班级号char* class_id = nullptr;// 性别int gender = -1;
};

下面敲黑板了,算是一个小重点吧,也就是user_select()函数。是不是看着一脸懵,像刚刚说的,operation_info<T*>只是一个模板,需要传递类对象进去才有用,这个模板的作用主要也就是为这个类对象服务的。所以下面这个查找函数的返回类型是一个operation_info<student_info>*,也就是学生类对象的模板。我姑且称之为操作类,也就是你看到的operation,这个操作类在这个查找函数中修改了几个地方。

这么说吧,这个操作类里面有个info_flag,默认是false,找到用户后就返回true,这个不难理解,有一个是info_path,默认是nullptr,查找成功后,会保存最后一个查找到的用户的所在记录文件account_xx.csv。假设这个用户是在账户文件2被查到的,那就是info_path = "./data/info/account/account_2.csv"

另外,有个成员变量是T* info_class = new T(),里面装的就是自由类型,也就是传入的student_info类对象并完成了初始化,当然,完成用户查询操作后,如果成功找到,那么这里面装的就是找到的那个学生的用户信息,包括用户名、密码、权限、姓名、学号、班级号、性别。

必须要强调下,这里我认为的班级号跟我们平常讲的班级号不一样,比如我们平常是4班、5班、6班,那只是一个序号,真正的班级号应该是行政班级号,也就是800864这种,或者干脆用学号前缀起,如这个学生的学号是2018070230421,那么他所在班级号是20180702304,学号是21

另外一个地方就是成员变量容器std::vector<T>,这里面装的,也是学生类对象student_info,但不同的是,这里装的是最后一次查找到相同用户名/学号的用户所在的文件下全部的学生类对象信息。

简单地说,上面那个是你要找的用户详细信息,下面那个是那个用户被找到的文件里包括他在内的所有用户详细信息。

当前位置:process_file.cpp

operation_info<student_info>* user_select(const char* uuid, const int mode)
{auto* operation = new operation_info<student_info>; // 新建一个学生类对象的操作类for (const auto& tmp_line : g_vector_file_path_account) // 遍历每一个用户文件{bool flag_select = false; // 查找成功的标志std::string tmp_file = trim(tmp_line);   // 去尾std::fstream f;try{f.open(tmp_file, std::ios::in | std::ios::binary);  // 逐个打开用户文件}catch (std::exception&){print_log("Not found file of accounts", severity_code_error);}if (!f.is_open()){print_log("Can't open an account file when load accounts to verify", severity_code_warning);continue;}std::string tmp_string;  // 行临时内容while (std::getline(f, tmp_string)) // 逐行读取{auto* student = new student_info();// 下面这些都是分割并装入容器char* context = new char[tmp_string.length() + 1];char* next_context;strcpy_s(context, tmp_string.length() + 1, tmp_string.c_str());char* token = strtok_s(context, ",", &next_context);std::vector<const char*> tmp_vector_field;while (token != nullptr){if ('\r' == token[strlen(token) - 1] || '\n' == token[strlen(token) - 1]){token[strlen(token) - 1] = '\0';}tmp_vector_field.emplace_back(token);token = strtok_s(nullptr, ",", &next_context);}switch (mode){case 1:case 2: // 根据传递的参数,判断是要检测用户名还是学号(因为这两个都是唯一标识符,所以具有权威性、独一性)if ((1 == mode && 0 == strcmp(uuid, tmp_vector_field[0])) || (2 == mode && 0 == strcmp(uuid, tmp_vector_field[4]))){try{flag_select = true;    // 找到了对应的用户标志置trueoperation->info_flag = true;  // 同时操作类的flag也置true,上面那个是临时的,这个要传出去的char* tmp_str_line = new char[tmp_file.length() + 1];strcpy_s(tmp_str_line, tmp_file.length() + 1, tmp_file.c_str());// 注意,info_class类型是student_info// 开始装入被找用户详细信息operation->info_class->user_id = const_cast<char*>(tmp_vector_field[0]);operation->info_class->user_password = const_cast<char*>(tmp_vector_field[1]);operation->info_class->user_privilege = strtol(const_cast<char*>(tmp_vector_field[2]), nullptr, 0L);operation->info_class->name = const_cast<char*>(tmp_vector_field[3]);operation->info_class->id = const_cast<char*>(tmp_vector_field[4]);operation->info_class->class_id = const_cast<char*>(tmp_vector_field[5]);operation->info_class->gender = strtol(const_cast<char*>(tmp_vector_field[6]), nullptr, 0L);operation->info_path = tmp_str_line;}catch (...){flag_select = false;operation->info_flag = false;}}break;default:print_log("Error select user param. ", severity_code_error);  // 打印日志,级别为错误级f.close();return operation;}try{// 开始装入找到用户的这个页面其他用户的详细信息student->user_id = const_cast<char*>(tmp_vector_field[0]);student->user_password = const_cast<char*>(tmp_vector_field[1]);student->user_privilege = strtol(const_cast<char*>(tmp_vector_field[2]), nullptr, 0L);student->name = const_cast<char*>(tmp_vector_field[3]);student->id = const_cast<char*>(tmp_vector_field[4]);student->class_id = const_cast<char*>(tmp_vector_field[5]);student->gender = strtol(const_cast<char*>(tmp_vector_field[6]), nullptr, 0L);}catch (std::exception&){print_log("Load information file errors!", severity_code_error);operation->info_flag = false;}operation->info_vector_class.emplace_back(*student);}f.close();if (flag_select){return operation;}operation->info_vector_class.clear();}return operation;   // 返回一个学生类对象的操作类
}

上面那个长吗?来看看这个短一点的,用户信息的存储,是不是很简单。反正传入的是学生类对象的容器,每一条都是一个学生信息记录,那我把这些信息逐行写入用户文件不就完了。

当前位置:process_file.cpp

bool user_store(std::vector<student_info>& vector_account, const char* path)
{std::fstream f;try{f.open(path, std::ios::out | std::ios::trunc | std::ios::binary);if (!f.is_open()){return false;}for (const auto& tmp : vector_account){// 因为是csv文件,所以必须要加逗号分隔,当然也可以不用逗号,但我们用户名总不会出现逗号(好像会),用它没错f << tmp.user_id << ",";f << tmp.user_password << ",";f << tmp.user_privilege << ",";f << tmp.name << ",";f << tmp.id << ",";f << tmp.class_id << ",";f << tmp.gender << "\r\n";}f.close();}catch (const std::exception& e){print_log(e.what(), severity_code_error);return false;}return true;
}

我们回顾下,最开始我们先初始化了配置文件和日志文件,接着,我们输入用户名和密码,调用函数进行匹配,匹配成功root用户后,进入了管理员菜单,菜单打印出来了,其次,我们选了创建用户这一选项,然后输入用户名、密码、权限、姓名等信息,这时候调用用户查找函数,看看是不是存在相同的用户名或者学号,如果没有,开始调用存储函数,将用户信息持久化,打印结果。

我们看看结果:

可以看到,因为我设置的名字宽度比较小,超出的名字长度将不被接受。来看看生成情况,看到最底下两个用户,证明创建用户成功。因为我当时没有把这个放进去,所以它没打印日志出来,懒得重新再演示一遍了,自己试看看就懂了,当然这个还得不断优化调整。


二、删除用户

来看看另一个删除函数,相似的,先给结果(图中是删除1002行的abcdef):

下载工程时优先下载时间最近的,最新的,因为之前的可能有些问题,比如删除时会增加空行,所以,还是保持新的为主。
下面是删除用户操作:
当前位置:manage_admin.cpp

void print_menu_admin_account_delete()
{while (true){CLEAN;// ---------- Start ----------switch (input_judgment(true, true, "Do you want to delete user? (Y/N) ")){case -1:continue;case 0:return;case 1:default:break;}const char* user_id = input(MAXSIZE_INPUT_USER_ID, true, "Please input the User ID to be deleted: ");// ---------- Reconfirm ----------std::cout << "Are you sure you want to delete \"" << user_id << "\"? (Y/N)" << std::endl;switch (input_judgment()){case 0:print_wait("Cancel.");case -1:free_ptr(user_id, true);continue;case 1:default:break;}// ---------- Select ----------auto* operation = user_select(user_id);if (!operation->info_flag){print_wait("Cancel, the user id not exists!");free_ptr(operation);break;}// ---------- Delete ----------operation = user_delete(operation);if (!operation->info_flag){print_log("Failed to delete user.", severity_code_error);print_wait("Failed to delete user.");break;}// ---------- Finish ----------std::cout << "Delete user id: " << user_id << std::endl;print_wait("Delete user account Successfully!");free_ptr(operation);free_ptr(user_id, true);}}

其中,删除函数user_delete()具体为下面这段代码,无非就是把读取到的内容放到容器中增删查改,然后写回文件,仅此而已:
当前位置:process_file.cpp

operation_info<student_info>* user_delete(operation_info<student_info>* operation)
{operation->info_flag = false;std::fstream f;try{f.open(operation->info_path, std::ios::in | std::ios::binary);if (!f.is_open()){return operation;}std::string tmp_string;std::vector<std::string> tmp_vector_line;while (std::getline(f, tmp_string)){char* context = new char[tmp_string.length() + 1];char* next_context;strcpy_s(context, tmp_string.length() + 1, tmp_string.c_str());char* token = strtok_s(context, ",", &next_context);std::vector<const char*> vector_tmp;while (token != nullptr){if ('\r' == token[strlen(token) - 1] || '\n' == token[strlen(token) - 1]){token[strlen(token) - 1] = '\0';}vector_tmp.emplace_back(token);token = strtok_s(nullptr, ",", &next_context);}if (0 != strcmp(operation->info_class->user_id, vector_tmp[0])){tmp_vector_line.emplace_back(tmp_string);}}f.close();f.open(operation->info_path, std::ios::out | std::ios::trunc | std::ios::binary);for (auto tmp : tmp_vector_line){int index = static_cast<int>(tmp.length()) - 1;while ((tmp[index] == '\r' || tmp[index] == '\n') && 0 < index){tmp[index] = '\0';index--;}f << tmp << "\n";}f.close();operation->info_flag = true;}catch (const std::exception& e){print_log(e.what(), severity_code_error);}return operation;
}

至此,增删用户完成,其实这些操作里还包含着查改的操作,所以准确地说应该是增删查改班级信息的增删查改也大同小异,这里不再复述


C++学生信息和考试成绩管理系统(三)相关推荐

  1. C++学生信息和考试成绩管理系统(一)

    C++学生信息和考试成绩管理系统 第一章 工程介绍 第二章 用户登陆准备和登陆 第三章 用户的增删查改 第四章 考试创建&成绩的增改 第五章 成绩查询 第一章 工程介绍 C++学生信息和考试成 ...

  2. c语言按学号查询学生排名极其考试成绩,C语言--学生成绩管理系统

    某班最多有不超过30人(具体人数由键盘输入)参加某门课程的考试.用一维数组作函数参数实现如下学生成绩管理: (1)录入每个学生学号和考试成绩: (2)计算课程的总分和平均分: (3)按成绩由高到低排出 ...

  3. 画图实现考试成绩管理系统

    考试成绩管理系统 1.1需求分析 考试成绩管理系统是举行成人高考.自学考试等成人高校对每个参与考试的学员成绩进行综合管理的一个系统.本系统的功能性需求如下: (1)学员报名参加相应的科目考试,通过考试 ...

  4. 教育部拟规定:中小学不得公开学生个人的考试成绩名次

    4月6日,教育部发布公告,就<未成年人学校保护规定(征求意见稿)>面向社会公开征求意见. 征求意见稿介绍,学校应当尊重和保护学生的人格尊严,尊重学生名誉,培育学生的荣誉感.责任感.学校应当 ...

  5. IO流(1)-键盘录入学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低存入文本文件...

    1.先写一个Student类 public class Student {private String name;private int chinese;private int math;privat ...

  6. Python习题解答:将学生的各科考试成绩保存为csv文件格式

    习题解答:将学生的各科考试成绩保存为csv文件格式 1.题目要求 将学生的各科考试成绩保存为csv文件格式. 2.设计要求 (1)已知学生的学号和各科成绩: data = [['99100', 90, ...

  7. 可执行源码:基于javaweb实现学生成绩管理系统,三种角色学生和教师 管理员,实现了学生信息管理,课程管理,教师信息管理,学生成绩汇总,学生登录注册,教师和管理员的登录,个人信息修改等

    基于javaweb实现学生成绩管理系统,实现了学生信息管理,课程管理,教师信息管理,学生成绩汇总,学生登录注册,教师和管理员的登录,个人信息修改等. 系统功能大致描述:基于javaweb实现学生成绩管 ...

  8. 学生成绩管理系统(三)

    这个程序,越改,越觉得有问题,就将就着改改吧. 3.4 添加学生模块 先看一下界面,主界面没有修改完,修改完之后在贴代码: 图1 添加学生界面 package org.ygy.view;import ...

  9. 定义一个学生结构体并打印出学生信息(平均成绩、最高分)

    /*定义一个Student结构体*/ typedef struct Student {int num; //学号char name[10]; //姓名float score[3];//三门课成绩 }; ...

最新文章

  1. matlab中卡尔曼滤波,卡尔曼滤波器和matlab代码.doc
  2. 【CentOS 7MySQL常用操作2】,连接MySQL#180112
  3. mysql运行报错64bit_关于MySQL5.6.25在Win7 64bit下重装后无法启动的解决方法
  4. exists用法_SQL中的ALL、ANY和SOME的用法介绍
  5. CKEditor4.4.5 插入高度代码及上传图片
  6. *args 和**kwargs 的理解以及 函数的参数的总结
  7. 数据库课设(足球联赛管理系统)
  8. Acwing 1085. 不要62
  9. 2021年中国机器人行业研究报告
  10. 推荐几个rpm下载站点
  11. 文本文档怎样改格式为html格式,文本文档格式怎么更改【图解】
  12. java视频播放器vlcj_vlcj--java-制作视频播放器
  13. RFID(射频识别)详解(带图)
  14. 用放大镜看计算机屏幕,使用放大镜可使屏幕上的内容更易于查看
  15. Repeated DNA Sequences
  16. 【b站雅思笔记】Charlie有好好学习 - 雅思机经8-14
  17. C盘容量不足,怎么增加c盘空间?看这5个方法
  18. 计算机账户注销重新登录,win10系统注销账户切换账号登录的方法
  19. 通过微博名查看id html,微博id在哪里查看?
  20. cpu可以直接识别并执行的计算机语言是,计算机硬件能够直接识别的指令是什么...

热门文章

  1. 【转】UIAutomation
  2. C语言 递归函数实现二分查找
  3. 关键词词库制作-搜索词分析工具
  4. 什么样的大学女生值得娶回家
  5. 解决会声会影X4无法插入AVI视频文件!
  6. Python2 long() 函数
  7. 9012年了你还在用单色图标?(iconfont多色图标详解)
  8. 《惊鸿一瞥》 陈伟鸿
  9. [unity] async-awit的函数,怎么才能关闭这个函数呢,现在来解析
  10. python pdb调试_使用Pdb进行Python调试