C语言学生成绩管理系统的逆向软件设计和开发
(1)来源
源代码来自https://github.com/dvxiaofan/C---demo/tree/master/%E5%AD%A6%E7%94%9F%E6%88%90%E7%BB%A9%E7%AE%A1%E7%90%86
(2)运行环境+运行结果的截图(附伸缩源代码)
点击查看代码
//
// main.c
// 学生成绩管理
//
// Created by 张张张小烦 on 16/1/12.
// Copyright © 2016年 张张张小烦. All rights reserved.
//
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#define STUDENTS 100//定义宏
#define ITEMS 10//同上
void input(int *n,int *k,char name[][20],char itemname[][10],int score[STUDENTS][ITEMS]);//指针函数声明
void show(int *n,int *k,char name[][20],char itemname[][10],int score[STUDENTS][ITEMS]);//指针函数声明
void sort(int *n,int *k,char name[STUDENTS][20],int score[STUDENTS][ITEMS]);
int main(int argc, const char * argv[])
{
int n;//班级总人数
int k;//班级总科目
char name[STUDENTS][20];//保存名字的二维数组
char itemname[ITEMS][10];//保存科目名字的二维数组
int score[STUDENTS][ITEMS];//保存分数的整型二维数组
input(&n,&k,name,itemname,score);//调用输入函数
show(&n,&k,name,itemname,score);//调用输出函数
sort(&n,&k,name,score);
show(&n,&k,name,itemname,score);
return 0;
}
//输入函数
void input(int *n,int *k,char name[][20],char itemname[][10],int score[STUDENTS][ITEMS])//定义指针式输入函数
{
printf("请输入班级人数:");//获取总人数
scanf("%d",n);
printf("请输入科目数:");//获取科目数
scanf("%d",k);
for (int i=0; i<*k; i++)//循环获得科目名字
{
printf("请输入第%d个科目名字:",i+1);
scanf("%s",itemname[i]);
}
for (int i=0; i<*n; i++)//循环获得同学名字
{
printf("请输入第%d位同学的名字:",i+1);
scanf("%s",name[i]);
score[i][*k]=0;//定义总分为零
for (int j=0; j<*k; j++)//循环获得每名同学每科成绩
{
printf("请输入%s同学%s科目的成绩:",name[i],itemname[j]);
scanf("%d",&score[i][j]);
score[i][*k]+=score[i][j];//总分累加而出
}
}
}
//输出函数
void show(int *n,int *k,char name[][20],char itemname[][10],int score[STUDENTS][ITEMS])//定义指针式输出函数
{
printf("姓名\t");//输出姓名显示
for (int i=0; i<*k; i++)//循环输出科目名字
{
printf("%s\t",itemname[i]);
}
printf("总分\n");//输出总分提示
for (int i=0; i<*n; i++)//循环输出每个名字
{
printf("%s\t",name[i]);
for (int j=0; j<=*k; j++)//内循环输出每科成绩
{
printf("%d\t",score[i][j]);
}
printf("\n");
}
}
//排序函数
void sort(int *n,int *k,char name[STUDENTS][20],int score[STUDENTS][ITEMS])
{
char temp[40];//定义一个临时数组
for (int i=0; i<*n-1; i++)//比较排名,跟后面的比
{
for (int j=i+1; j<*n; j++)//后面的人
{
if (score[i][*k]<score[j][*k])//判断谁的总分高
{
int t=score[i][*k];//进行总分调换
score[i][*k]=score[j][*k];
score[j][*k]=t;
strcpy(temp, name[i]);//姓名调换
strcpy(name[i], name[j]);
strcpy(name[j], temp);
for (int m=0; m<*k; m++)//各科分数调换
{
int t=score[i][m];
score[i][m]=score[j][m];
score[j][m]=t;
}
}
}
}
}

(3)主要问题列表,针对问题的改善或者重构思路
源代码功能只有输入输出学生成绩和排序总成绩的功能,功能太单调
同时发现源代码中的总分排序是直接在总分的数组内调整顺序,可能会出bug
改善:准备增加求平均数功能和单科的排序功能
同时增加菜单功能进而能对数据进行更加明朗的操作
总分排序通过新设立一个数组来保存顺序,同时用结构体来使数据的相互匹配,使排序时学生的信息是跟着一起移动
(4)新增部分代码附上
部分小改动不在展示
点击查看代码
// 使用结构体让数据管理更清晰
typedef struct {
char name[20];
int scores[ITEMS];
int total;
float average;
} Student;
// 增加菜单选择
int choice;
printf("\n请选择排序方式:1.按总分排序 2.按单科排序 其他.不排序\n");
printf("请输入选择:");
scanf("%d", &choice);
if (choice == 1) {
sortByTotal(&n, &k, stu);
printf("\n===== 按总分排序结果 =====\n");
show(&n, &k, itemname, stu);
}
else if (choice == 2) {
sortBySubject(&n, &k, itemname, stu);
printf("\n===== 按单科排序结果 =====\n");
show(&n, &k, itemname, stu);
}
// 新增:按单科排序
void sortBySubject(int* n, int* k, char itemname[][10], Student stu[])
{
int subjectIndex;
// 显示可选科目
printf("\n可选科目:\n");
for (int i = 0; i < *k; i++)
{
printf("%d. %s\n", i + 1, itemname[i]);
}
printf("请选择要排序的科目编号:");
scanf("%d", &subjectIndex);
subjectIndex--; // 转为数组下标(0开始)
if (subjectIndex < 0 || subjectIndex >= *k)
{
printf("科目编号无效!\n");
return;
}
// 按选定科目成绩排序
Student temp;
for (int i = 0; i < *n - 1; i++)
{
for (int j = i + 1; j < *n; j++)
{
if (stu[i].scores[subjectIndex] < stu[j].scores[subjectIndex])
{
temp = stu[i];
stu[i] = stu[j];
stu[j] = temp;
}
}
}
printf("已按 %s 成绩从高到低排序\n", itemname[subjectIndex]);
}// 新增:按单科排序
void sortBySubject(int* n, int* k, char itemname[][10], Student stu[])
{
int subjectIndex;
// 显示可选科目
printf("\n可选科目:\n");
for (int i = 0; i < *k; i++)
{
printf("%d. %s\n", i + 1, itemname[i]);
}
printf("请选择要排序的科目编号:");
scanf("%d", &subjectIndex);
subjectIndex--; // 转为数组下标(0开始)
if (subjectIndex < 0 || subjectIndex >= *k)
{
printf("科目编号无效!\n");
return;
}
// 按选定科目成绩排序
Student temp;
for (int i = 0; i < *n - 1; i++)
{
for (int j = i + 1; j < *n; j++)
{
if (stu[i].scores[subjectIndex] < stu[j].scores[subjectIndex])
{
temp = stu[i];
stu[i] = stu[j];
stu[j] = temp;
}
}
}
printf("已按 %s 成绩从高到低排序\n", itemname[subjectIndex]);
}

(6)总结:难点、花时间比较久的、逆向软件工程的一些思考
1.在读没批注的代码时要花费些许时间来判断其目的和是如何完成目标的方法,然后还需要分析出其中可能会存在的bug和可以修改的算法
2.在新增结构题后很多输入输出的地方都要重新修改使其能匹配上结构体
3.思考实现新功能所需的算法
4.修复各种没注意的bug以及还要搜索如何解决代码和编译器的兼容问题难点

浙公网安备 33010602011771号