C++学生信息和考试成绩管理系统
叨扰
终于到了最后一章,开心得一批,在这一章主要讲的是成绩查询。
在本工程中,我写了一种查询方式,两种显示方法,第一种是直接罗列结果,就是大片大片的打印成绩,第二种依托了Windows提供的_getch()
,从而采用翻页的方法。在管理员界面我选的是第一种,而在标准用户界面和只读用户界面我选的是第二种。
好了,先看看第一种是什么样。先随机生成一大堆数据。如下图,左两个文件为考试记录,右一为账户记录。
来看看第一种查询,因为管理员没有直接查询的功能(是懒了),我直接展示更新成绩后的结果吧。
我们更改的时间范围是这样大:
这时候大概要等二十秒,控制台输出太慢了……
找到了,下面这个是2024年11月31日10点30分
的考试(不要在意细节,闰年、一月大二月小这些什么的,我只考虑了在一到十二月、一到三十一号):
因为这个考试的科目名也是随机生成的,所以我们也选一个看看。
注意这个考试的基本情况:
更改成绩后:
可以看到,成绩修改成功,相应的值也已经重新修改。不过你肯定发现排名没变,没错,因为我还没写排名更新的函数,不过要实现起来也不难,因为这些成绩其实都是装进了容器里的,你再根据个人平均分重新排名,写回文件道理是一样的,只不过多了个步骤而已。
再来看第二种,需要登陆普通用户。
就是这样,翻页的。
总的来说,这个工程只是提供了一个框架,具体实现来来回回就是那几样东西,从文件读出到容器,修改容器值,写回文件,修改相应的配置文件内容。
一、第一种显示方式
注意这个代码是类对象里边的成员函数。
当前位置:exam_info.cpp
void exam_info::print_exam()
{
std::cout << "========== ========== ========== ========== ========== ========== ========== ==========" << std::endl;
std::cout << "********** ********** ********** ********** ********** ********** ********** **********" << std::endl;
std::cout << "|";
std::cout.width(12);
std::cout << "Exam D & T" << "|";
std::cout.width(MAXSIZE_INPUT_USER_ID);
std::cout << "Admin" << "|";
std::cout.width(DEFAULT_PRINT_WIDTH);
std::cout << "Student" << "|";
std::cout.width(DEFAULT_PRINT_WIDTH);
std::cout << "Average" << "|";
std::cout.width(DEFAULT_PRINT_WIDTH);
std::cout << "Majors" << "|";
std::cout << "\n";
std::cout << "--------------------------------------------------------------------------------" << std::endl;
std::cout << "|";
if (nullptr != date_time)
{
std::cout.width(12);
std::cout << date_time << "|";
}
if (nullptr != admin)
{
std::cout.width(MAXSIZE_INPUT_USER_ID);
std::cout << admin << "|";
}
std::cout.width(DEFAULT_PRINT_WIDTH);
std::cout << count_student << "|";
std::cout.width(DEFAULT_PRINT_WIDTH);
std::cout << setiosflags(std::ios::fixed) << std::setprecision(1) << average_score << "|";
std::cout.width(DEFAULT_PRINT_WIDTH);
std::cout << count_subject << "|";
std::cout << "\n";
std::cout << "********** ********** ********** ********** ********** ********** ********** **********" << std::endl;
std::cout << "|";
if (!vector_subject_serial_number.empty())
{
for (auto* tmp : vector_subject_serial_number)
{
std::cout.width(DEFAULT_PRINT_WIDTH);
std::cout << tmp << "|";
}
}
std::cout << "\n";
std::cout << "--------------------------------------------------------------------------------" << std::endl;
std::cout << "|";
if (!vector_subject_average_score.empty())
{
for (auto tmp : vector_subject_average_score)
{
std::cout.width(DEFAULT_PRINT_WIDTH);
std::cout << setiosflags(std::ios::fixed) << std::setprecision(1) << tmp << "|";
}
}
std::cout << "\n";
std::cout << "********** ********** ********** ********** ********** ********** ********** **********" << std::endl;
std::cout << "|";
std::cout.width(4);
std::cout << "R&K" << "|";
std::cout.width(MAXSIZE_STUDENT_NAME * 2);
std::cout << "Name" << "|";
std::cout.width(MAXSIZE_CLASS_ID);
std::cout << "Class" << "|";
std::cout.width(MAXSIZE_STUDENT_ID);
std::cout << "ID" << "|";
std::cout.width(DEFAULT_PRINT_WIDTH);
std::cout << "Score" << "|";
for (int i = 0; i < count_subject; i++)
{
std::cout.width(DEFAULT_PRINT_WIDTH);
std::cout << vector_subject_serial_number[i] << "|";
}
printf_s("\n");
std::cout << "--------------------------------------------------------------------------------" << std::endl;
if (!vector_student_exam_record.empty())
{
for (auto* tmp : vector_student_exam_record)
{
tmp->print_record();
}
}
std::cout << "********** ********** ********** ********** ********** ********** ********** **********" << std::endl;
std::cout << "========== ========== ========== ========== ========== ========== ========== ==========\n" << std::endl;
}
二、第二种显示方式
这是只读用户的查询成绩:
当前位置:manage_read.cpp
void print_menu_read_statistics_examination(menu& menus)
{
auto* exam_all = exam_select(g_vector_login_info[4]);
double average_rankings = 0;
double average_scores = 0.0;
if (exam_all->info_flag)
{
for (auto* tmp_exam : exam_all->info_vector_class)
{
for (auto* tmp_student : tmp_exam->vector_student_exam_record)
{
if (0 == strcmp(tmp_student->student_id, g_vector_login_info[4]))
{
average_rankings += tmp_student->rankings;
average_scores += tmp_student->score_average;
}
}
}
if (!exam_all->info_vector_class.empty())
{
average_rankings /= exam_all->info_vector_class.size();
average_scores /= exam_all->info_vector_class.size();
}
}
free_ptr(exam_all);
while (true)
{
CLEAN;
std::cout << "ID: " << g_vector_login_info[4] << std::endl;
std::cout << "Name: " << g_vector_login_info[3] << std::endl;
std::cout << "Rankings: " << average_rankings << std::endl;
std::cout << "Scores: " << average_scores << std::endl;
char* datetime_start = nullptr;
char* datetime_end = nullptr;
print_menu(false, 1, menus.vector_read_exam_statistics, "Please select an option: ");
switch (input_option(static_cast<int>(menus.vector_read_exam_statistics.size())))
{
case 0:
return;
case 1:
break;
case 2:
if (1 == input_judgment(true, true, "Do you want to set range of start datetime? (Y/N): "))
{
datetime_start = input_datetime();
}
if (1 == input_judgment(true, true, "Do you want to set range of end datetime? (Y/N): "))
{
datetime_end = input_datetime();
}
break;
default:
break;
}
auto* exam_record = exam_select(g_vector_login_info[4], datetime_start, datetime_end);
if (exam_record->info_vector_class.empty())
{
print_wait("Not found any exam record.");
continue;
}
double range_average_rankings = 0.0;
double range_average_scores = 0.0;
for (auto* tmp_exam : exam_record->info_vector_class)
{
for (auto* tmp_student : tmp_exam->vector_student_exam_record)
{
if (0 == strcmp(tmp_student->student_id, g_vector_login_info[4]))
{
range_average_rankings += tmp_student->rankings;
range_average_scores += tmp_student->score_average;
}
}
}
if (!exam_record->info_vector_class.empty())
{
range_average_rankings /= exam_record->info_vector_class.size();
range_average_scores /= exam_record->info_vector_class.size();
}
int index_exam = 0;
bool flag_viewing = true;
while (flag_viewing)
{
CLEAN;
std::cout << "ID: " << g_vector_login_info[4] << std::endl;
std::cout << "Name: " << g_vector_login_info[3] << std::endl;
std::cout << "Range Rankings: " << range_average_rankings << std::endl;
std::cout << "Range Scores: " << range_average_scores << std::endl;
printf_s("\n");
exam_record->info_vector_class[index_exam]->print_exam();
std::cout << "Please press <- or -> to turn page, and press ESC to exit." << std::endl;
int show = _getch();
if (224 == show || 0 == show)
{
show = _getch();
}
switch (show)
{
case 27:
flag_viewing = false;
break;
case 75:
if (0 < index_exam)
{
index_exam--;
}
break;
case 77:
if (index_exam < static_cast<int>(exam_record->info_vector_class.size()) - 1)
{
index_exam++;
}
break;
default:
break;
}
}
}
}
后记
这么潦草的工程居然有后记,只能说明这个作者不是一般闲。
这个工程说到底只是给写课设(课程设计)和毕设(毕业设计)的人提供一个基本框架,为什么这么复杂,本来代码不多的,但要考虑程序的健壮性就不得不多下点功夫来把输入和输出这个基本功写好(你看工程里有多少是std::cin
的,自信点,没有),为啥,因为怕啊,这东西也不只是写给你看,我自己也要参考(从开始写的时候,讲真我还不知道std::vector
是啥),va_list
这东西压根没见过(其实就在printf()
里),所以我最开始的习惯是用C来写工程,写着写着想用std::cin
了,后来发现好像有点问题,就又换成了另一种感觉相对安全的写法,就是input()
(但我还是不建议用va_list
),再后来写结构体太麻烦了,不得不看了菜鸟教程简单学了下模板
和类对象
,当然,到现在还没学好。所以啊,我尽量把这些东西写成模块化,就像零件一样拼起来一个工程,最后如果我想用的时候随手一用就好了。
还有就是这个工程环境一定要配对,以前我写C,都是关了那个提示来写的,也就是安全性写法。这次写工程,就觉得不行,以前还是VC++6.0
,学不来学不来,所以你会看到很多_s
,包括strcpy_s
之类的。
刚刚忘说了,为什么不会类对象,明明先学了Java、Python,我只能说,手工造出来的轮子不一定和自动化造出来的轮子一样,尽管它们都是轮子。我本身并没有学过一门C++课程。
工程多有不足,希望大佬多提意见,学习的同僚拿去用就好了。最后再放一遍工程地址:C-plus-plus-Student-Examination-Manage-System
下一步,嵌入式……
END