当前位置: 首页 > news >正文

“软件开发与创新课程设计”实验1

上海海洋大学 软件开发与创新课程设计 实验1 - 个人信息管理系统逆软件工程分析

本次随笔针对上海海洋大学信息学院“软件开发与创新课程设计”实验1展开,核心是对同院学号2452826同学的C++项目《基于C++的个人信息管理系统》进行逆软件工程的思考与实践。

1 开发设备运行环境

配置项 具体信息
OS 名称 Microsoft Windows 11 家庭中文版
OS 版本 10.0.26200 暂缺 Build 26200
系统制造商 LENOVO
系统型号 83DF
系统类型 x64-based PC
处理器 安装了1个处理器:[01]:Intel64 Family 6 Model 183 Stepping 1 GenuineIntel ~2200 Mhz
物理内存总量 32,492 MB
可用的物理内存 17,238 MB
虚拟内存(最大值) 34,540 MB
虚拟内存(可用) 12,397 MB
虚拟内存(使用中) 22,143 MB
编译器 Dev-C++

2 系统核心模块功能测试

本次测试覆盖系统三大核心模块:学生管理模块、银行账户管理模块、数据管理模块(以下图片依次为对应功能的源代码和测试结果截图)。

2.1 学生管理模块

2.1.1 添加学生

创建新节点并初始化输入的姓名、专业、生源地;将节点添加到链表尾部,同时为该学生创建农业银行和建设银行账户。

点击查看代码
void addStudent(string name, string major, string origin) {Student* newStudent = new Student(name, major, origin);if (!head) {head = newStudent;} else {Student* temp = head;while (temp->next) temp = temp->next;temp->next = newStudent;}accounts.push_back(BankAccount());  // 创建对应的银行账户cout << "学生 " << name << " 添加成功!" << endl;
}

image

2.1.2 删除学生

遍历链表查找目标姓名对应的节点;调整指针关系断开节点连接,释放节点内存,并删除关联的银行账户数据。

