C++学生信息和考试成绩管理系统
第一章 工程介绍
前言
理论上,这篇文章会很长,因为代码相对课程设计来讲是有点多,值得注意的是,这个工程有个很严重的BUG——内存泄漏,当然也是自我感觉,为什么呢,因为我写的时候很多时候是从一个函数进入另一个函数,出来的时候就容易忘记了释放,所以如果你只是写个毕设、课设什么的参考下就好了,不要太当真。还有就是因为没用多线程,处理数据杠杠的,慢。一千个学生数据处理大概要5s这样。
为什么不用智能指针?那就顺带说一下,刚开始我的想法是直接用C来写,嗯,是的没错是用C,但写着写着发现不对劲,好多东西很不方便,比如类对象
,我用结构体指针来搞,可搞着搞着越来越麻烦,后来索性换成了类对象或者模板,类似的还有很多,比如std::vector
,也比如有时候用char* str
有时候是std::string
。所以也可以看到绝大多数时候我会保留C的写法,尽可能使用char* str
,为什么,因为喜欢。
C++代码我已经放在Github上,Python代码也在里面(这个代码是用来批量生成数据的),但我觉得写得还不好,有点随意,不过勉强能用,传送门:C-plus-plus-Student-Examination-Manage-System,当然我也可能上传到优快云,这个不确定,因为就像我这种人也很穷,没有C币的,有时候想要下个资源就很麻烦(DdDd)。当然,最简单的,把这文章里所有代码收集起来也会得到近乎完整工程。另外,如果觉得这篇文章合适你就看,不然就是浪费时间。
版权说明:
C++工程为原创内容,大可使用在毕设、课设等方面,不用标注来源,每个模块可以拆分使用,就当成是自己的代码就行。但转载文章这种,还是标注来源比较好。
Python工程为原创内容,名字资源来源于网上,具体已经标注,除了资源,其他的如代码这种的用途同上。转载请标明来源,其他用途任意。
一、实验结果/功能
为啥一上来就是实验结果?因为,万一你想要的功能和我写的不一样那你不就白打开网页了么,所以先比较下,功能适不适合你,适合就下滑,不适合就Ctrl + W。
功能对应三种用户,管理员用户,懂的都懂;标准用户,就当老师账户吧,也不一定,反正是有部分管理权限的;只读用户,就当学生用户吧。其实这些功能可以随意组合,我也没啥需求,所以就靠感觉来写了,相对费时的是管理员功能,因为写的过程中需要封装各种函数,封装完了,另外两个用户也很好写了。
(一)功能
管理员功能
- 创建用户
- 删除用户
- 创建班级
- 删除班级
- 创建考试
- 更改成绩
标准用户功能
- 更改学号
- 更改班级
- 查看成绩
- 更改成绩
只读用户功能
- 更改用户名
- 更改密码
- 统计考试情况
(二)结果
如果你觉得看了上面的内容并且觉得很适合,那就继续往下滑。
二、工程环境
系统环境:Windows 10 1909
开发软件:Microsoft Visual Studio Professional 2019 v16.6.0
编译器要求:MSVC且支持C++11
其他:工程用到Windows库,原工程无法跨平台。
三、工程树
如下图,主函数是入口,主要分为三大类,模板对象类、输入输出类、内容处理类,分别对应Info、IO、Manage,还有一个Template归为模板对象类,共三大类。
下面具体来说一下这些文件有什么用吧,自上而下。
class_info.h
班级信息类对象,包含行政班级号、管理员、年级、专业、班级。(其实没怎么用)
exam_info.h
考试类对象,包含考试日期、创建者、考生人数、考试科目、平均分、考生成绩记录等。
exam_record.h
考生成绩类对象,包含考生排名、考生姓名、考生班级、考生学号、考生均分、每科分数。
menu.h
用户界面菜单内容,全在这里头了,就是那些你能在屏幕上直接看到的菜单。
student_info.h
学生类对象,包含用户名、密码、权限、学生名、学号、班级号、性别。
format_input.h
封装了与输入相关的东西,包括日期输入、选项输入、选择输入、内容输入等。
format_print.h
封装了与输出相关的东西,包括菜单输出、休眠输出、等待输出。
process_file.h
和文件最近距离的封装,封装了一大堆与文件操作相关处理的函数。
manage_admin.h
管理员的界面,负责前端(输出屏幕)和后端(菜单读取、交互处理)内容的交互。
manage_read.h
只读用户的界面,负责前端(输出屏幕)和后端(菜单读取、交互处理)内容的交互。
manage_standard.h
标准用户的界面,负责前端(输出屏幕)和后端(菜单读取、交互处理)内容的交互。
template_free_pointer.h
模板类,销毁任意类型指针、对象(前提如果能销毁的话)。
template_operation_info.h
模板类,封装了标志、字符串地址、数值、容器、对象。传递类对象基本靠它。
main.h
主函数,登陆验证处理,还有一个判断字符串是否为数字类型(不怎么用,其实可以用正则表达式)。
喏,就是这样子,整个过程就是入口读取配置文件,然后再验证用户,调用输入函数将得到的内容拿去遍历文件,匹配后进入用户界面,读取菜单类内容并通过输出菜单函数展示到屏幕,根据输入内容查找或修改内容,最后写回文件,将结果显示在屏幕上并等待用户下一步输入。
四、代码讲解
以登陆管理员用户为例,按操作顺序进行代码说明。因为太多了,放上来太碍眼,如果你自信能看懂的话,也可以跳到最后,直接复制代码。
C++的代码都在后续文章中,这里放的是Python工程,创建适合本工程的伪数据。为什么要大批量创造这些呢,当然是为了方便调试,你总不会想着要把成绩和姓名一个个想好,然后输入进去吧!
(一)主函数:main.py
# -*- coding:utf-8 -*-
# ===============================================
# @Author HDM
# @Copyright HDM
# @blogs https://blog.youkuaiyun.com/qq_43634664
# @Version 0.0.1
# @Time 2021/2/9 14:26
# @FileName main.py
# @Description None
# ===============================================
from generate_user_info import generate_user
from generate_exam import generate_exam
K_PATH_FOLDER_DATA = r"C:/Users/THDMI/source/repos/sks853/C-plus-plus-Student-Examination-Manage-System/NoUi_Student_Manage_System/data"
k_PATH_FOLDER_CONFIG = K_PATH_FOLDER_DATA + r"/config"
K_PATH_FOLDER_INFO_ACCOUNT = K_PATH_FOLDER_DATA + r"/info/account"
K_PATH_FOLDER_INFO_CLASS = K_PATH_FOLDER_DATA + r"/info/class"
K_PATH_FOLDER_INFO_RECORD = K_PATH_FOLDER_DATA + r"/record"
K_PATH_FILE_PROPERTIES = k_PATH_FOLDER_CONFIG + r"/init.ini"
K_PATH_FILE_LOG = k_PATH_FOLDER_CONFIG + r"/log.log"
g_ls_path_file_account = []
g_ls_path_file_class = []
g_ls_path_file_record = []
def init_properties():
with open(K_PATH_FILE_PROPERTIES, "r+", encoding='GB2312') as f:
ls_properties = []
flag_properties = 0
for line in f:
ls = line.split()
for ele in ls:
ls_properties.append(ele.replace(r"./data", K_PATH_FOLDER_DATA))
for ele in ls_properties:
if "[account]" == ele:
flag_properties = 1
continue
if "[class]" == ele:
flag_properties = 2
continue
if "[record]" == ele:
flag_properties = 3
continue
if 1 == flag_properties:
g_ls_path_file_account.append(ele)
elif 2 == flag_properties:
g_ls_path_file_class.append(ele)
elif 3 == flag_properties:
g_ls_path_file_record.append(ele)
def append_account():
global g_ls_path_file_account
global g_ls_path_file_class
global g_ls_path_file_record
for index in range(len(g_ls_path_file_account)):
g_ls_path_file_account[index] = g_ls_path_file_account[index].replace(K_PATH_FOLDER_DATA, r"./data")
for index in range(len(g_ls_path_file_class)):
g_ls_path_file_class[index] = g_ls_path_file_class[index].replace(K_PATH_FOLDER_DATA, r"./data")
for index in range(len(g_ls_path_file_record)):
g_ls_path_file_record[index] = g_ls_path_file_record[index].replace(K_PATH_FOLDER_DATA, r"./data")
with open(K_PATH_FILE_PROPERTIES, "w+", encoding="gb2312", newline='') as f:
f.write("[account]\n")
for ele_account in g_ls_path_file_account:
f.write(ele_account + "\n")
f.write("[class]\n")
for ele_class in g_ls_path_file_class:
f.write(ele_class + "\n")
f.write("[record]\n")
for ele_record in g_ls_path_file_record:
f.write(ele_record + "\n")
if __name__ == '__main__':
""" main """
init_properties()
user_info = generate_user(K_PATH_FOLDER_INFO_ACCOUNT + r"/account_1.csv")
exam = generate_exam(K_PATH_FOLDER_INFO_RECORD, user_info.generate_account())
exam.store_exam()
for element in exam.path:
g_ls_path_file_record.append(element)
append_account()
(二)根据性别批量生成姓名:generate_chinese_names.py
# -*- coding:utf-8 -*-
# ===============================================
# @Author HDM
# @Copyright HDM
# @blogs https://blog.youkuaiyun.com/qq_43634664
# @Version 0.0.1
# @Time 2021/2/9 12:47
# @FileName generate_chinese_names.py
# @Description 资源参考博客:https://www.jianshu.com/p/94be1c4ebf82 和 https://www.jianshu.com/p/d23e3ac18481
# ===============================================
import random
name = "陈,林,黄,张,李,王,吴,刘,蔡,杨,许,郑,谢,洪,郭,邱,曾,廖,赖,徐,周,叶,苏,庄,吕,江,何,萧,罗,高,周,叶,苏,庄,吕,江,何,萧,罗," \
"高,潘,简,朱,彭,游,詹,胡,施,沈,余,卢,梁,赵,颜,柯,翁,魏,孙,戴,范,方,宋,邓,杜,傅,侯,曹,薛,丁,卓,马,阮,董,唐,温,蓝,蒋," \
"石,古,纪,姚,连,冯,欧,程,汤,田,康,姜,汪,白,邹,尤,巫,钟,黎,涂,龚,严,韩,袁,金,童,陆,夏,柳,邵,"
male = "辰,士,以,建,家,致,树,炎,德,行,时,泰,盛,雄,琛,钧,冠,策,铭,腾,伟,刚,勇,毅,俊,峰,强,军,平,保,东,文,辉,力,明,永,健,世,广," \
"志,义,兴,良,海,山,仁,波,宁,贵,福,生,龙,元,全,国,胜,学,祥,才,发,成,康,星,光,天,达,安,岩,中,茂,武,新,利,清,飞,彬,富,顺," \
"信,子,杰,楠,榕,风,航,弘,鼎"
female = "嘉,琼,桂,娣,叶,璧,璐,娅,琦,晶,妍,茜,秋,珊,莎,锦,黛,青,倩,婷,姣,婉,娴,瑾,颖,露,瑶,怡,婵,雁,蓓,纨,仪,荷,丹,蓉,眉,君," \
"琴,蕊,薇,菁,梦,岚,苑,婕,馨,瑗,琰,韵,融,园,艺,咏,卿,聪,澜,纯,毓,悦,昭,冰,爽,琬,茗,羽,希,宁,欣,飘,育,滢,馥,筠,柔,竹," \
"霭,凝,晓,欢,霄,枫,芸,菲,寒,伊,亚,宜,可,姬,舒,影,荔,枝,思,丽,秀,娟,英,华,慧,巧,美,娜,静,淑,惠,珠,翠,雅,芝,玉,萍,红," \
"娥,玲,芬,芳,燕,彩,春,菊,勤,珍,贞,莉,兰,凤,洁,梅,琳,素,云,莲,真,环,雪,荣,爱,妹,霞,香,月,莺,媛,艳,瑞,凡,佳"
ls_name_last = [
'赵', '钱', '孙', '李', '周', '吴', '郑', '王', '冯', '陈', '褚', '卫', '蒋', '沈', '韩', '杨', '朱', '秦', '尤', '许',
'何', '吕', '施', '张', '孔', '曹', '严', '华', '金', '魏', '陶', '姜', '戚', '谢', '邹', '喻', '柏', '水', '窦', '章',
'云', '苏', '潘', '葛', '奚', '范', '彭', '郎', '鲁', '韦', '昌', '马', '苗', '凤', '花', '方', '俞', '任', '袁', '柳',
'酆', '鲍', '史', '唐', '费', '廉', '岑', '薛', '雷', '贺', '倪', '汤', '滕', '殷', '罗', '毕', '郝', '邬', '安', '常',
'乐', '于', '时', '傅', '皮', '卞', '齐', '康', '伍', '余', '元', '卜', '顾', '孟', '平', '黄', '和', '穆', '萧', '尹',
'姚', '邵', '堪', '汪', '祁', '毛', '禹', '狄', '米', '贝', '明', '臧', '计', '伏', '成', '戴', '谈', '宋', '茅', '庞',
'熊', '纪', '舒', '屈', '项', '祝', '董', '梁'
]
ls_name_first_male = male.split(',')
ls_name_first_female = female.split(',')
def generate_name(gender):
name_length = random.choice((2, 3))
if gender == 0:
if name_length == 2:
return random.choice(ls_name_last) + random.choice(ls_name_first_female)
if name_length == 3:
return random.choice(ls_name_last) + random.choice(ls_name_first_female) + \
random.choice(ls_name_first_female)
if gender == 1:
if name_length == 2:
return random.choice(ls_name_last) + random.choice(ls_name_first_male)
if name_length == 3:
return random.choice(ls_name_last) + random.choice(ls_name_first_male) + \
random.choice(ls_name_first_male)
return None
(三)批量生成ID相关信息:generate_id.py
# -*- coding:utf-8 -*-
# ===============================================
# @Author HDM
# @Copyright HDM
# @blogs https://blog.youkuaiyun.com/qq_43634664
# @Version 0.0.1
# @Time 2021/2/9 14:03
# @FileName generate_id.py
# @Description None
# ===============================================
import string
import random
def generate_uuid(length):
uuid = ""
for i in range(length):
uuid += random.choice(string.ascii_letters + string.digits)
return uuid
def generate_class_id(length):
class_id = ""
for i in range(length):
class_id += random.choice(string.digits)
return class_id
def generate_student_id(class_id):
student_id = ""
student_id += str(random.randint(2018, 2024))
academy = random.randint(1, 12)
if academy < 10:
student_id += '0' + str(academy)
else:
student_id += str(academy)
major = random.randint(1, 125)
if major < 10:
student_id += '00' + str(major)
elif major < 100:
student_id += '0' + str(major)
else:
student_id += str(major)
student_id += class_id[-2:]
last_id = random.randint(1, 75)
if last_id < 10:
student_id += '0' + str(last_id)
else:
student_id += str(last_id)
return student_id
(四)批量生成用户信息:generate_user_info.py
# -*- coding:utf-8 -*-
# ===============================================
# @Author HDM
# @Copyright HDM
# @blogs https://blog.youkuaiyun.com/qq_43634664
# @Version 0.0.1
# @Time 2021/2/9 14:26
# @FileName generate_user_info.py
# @Description None
# ===============================================
import csv
import random
from generate_chinese_names import generate_name
from generate_id import generate_uuid
from generate_id import generate_student_id
from generate_id import generate_class_id
class generate_user:
def __init__(self, path):
self.path = path
def generate_account(self):
ls = []
tmp_ls = []
for i in range(1000):
user_name = generate_uuid(4)
user_password = generate_uuid(6)
privilege = random.choice(('1', '2'))
student_gender = random.choice(('0', '1'))
student_name = generate_name(gender=eval(student_gender))
student_class = generate_class_id(6)
student_id = generate_student_id(student_class)
tmp_ls.append(
(user_name, user_password, privilege, student_name, student_id, student_class, student_gender))
tmp_ls_name = []
tmp_ls_id = []
count = 0
for ele in tmp_ls:
if not ele[0] in tmp_ls_name and not ele[4] in tmp_ls_id:
count += 1
ls.append(ele)
tmp_ls_name.append(ele[0])
tmp_ls_id.append(ele[4])
ls = sorted(ls, key=lambda x: x[4])
for i in ls:
print(i)
print("成功生成数据个数:", count)
try:
with open(self.path, "w", encoding='GB2312', newline='') as f:
writer = csv.writer(f, delimiter=",")
for i in ls:
writer.writerow(i)
except Exception as e:
print(e)
return ls
(五)批量生成考试记录:generate_exam.py
# -*- coding:utf-8 -*-
# ===============================================
# @Author HDM
# @Copyright HDM
# @blogs https://blog.youkuaiyun.com/qq_43634664
# @Version 0.0.1
# @Time 2021/2/9 15:41
# @FileName generate_exam.py
# @Description None
# ===============================================
import csv
import string
import random
AMOUNT_EXAM = 20
class generate_exam:
def __init__(self, folder_path, student_info):
self.folder_path = folder_path
self.student_info = student_info
self.datetime = ""
self.admin = "root"
self.count_student = len(student_info)
self.count_major = random.randint(2, 10)
self.average = 0.0
self.major = []
self.major_score = []
self.ls_record = []
self.path = []
def store_exam(self):
for index in range(AMOUNT_EXAM):
self.create_exam()
file_path = self.folder_path + r"/exam_" + str(index) + r".csv"
base = (self.datetime, self.admin, self.count_student, self.average, self.count_major)
ls = [base, self.major, self.major_score]
for ele in self.ls_record:
ls.append(ele)
with open(file_path, "w", encoding="gb2312", newline='') as f:
writer = csv.writer(f, delimiter=",")
for i in ls:
writer.writerow(i)
self.path.append(file_path)
self.clean_exam()
def clean_exam(self):
self.datetime = ""
self.count_major = random.randint(2, 10)
self.average = 0.0
self.major.clear()
self.major_score.clear()
self.ls_record.clear()
def create_exam(self):
self.create_exam_datetime()
self.create_exam_major_serial_num()
self.create_exam_student_record()
self.statistics_exam()
def print_exam(self):
base = [self.datetime, self.admin, self.count_student, self.average, self.count_major]
print(base)
print(self.major)
print(self.major_score)
for ele in self.ls_record:
print(ele)
def statistics_exam(self):
self.average = round(self.average / self.count_student, 1)
for index in range(self.count_major):
self.major_score[index] = round(self.major_score[index] / self.count_student, 1)
def create_exam_student_record(self):
for i in range(self.count_student):
rank = 0
student_name = self.student_info[i][3]
student_class = self.student_info[i][5]
student_id = self.student_info[i][4]
student_score_major = []
for index in range(self.count_major):
major_score = round(random.uniform(45, 95), 1)
student_score_major.append(major_score)
if 0 == i:
self.major_score.append(major_score)
else:
self.major_score[index] += major_score
student_score_average = round(sum(student_score_major) / self.count_major, 1)
self.average += student_score_average
student = [rank, student_name, student_class, student_id, student_score_average]
for element in student_score_major:
student.append(element)
self.ls_record.append(student)
self.ls_record = sorted(self.ls_record, key=lambda x: x[4], reverse=True)
for index in range(self.count_student):
self.ls_record[index][0] = index + 1
def create_exam_major_serial_num(self):
for i in range(self.count_major):
major = ""
for index in range(5):
major += random.choice(string.ascii_letters + string.digits)
self.major.append(major)
def create_exam_datetime(self):
datetime = ""
datetime += str(random.randint(2018, 2024))
month = random.randint(1, 12)
if month < 10:
datetime += '0' + str(month)
else:
datetime += str(month)
day = random.randint(1, 31)
if month < 10:
datetime += "0" + str(day)
else:
datetime += str(day)
hour = random.randint(1, 23)
if hour < 10:
datetime += "0" + str(hour)
else:
datetime += str(hour)
minute = random.randint(1, 59)
if minute < 10:
datetime += "0" + str(minute)
else:
datetime += str(minute)
self.datetime = datetime
(六)生成结果
这些代码有点懒得说了,懂的都懂,用途就是创造适合本工程的大批数据,不多,也就1000个学生、20个考试记录。