一、来源
源代码来自同学大一上学期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", ¤t->data.name);printf("请输入修改后的学生年龄:");scanf("%d", ¤t->data.age);printf("请输入修改后的学生成绩(最多5科):");for (int i = 0; i < MAX_SCORE_COUNT; i++) {scanf("%d", ¤t->data.scores[i]);}printf("请输入修改后的学生奖学金金额:");scanf("%d", ¤t->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.运行结果
四、主要问题列表及改善
- 输入验证不足:在输入年龄、成绩、奖学金金额时,没有检查输入是否为合法的整数。
改进:在 scanf 之后,检查返回值是否符合预期,同时可以增加范围检查,确保输入的年龄、成绩等在合理范围内。
2.添加计算学生平均成绩,在后台将学生成绩计算平均值。
2.添加排序学生信息:通过学生的平均成绩对链表中的学生信息进行排序。
五、重构的软件的测试截图
六、总结:难点、花时间比较久的、逆向软件工程的一些思考
花费时间最久的就是逆向工程完成后,需要对还原的功能进行测试,确保其与原始程序的功能一致,在逆向过程中,又会出现一些以前没有的错误,需要对这些问题进行修复,所以不仅要考虑新加入的功能,还要分析以前的代码和新加入的功能的合理性。
在此次实验中,我了解到逆向软件工程有一定实际意义,逆向工程可以帮助我们学习和研究优秀的软件设计和实现技术。通过分析成功的软件产品,可以借鉴其中的架构设计、算法实现、优化技巧等,从而提高自己的开发水平。如果推广到企业,企业可以通过逆向工程来分析竞争对手的软件产品,了解其功能特点、技术优势和不足之处,为自己的产品研发提供参考和方向。无论是对于科研学习和企业应用,都有重要的研究意义。