逆向软件设计和开发---学生信息管理程序

news/2025/2/26 22:49:02/文章来源:https://www.cnblogs.com/Chen-0119/p/18739545

一、来源
源代码来自同学大一上学期C语言大作业
二、运行环境
Dev-C++ 6.3
三、源代码及运行结果
1.源代码

点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define MAX_NAME_LENGTH 20
#define MAX_SCORE_COUNT 5// 学生信息结构体
typedef struct {char name[MAX_NAME_LENGTH];int age;int scores[MAX_SCORE_COUNT];int scholarship;
} Student;// 学生链表节点结构体
typedef struct StudentNode {Student data;struct StudentNode* next;
} StudentNode;// 全局变量,链表头指针
StudentNode* head = NULL;// 函数声明
void addStudent();
void deleteStudent();
void modifyStudent();
void searchStudent();
void browseStudents();
void saveToFile();
void loadFromFile();
void viewScholarship();
void clearBuffer();int main() {int choice;while (1) {printf("-----------------------\n");printf("1. 添加学生\n");printf("2. 删除学生\n");printf("3. 修改学生信息\n");printf("4. 查找学生\n");printf("5. 浏览学生信息\n");printf("6. 保存到文件\n");printf("7. 从文件读取\n");printf("8. 查看奖学金信息\n");printf("0. 退出\n");printf("-----------------------\n");printf("请选择操作:");scanf("%d", &choice);switch(choice) {case 0:// 退出程序printf("感谢使用!\n");exit(0);case 1:addStudent();break;case 2:deleteStudent();break;case 3:modifyStudent();break;case 4:searchStudent();break;case 5:browseStudents();break;case 6:saveToFile();break;case 7:loadFromFile();break;case 8:viewScholarship();break;default:printf("无效的选择,请重新输入。\n");break;}}return 0;
}// 添加学生
void addStudent() {Student newStudent;printf("请输入学生姓名:");clearBuffer();fgets(newStudent.name, MAX_NAME_LENGTH, stdin);newStudent.name[strcspn(newStudent.name, "\n")] = '\0'; // 去掉换行符printf("请输入学生年龄:");scanf("%d", &newStudent.age);printf("请输入学生成绩(最多5科):");for (int i = 0; i < MAX_SCORE_COUNT; i++) {scanf("%d", &newStudent.scores[i]);}printf("请输入学生奖学金金额:");scanf("%d", &newStudent.scholarship);// 创建新节点StudentNode* newNode = (StudentNode*)malloc(sizeof(StudentNode));newNode->data = newStudent;newNode->next = NULL;// 链表为空,直接插入if (head == NULL) {head = newNode;printf("添加成功!\n");} else {// 链表不为空,找到尾节点,插入尾部StudentNode* current = head;while (current->next != NULL) {current = current->next;}current->next = newNode;printf("添加成功!\n");}
}// 删除学生
void deleteStudent() {if (head == NULL) {printf("学生信息为空,无法删除!\n");return;}char name[MAX_NAME_LENGTH];printf("请输入要删除的学生姓名:");clearBuffer();fgets(name, MAX_NAME_LENGTH, stdin);name[strcspn(name, "\n")] = '\0'; // 去掉换行符// 头结点就是要删除的节点if (strcmp(head->data.name, name) == 0) {StudentNode* temp = head;head = head->next;free(temp);printf("删除成功!\n");return;}// 遍历链表,查找要删除的节点StudentNode* current = head;StudentNode* prev = NULL;while (current != NULL && strcmp(current->data.name, name) != 0) {prev = current;current = current->next;}// 找到了要删除的节点if (current != NULL) {prev->next = current->next;free(current);printf("删除成功!\n");} else {printf("未找到要删除的学生!\n");}
}// 修改学生信息
void modifyStudent() {if (head == NULL) {printf("学生信息为空,无法修改!\n");return;}char name[MAX_NAME_LENGTH];printf("请输入要修改的学生姓名:");clearBuffer();fgets(name, MAX_NAME_LENGTH, stdin);name[strcspn(name, "\n")] = '\0'; // 去掉换行符// 遍历链表,查找要修改的节点
StudentNode* current = head;while (current != NULL && strcmp(current->data.name, name) != 0) {current = current->next;}// 找到了要修改的节点if (current != NULL) {printf("请输入修改后的学生姓名:");scanf("%s", &current->data.name);printf("请输入修改后的学生年龄:");scanf("%d", &current->data.age);printf("请输入修改后的学生成绩(最多5科):");for (int i = 0; i < MAX_SCORE_COUNT; i++) {scanf("%d", &current->data.scores[i]);}printf("请输入修改后的学生奖学金金额:");scanf("%d", &current->data.scholarship);printf("修改成功!\n");} else {printf("未找到要修改的学生!\n");}
}// 查找学生
void searchStudent() {if (head == NULL) {printf("学生信息为空,无法查找!\n");return;}char name[MAX_NAME_LENGTH];printf("请输入要查找的学生姓名:");clearBuffer();fgets(name, MAX_NAME_LENGTH, stdin);name[strcspn(name, "\n")] = '\0'; // 去掉换行符// 遍历链表,查找要查找的节点StudentNode* current = head;while (current != NULL && strcmp(current->data.name, name) != 0) {current = current->next;}// 找到了要查找的节点if (current != NULL) {printf("学生姓名:%s\n", current->data.name);printf("学生年龄:%d\n", current->data.age);printf("学生成绩:");for (int i = 0; i < MAX_SCORE_COUNT; i++) {printf("%d ", current->data.scores[i]);}printf("\n");printf("学生奖学金金额:%d\n", current->data.scholarship);} else {printf("未找到要查找的学生!\n");}
}// 浏览学生信息
void browseStudents() {if (head == NULL) {printf("学生信息为空!\n");return;}printf("学生信息如下:\n");// 遍历链表,输出学生信息StudentNode* current = head;while (current != NULL) {printf("学生姓名:%s\n", current->data.name);printf("学生年龄:%d\n", current->data.age);printf("学生成绩:");for (int i = 0; i < MAX_SCORE_COUNT; i++) {printf("%d ", current->data.scores[i]);}printf("\n");printf("学生奖学金金额:%d\n", current->data.scholarship);printf("-----------------------\n");current = current->next;}
}// 保存到文件
void saveToFile() {if (head == NULL) {printf("学生信息为空,无法保存!\n");return;}FILE *file = fopen("students.txt", "w");if (file == NULL) {printf("文件保存失败!\n");return;}// 遍历链表,将学生信息写入文件StudentNode* current = head;while (current != NULL) {fprintf(file, "%s %d ", current->data.name, current->data.age);for (int i = 0; i < MAX_SCORE_COUNT; i++) {fprintf(file, "%d ", current->data.scores[i]);}fprintf(file, "%d\n", current->data.scholarship);current = current->next;}fclose(file);printf("保存成功!\n");
}// 从文件读取
void loadFromFile() {FILE *file = fopen("students.txt", "r");if (file == NULL) {printf("文件读取失败!\n");return;}// 清空原有链表数据while (head != NULL) {StudentNode* temp = head;head = head->next;free(temp);}// 从文件中读取学生信息,创建新节点插入链表char name[MAX_NAME_LENGTH];int age;int scores[MAX_SCORE_COUNT];int scholarship;while (fscanf(file, "%s %d", name, &age) != EOF) {for (int i = 0; i < MAX_SCORE_COUNT; i++) {fscanf(file, "%d", &scores[i]);}fscanf(file, "%d", &scholarship);// 创建新节点Student newStudent;strcpy(newStudent.name, name);newStudent.age = age;memcpy(newStudent.scores, scores, sizeof(scores));newStudent.scholarship = scholarship;StudentNode* newNode = (StudentNode*)malloc(sizeof(StudentNode));newNode->data = newStudent;newNode->next = NULL;// 链表为空,直接插入if (head == NULL) {head = newNode;} else {// 链表不为空,找到尾节点,插入尾部StudentNode* current = head;while (current->next != NULL) {current = current->next;}current->next = newNode;}}fclose(file);printf("读取成功!\n");
}// 查看奖学金信息
void viewScholarship() {if (head == NULL) {printf("学生信息为空,无法查看奖学金信息!\n");return;}int scholarshipCount = 0; // 奖学金人数int totalScholarship = 0; // 奖学金总金额// 遍历链表,计算奖学金信息StudentNode* current = head;while (current != NULL) {if (current->data.scholarship > 0) {scholarshipCount++;totalScholarship += current->data.scholarship;}current = current->next;}printf("奖学金信息如下:\n");printf("奖学金人数:%d\n", scholarshipCount);printf("奖学金总金额:%d\n", totalScholarship);
}// 清空缓冲区
void clearBuffer() {while(getchar() != '\n');
}

2.运行结果






四、主要问题列表及改善

  1. 输入验证不足:在输入年龄、成绩、奖学金金额时,没有检查输入是否为合法的整数。
    改进:在 scanf 之后,检查返回值是否符合预期,同时可以增加范围检查,确保输入的年龄、成绩等在合理范围内。

2.添加计算学生平均成绩,在后台将学生成绩计算平均值。

2.添加排序学生信息:通过学生的平均成绩对链表中的学生信息进行排序。

五、重构的软件的测试截图








六、总结:难点、花时间比较久的、逆向软件工程的一些思考
花费时间最久的就是逆向工程完成后,需要对还原的功能进行测试,确保其与原始程序的功能一致,在逆向过程中,又会出现一些以前没有的错误,需要对这些问题进行修复,所以不仅要考虑新加入的功能,还要分析以前的代码和新加入的功能的合理性。
在此次实验中,我了解到逆向软件工程有一定实际意义,逆向工程可以帮助我们学习和研究优秀的软件设计和实现技术。通过分析成功的软件产品,可以借鉴其中的架构设计、算法实现、优化技巧等,从而提高自己的开发水平。如果推广到企业,企业可以通过逆向工程来分析竞争对手的软件产品,了解其功能特点、技术优势和不足之处,为自己的产品研发提供参考和方向。无论是对于科研学习和企业应用,都有重要的研究意义。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/890401.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在鹅厂做java开发是什么体验

离职已有好几个月,准备写一篇关于之前在腾讯做Java开发的经历,现在来谈谈在Java领域里,在腾讯做Java开发的体验。随便写写别较真。首先,介绍一下腾讯里与Java相关的部门。主要有CDG(云与智慧产业事业群)中的腾讯广告和FIT(金融科技事业群)理财通。其他部门则包括TEG中的…

软件二次开发

软件来源:舍友期末大作业 软件运行环境:dev C++ 软件运行图: 软件伸缩代码图: 问题:菜单只会出现一次,在多次操作之后菜单会被顶走,届时用户只能依照记忆操作系统 更改的代码: 在循环执行选项的代码部分增加了菜单的输出 更改后的代码运行:

换根dp

概念 换根 \(dp\) ,又被称为二次扫描,是属于树形 \(dp\) 的一类但比一般树形dp更难。 特点通常是没有指定根结点,且根结点的变化会对一些值产生影响。通常需要两次 \(dfs\) ,第一次 \(dfs\) 预处理信息,第二次 \(dfs\) 开始换根动态规划。求解的答案通常需要结合所有相连的…

千锋教育MyBatisPlus全套课程,简单快速一套精通MyBatisPlus框架(代码生成器_引入_使用)

https://www.bilibili.com/video/BV1aa4y1A7iN?spm_id_from=333.788.videopod.episodes&vd_source=0d7b1712ce42c1a2fa54bb4e1d601d78代码生成器_引入_使用 https://github.com/godmaybelieve

【PLSQL】使用PLSQL查看创表SQL踩坑

背景 通过PL/SQL Developer的View SQL查看表的创表语句,结果发现创表语句少了字段 可能原因PL/SQL Developer 的对象浏览器会缓存元数据信息以提高性能。如果修改表结构后未手动刷新,工具可能继续展示缓存中的旧元数据。 Oracle 的数据字典视图(如 USER_TAB_COLUMNS)本身是…

从 0 到 Offer:Dynamics 365 CRM 学员的普华永道逆袭之路

在竞争激烈的就业市场中,如何才能脱颖而出,收获理想的工作?李先顺(化名)的经历或许能给我们带来深刻的启示。这位出身普通高校信息管理专业的应届毕业生,通过在爱码士IT培训www.aimashi365.com机构的报名和培训,凭借着对 Dynamics 365 CRM 技术的深入学习和实践,成功入…

本地?线上?分布式系统前后端架构、部署、联调指南,突破技术

“ 引言:对于常见的BS架构系统,程序员如何进行本地或者线上环 境联调,这有助于提高个人工作效率,站在更高的角度审视系统, 从此以后再无惧Bug,让你早干完活,早摸鱼🐟,早下班。 对于Java初学者,或者是三年工作经验的“新手” ,希望此文对你有所裨益! -- 诗经有云,…

Spring AI 学习之路 快速上手

随着人工智能(AI)技术的迅速发展,越来越多的开发者开始关注如何在自己的应用中集成 AI 功能。Spring 框架作为一种流行的 Java 开发框架,提供了强大的支持来构建现代应用程序。本文将为你介绍如何快速上手 Spring AI,帮助你在项目中轻松集成 AI 功能。什么是 Spring AI? …

【PWN】初识Orw

例题:NPCCTF - Ooooorw发现开启了沙箱,禁用了execve函数,所以只能利用open,read,write函数来进行输出flag from pwn import *file = ./pwnlibc = ELF(./libc.so.6)i = 0if i == 1: io = process(file)else: io = remote(175.27.249.18,32438)elf = ELF(file)context…

洛谷2025省选模拟赛D1T1“Ball” 题解

洛谷2025省选模拟赛D1T1“Ball” 题解首先可以写出一个暴力的 dp : 令 \(f_{i,j}\) 表示有 \(i\) 个选了一次的球和 \(j\) 个选了大于一次的球的期望答案,有等式: \[f_{i,j}=\frac jnf_{i,j}+\frac{n-i-j}nf_{i+1,j}+\frac in f_{i-1,j+1} \]进一步得 \(f_{i,j}=\frac{n-i-j…

[计算机网络/网络抓包/以太网] `.pcap` 数据报文存储格式

序:一份以太网报文概述:.pcap 数据报文存储格式 简介.pcap文件:一种常用的数据报文存储格式,主要用于网络数据包的捕获和存储。pcap文件格式由PCAP库提供,支持将网络上的所有数据包保存到文件中,并可以从文件中读取数据包。 pcap文件通常由文件头和数据包头组成,每个数据…