C++大作业二次开发
来源
此程序是一位同学bkali 的大一下期末大作业。项目名称为《学校计算机机房管理系统》,采用C++编写。
运行环境与结果
运行环境
Visual Studio 2022
运行结果
主函数代码
int main()
{
// 设置通过标记为-1 会进入登陆界面
int pass = -1;//这里1方便调试
while (true)
{
switch (pass)
{
case -1:
pass = loginmenu(pass);
break;
case 0:
return 0;
// 当管理员登陆通过->pass=1 以管理员身份进入系统
case 1:
pass = menu(pass);
break;
}
system("cls");
}
return 0;
}
教室创建相关的代码
/*初始化教室*/
void Initialize_Classroom(CLASSROOM a)
{
ofstream CLASSROOM("data/" + a.get_id() + ".txt");
CLASSROOM << a;
ofstream CLASSROOMID("data/classroomid.txt", ios::app);
CLASSROOMID << a.get_id() << endl;
}
主要问题与改进方式
输入校验
问题现象
我在使用的过程发现,该程序并没有设置输入校验。以用户的视角来看,对于错误的输入是很常见的现象,比如需要输入一个int类型的数字,却多打了一个a这样的字符类型。然而该系统并没有对此类错误信息做出相应的判断,因此在系统读取到错误的信息后往往会导致程序运行出错,进而反馈到用户的使用上来说就是系统的崩溃。
(在开始菜单的选项中输入‘a’后 程序直接崩溃退出)
改进方式
对于此类问题,则需要在程序读取到用户的输入后,对输入的数据进行进一步的判断,如果数据类型是符合的,则可以正常读取并继续运行;数据不符合的话就不能读取,以防止程序崩溃。在此应该清除读取到的数据并清理缓存,并提示出错的信息。
改进后的代码
bool Isdigit(int c)
{
if (cin.rdstate()) {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
return false;
}
return true;
}
测试截图
资源释放
问题现象
程序有个功能可以查询相应教室的排课信息,在查询前需要先选择教室。但是在我第二次使用程序时,我发现我不需要选择教室就能够直接看到教室信息,此时显示的是上一次运行所选择的教室。
改进方式
在仔细研究代码后,发现程序在执行选择教室时会创建一个临时文件来储存选择的教室,但是在运行结束后并没有对此文件进行删除、释放资源。因此我通过atexit()函数来注册程序正常终止时要被调用的函数,即对资源进行释放。在函数中先判断临时文件是否存在来选择是否删除相应的文件。
改进后的代码
#include "menu.h"
#include <cstdio>
using namespace std;
void my_release() {
const char* file_path = "data/classroomtmp.txt"; // 指定文件路径
ifstream f(file_path);
if (f.good()) { //判断文件是否存在
f.close();
if (remove(file_path) != 0) { // 尝试删除文件
cout << "Failed to delete file." << endl;
}
else {
cout << "File deleted successfully." << endl;
}
}
else {
cout << "File Not Find" << endl;
}
}
int main()
{
//注册程序结束所调用的函数
atexit(my_release);
// 设置通过标记为-1 会进入登陆界面
int pass = -1;//这里1方便调试
while (true)
{
switch (pass)
{
case -1:
pass = loginmenu(pass);
break;
case 0:
return 0;
// 当管理员登陆通过->pass=1 以管理员身份进入系统
case 1:
pass = menu(pass);
break;
}
system("cls");
}
return 0;
}
测试截图
总结
在我对该程序进行逆向开发的过程中,最耗时间的是对于程序的解构和分析,理解每个功能函数以及其中涉及的相互关系。需要对每个代码块进行解读,理解其原理,这样在后续发现问题时才能及时找到问题出错的原因和对应的功能代码。其次就是对于代码的修改,尤其是高耦合度的代码,修改其中的一小部分往往便会造成大范围的变动,这显然不是我想要的。因此我采用“打补丁”的方式,对于用户输入问题,我并没有修改读取的类型,而是进行输入校验,以保证在原程序正常运行的情况下修改相应的bug。