点击查看代码
void deleteStudent(string name) {Student* curr = head;Student* prev = nullptr;int index = 0;while (curr) {if (curr->name == name) {// 从链表中删除if (prev) prev->next = curr->next;else head = curr->next;// 从账户容器中删除accounts.erase(accounts.begin() + index);delete curr;cout << "学生 " << name << " 已删除" << endl;return;}prev = curr;curr = curr->next;index++;}cout << "未找到学生: " << name << endl;
}

image

2.1.3 修改学生信息

按姓名查找节点后,直接更新专业和生源地字段值。

点击查看代码
void updateStudent(string name, string newMajor, string newOrigin) {Student* curr = head;while (curr) {if (curr->name == name) {curr->major = newMajor;curr->origin = newOrigin;cout << "学生信息已更新" << endl;return;}curr = curr->next;}cout << "未找到学生: " << name << endl;
}

image

2.1.4 显示学生列表

遍历链表,按序号、姓名、专业、生源地格式生成表格输出。

点击查看代码
void displayAllStudents() {cout << "\n====== 学生通讯录 ======\n";Student* curr = head;int index = 0;while (curr) {cout << "[" << index + 1 << "] " << curr->name << " | "<< curr->major << " | " << curr->origin << endl;curr = curr->next;index++;}cout << "=======================\n";
}

image

2.2 银行账户管理模块

2.2.1 存款操作

验证学生存在性及存款金额有效性(>0);直接增加对应银行账户的余额,并实时显示更新后余额。

点击查看代码
void deposit(string name, string bank, double amount) {int index = findAccountIndex(name);if (index != -1) {accounts[index].deposit(bank, amount);cout << "存款成功! 当前" << bank << "余额: "<< getBalance(name, bank) << endl;} else {cout << "学生不存在" << endl;}
}

image

2.2.2 消费操作

检查消费金额是否超过账户余额,充足则扣减金额,否则提示 “余额不足”;操作后显示当前余额。

点击查看代码
void consume(string name, string bank, double amount) {int index = findAccountIndex(name);if (index != -1) {if (accounts[index].consume(bank, amount)) {cout << "消费成功! 当前" << bank << "余额: "<< getBalance(name, bank) << endl;} else {cout << "消费失败! " << bank << "余额不足" << endl;}} else {cout << "学生不存在" << endl;}
}

image

2.3 数据管理模块

2.3.1 保存数据(二进制格式存储)

将学生链表数据写入contacts.dat文件,账户数据写入bank.dat文件;支持手动触发保存或退出时自动保存。

点击查看代码
void saveToFile(string contactFile, string bankFile) {// 保存通讯录ofstream outContact(contactFile, ios::binary);Student* curr = head;while (curr) {size_t len = curr->name.size();outContact.write(reinterpret_cast<char*>(&len), sizeof(len));outContact.write(curr->name.c_str(), len);len = curr->major.size();outContact.write(reinterpret_cast<char*>(&len), sizeof(len));outContact.write(curr->major.c_str(), len);len = curr->origin.size();outContact.write(reinterpret_cast<char*>(&len), sizeof(len));outContact.write(curr->origin.c_str(), len);curr = curr->next;}outContact.close();// 保存银行数据ofstream outBank(bankFile, ios::binary);for (auto& acc : accounts) {outBank << acc;}outBank.close();cout<< "" cout << "数据保存成功!" << endl;
}

image

2.3.2 加载数据

contacts.dat读取数据重建学生链表,从bank.dat读取数据填充账户容器;启动时自动加载或由用户手动触发加载。

点击查看代码
void loadFromFile(string contactFile, string bankFile) {// 加载通讯录ifstream inContact(contactFile, ios::binary);if (!inContact) return;while (true) {size_t len;if (!inContact.read(reinterpret_cast<char*>(&len), sizeof(len))) break;string name(len, ' ');inContact.read(&name[0], len);inContact.read(reinterpret_cast<char*>(&len), sizeof(len));string major(len, ' ');inContact.read(&major[0], len);inContact.read(reinterpret_cast<char*>(&len), sizeof(len));string origin(len, ' ');inContact.read(&origin[0], len);addStudent(name, major, origin);}inContact.close();// 加载银行数据ifstream inBank(bankFile, ios::binary);if (!inBank) return;accounts.clear();BankAccount acc;while (inBank >> acc) {accounts.push_back(acc);}inBank.close();cout << "数据加载成功!" << endl;
}

image

补充说明

该系统的运行结果截图中的可视化列表均在主函数中编写,且代码结构均类似,以下以 “学生管理子菜单” 为例附源代码:

点击查看代码
// 学生管理子菜单
void displayStudentMenu() {cout << "\n===== 学生管理 =====";cout << "\n1. 添加学生";cout << "\n2. 删除学生";cout << "\n3. 修改学生信息";cout << "\n4. 显示所有学生";cout << "\n0. 返回主菜单";cout << "\n请选择操作: ";
}

3 系统现存核心问题分析

  1. 查找效率低:原系统中findAccountIndex/updateStudent等方法遍历单链表,时间复杂度为$O(n)$,学生数量较大时,查找、修改、删除的效率显著下降。
  2. 文件IO性能差saveToFile函数逐节点/逐账户写入文件,频繁的磁盘IO交互导致系统整体性能降低。
  3. 内存安全与数据一致性问题:使用裸指针易引发内存泄漏;loadFromFile加载数据时未清空原有数据,导致新旧数据混杂,数据一致性差。

4 针对性优化建议

4.1 优化查找效率(解决问题1)

改用std::unordered_map<string, Student>(以学生姓名为Key),将查询、修改、删除的时间复杂度降至$O(1)$,核心代码如下:

点击查看代码
class PersonalInfoSystem {
private:unordered_map<string, Student> studentMap; // 替代单链表unordered_map<string, BankAccount> accountMap; // 替代账户向量
};

4.2 优化文件IO性能(解决问题2)

先写入“学生数量”到文件头部,再批量写入数据,减少磁盘交互次数,核心代码如下:

点击查看代码
void saveToFile(string contactFile, string bankFile) {ofstream outContact(contactFile, ios::binary);size_t studentCount = studentMap.size();//先写入学生的数量outContact.write(reinterpret_cast<char*>(&studentCount),sizeof(studentCount));for (unordered_map<string, Student>::iterator it = studentMap.begin(); it != studentMap.end(); ++it) {string& name = it->first;Student& stu = it->second;// 写入stu信息...
}
}
测试结果截图:

image

4.3 优化内存与数据一致性(解决问题3)

loadFromFile函数加载数据前,调用clear()清空原有数据,避免冗余,核心代码如下:

点击查看代码
void loadFromFile(string contactFile, string bankFile) {studentMap.clear();accountMap.clear();// 原加载数据的代码逻辑
}
测试结果截图:

image

5 总结

  1. 所有优化中最难的点在于思维转变和技术壁垒:
    • 习惯单链表「节点创建(new)→ 指针遍历→ 手动释放(delete)」的手动操作,切换到unordered_map的「键值对存储 + 自动管理内存」时易出问题:
      1. 学习并实践新语法/语句的时间成本较高;
      2. 忽略姓名作为键的唯一性约束,遗漏“添加前find()校验唯一性”逻辑,导致业务逻辑错乱;
      3. 迭代器使用出错(如用错it->first/second、Dev-C++中advance()因缺<iterator>头文件编译报错)。
  2. 逆向软件工程核心思维:
    • 以现有系统/代码为结果,反向推导其需求、架构、设计缺陷与优化逻辑,而非正向开发;
    • 由表及里(功能表象→底层逻辑)、溯源归因(优化结果→原始问题)、抓核心关联(如以“姓名为键”推导存储/耦合规则),核心是还原“为什么这么设计” 而非仅“怎么做”。
http://www.jsqmd.com/news/455403/

相关文章:

  • 轻量级视频生成模型Wan2.2-T2V-A5B体验:速度快、门槛低、效果直观
  • MogFace人脸检测模型训练复现:自建数据集微调提升口罩识别专项精度
  • MusePublic Art Studio一文详解:如何用Streamlit实现SDXL的低门槛交互封装
  • mPLUG模型性能调优:从参数到架构
  • 龙虾养成日记PPT看不过瘾?内部版逐字稿来了
  • MCP 2.0安全协议深度解析(TLS 1.3+双向认证+动态密钥协商全链路拆解)
  • 人脸识别OOD模型保姆级教学:日志定位‘质量分突降’根因方法
  • 基于GTE+SeqGPT的Agent Skill开发实战指南
  • YOLO-v8.3问题解决:部署常见错误排查,一键修复环境配置问题
  • 通信 I/O 基础知识总结
  • 从 OpenClaw 到 落地Claw:AI Agent 的「最后一公里」
  • 移动端适配尝试:cv_resnet101_face-detection模型轻量化后用于Android原型开发效果
  • Qwen3-4B实战:如何用一块普通显卡搭建高性能文本生成服务?
  • (200分)- 找数字(Java JS Python C)
  • 深度解析:Flowable + Vue3 企业级流程架构设计——为什么 若依RuoYi Office 的 BPM 能真正落地?
  • 2026四川活动物料工厂推荐榜 环保合规服务优 - 资讯焦点
  • (200分)- 找到比自己强的人数(Java JS Python)
  • Qwen3-ASR-0.6B在智能汽车中的应用:多模态交互系统设计
  • RAG意图分类微调实战教程(非常详细):构建专属“前置路由”,从入门到精通,收藏这一篇就够了!
  • 付了GPT-5的钱,用的是开源模型
  • 高效安全的开源激活工具:轻松搞定Windows与Office授权难题
  • GoChatIAI -Go语言AI应用服务平台
  • Ansible+cpolar NAS 设备远程自动化管理,不再手动操作!
  • 【2026强制新规预警】:MCP系统OAuth接入失败率下降83%的5个关键配置项
  • Agentic RAG深度解析教程(非常详细):最新论文揭秘技术真相,从入门到精通,收藏这一篇就够了!
  • UnityLive2DExtractor:自动化资源提取赋能Live2D工作流的效率革命
  • PyTorch二分类实战:BCEWithLogitsLoss的3个常见坑与解决方案
  • 用Gazebo+ROS打造智能家居仿真环境:从建模到自动化启动全流程
  • RAG评估体系搭建教程(非常详细):RAGAS+LangFuse实战全解,从入门到精通,收藏这一篇就够了!
  • Java 17中5种高效复制List的方法对比(附性能测试)