软件开发与创新课程设计作业——软件逆向设计

一、来源:CSDN网站他人分享的学生管理系统,网站导航

点击查看源码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct student
{
	int num;
	char name[20];
	char sex[10];
	int year;
	float score;
	struct student* next;
};
int n;
struct student* h;
int main()
{
	void log();//登录函数
	void record();//目录
	struct student* creat();//输入函数
	void print(struct student* head); //输出函数
	void dels(); //删除全操作
	void adds(); //添加全操作 
	struct student* refers(struct student* h1);//查询操作 
	struct student* change(struct student* hl); //更改操作 

	int in1, in2;

	log();
	while (1)
	{
		printf("\n请输入你的操作命令:");
		do {
			scanf("%d", &in1);
		} while (in1 != 1 && in1 != 2 && in1 != 3 && in1 != 4 && in1 != 5 && in1 != 6);
		if (in1 == 1 || in1 == 2 || in1 == 3 || in1 == 4 || in1 == 5)
		{
			printf("\n未储存有数据!\n请输入数据!");
			break;
		}
		else {
			printf("你已退出!欢迎使用!");
			break;
		}
	}
	h = creat();
	print(h);
A: {
	printf("\n**********************************************************");
	printf("\n1、返回界面  2、添加  3、删除  4、更改  5、查询  6、退出");
	printf("\n请输入你的操作命令:");
	scanf("%d", &in2);
	switch (in2)
	{
	case 1: {
		log();
		break;
	}
	case 2: {
		adds();
		goto A;
		break;
	}
	case 3: {
		dels();
		goto A;
		break;
	}
	case 4: {
		change(h);
		goto A;
		break;
	}
	case 5: {
		refers(h);
		goto A;
		break;
	}
	case 6: {
		printf("\n你已退出!欢迎使用!");
		break;
	}
	default:printf("\n输入错误!"); printf("\n你已退出!欢迎使用!"); break;
	}
	}
}
void log() //登录函数
{
	int i;
	void record();
	printf("      学生管理系统 \t");
	printf("\n\t1、登录\n\t2、退出\t");

	while (1) //循环输入,判断
	{
		printf("\n\n请输入你要执行的操作:");
		do {
			scanf("%d", &i);
		} while (i != 1 && i != 2);

		if (i == 1)
		{
			record();
			break;
		}
		else
		{
			printf("\n你已退出,欢迎使用!");
			break;
		}
	}
}
void record() //显示目录
{
	printf("\n\t1、显示学生信息");
	printf("\n\t2、添加学生信息");
	printf("\n\t3、删除学生信息");
	printf("\n\t4、更改学生信息");
	printf("\n\t5、查询学生信息");
	printf("\n\t6、退出学生系统");
}
struct student* creat() //输入数据 
{
	struct student* head;
	struct student* p1, * p2;
	p1 = (struct student*)malloc(sizeof(struct student));
	p2 = p1;
	printf("\n请输入学生学号、姓名、性别、年龄、成绩 :");
	scanf("%d%s%s%d%f", &p1->num, &p1->name, &p1->sex, &p1->year, &p1->score);
	head = NULL;
	n = 0;
	while (p1->num != 0)
	{
		n++;
		if (n == 1)
		{
			head = p1;
		}
		else
		{
			p2->next = p1;
		}
		p2 = p1;
		p1 = (struct student*)malloc(sizeof(struct student));
		printf("请输入学生学号、姓名、性别、年龄、成绩 :");
		scanf("%d%s%s%d%f", &p1->num, &p1->name, &p1->sex, &p1->year, &p1->score);
	}
	p2->next = NULL;
	return head;
}
void print(struct student* hl) //输出数据 
{
	struct student* p;
	p = hl;
	if (hl != NULL)
	{
		printf("\n\t学号:\t姓名:\t性别:\t年龄:\t成绩:");
		do {
			printf("\n\t%d\t%s\t%s\t%d\t%.2f", p->num, p->name, p->sex, p->year, p->score);
			p = p->next;
		} while (p != NULL);
	}
}
void dels() 
{
	struct student* del(struct student* h, int sum);
	void print(struct student* head);

	int sum;
	int ch;

	while (1)
	{
		printf("\n你是否需要删除数据(Y/N):");
		do
		{
			ch = getchar();
		} while (ch != 'Y' && ch != 'N');

		if (ch == 'Y')
		{
			printf("请输入你要删除的数据:");
			scanf("%d", &sum);
			h = del(h, sum);
			print(h);
		}
		else
		{
			break;
		}
	}

	printf("删除完毕!最终数据为:\n");
	print(h);

}
struct student* del(struct student* hl, int sum) 
{
	struct student* p1, * p2;
	p2 = p1 = hl;

	while (p1->num != sum && p1->next != NULL)
	{
		p2 = p1;
		p1 = p1->next;
	}
	if (p1->num == sum)
	{
		if (p1 == h)
		{
			hl = p1->next;
		}
		else
		{
			p2->next = p1->next;
		}
	}
	else
	{
		printf("未找到数据!");
	}
	return h;
}
void adds() {
	struct student* add(struct student** h, int num, char name[20], char sex[10], int year, float score);
	void print(struct student* h);

	int num;
	char name[20];
	char sex[10];
	int year;
	float score;
	int ch;

	while (1)
	{
		printf("\n你是否需要添加数据:");
		do {
			ch = getchar();
		} while (ch != 'Y' && ch != 'N');

		if (ch == 'Y')
		{
			printf("\n请输入学生学号、姓名、性别、年龄、成绩 :");
			scanf("%d%s%s%d%f", &num, &name, &sex, &year, &score);
			h = add(&h, num, name, sex, year, score);
		}
		else
		{
			break;
		}
	}

	printf("添加完毕!");
	printf("最终数据为:\n");
	print(h);

}
struct student* add(struct student** hl, int num, char name[20], char sex[10], int year, float score)  
{
	struct student* p1, * p2, * New;
	p1 = *hl;
	p2 = NULL;

	while (p1 != NULL && p1->num < num)
	{
		p2 = p1;
		p1 = p1->next;
	}

	New = (struct student*)malloc(sizeof(struct student));

	New->num = num;
	strcpy(New->name, name);
	strcpy(New->sex, sex);
	New->year = year;
	New->score = score;
	New->next = p1;

	if (p2 == NULL)
	{
		*hl = New;
	}
	else
	{
		p2->next = New;
	}

	return *hl;
}
struct student* refers(struct student* hl) //查询全操作 
{
	struct student* p1, * p2, * p0;
	int num;
	int ch;
	p0 = NULL;
	while (1)
	{
		p1 = p2 = hl;
		printf("\n你是否需要查询(Y/N):");
		do {
			ch = getchar();
		} while (ch != 'Y' && ch != 'N');
		if (ch == 'Y')
		{
			printf("\n请输入你要查询的学号:");
			scanf("%d", &num);
			while (p1->num != num && p1->next != NULL)
			{
				p2 = p1;
				p1 = p1->next;
			}
			if (p1->num == num)
			{
				p0 = p1;
				printf("\n你的查询结果:");
				printf("\n\t学号:\t姓名:\t性别:\t年龄:\t成绩:");
				printf("\n\t%d\t%s\t%s\t%d\t%.2f", p0->num, p0->name, p0->sex, p0->year, p0->score);
			}
			else
			{
				printf("未找到相关数据!");
			}
		}
		else {
			printf("\n你已退出查询!");
			break;
		}
	}
	return h;
}
struct student* change(struct student* hl) //更改全操作 
{
	struct student* xue(struct student* d);
	struct student* xing(struct student* d);
	struct student* bie(struct student* d);
	struct student* nian(struct student* d);
	struct student* cheng(struct student* d);
	struct student* p1, * p2, * p0;
	int num;
	int ch;
	int chan;
	p0 = NULL;
	while (1)
	{
		p1 = p2 = hl;
		printf("\n你是否需要更改(Y/N):");
		do {
			ch = getchar();
		} while (ch != 'Y' && ch != 'N');
		if (ch == 'Y')
		{
			printf("\n请输入你要更改的学号:");
			scanf("%d", &num);
			while (p1->num != num && p1->next != NULL)
			{
				p2 = p1;
				p1 = p1->next;
			}
			if (p1->num == num)
			{
				p0 = p1;
				printf("\n1、学号 2、姓名 3、性别 4、年龄 5、成绩");
				printf("\n请输入你的操作:");
				scanf("%d", &chan);
				switch (chan)
				{
				case 1:xue(p0); break;
				case 2:xing(p0); break;
				case 3:bie(p0); break;
				case 4:nian(p0); break;
				case 5:cheng(p0); break;
				default:break;
				}
				printf("\n你更改后的结果:");
				printf("\n\t学号:\t姓名:\t性别:\t年龄:\t成绩:");
				printf("\n\t%d\t%s\t%s\t%d\t%.2f", p0->num, p0->name, p0->sex, p0->year, p0->score);
			}
			else
			{
				printf("未找到相关数据!");
			}
		}
		else {
			printf("\n你已退出更改!");
			break;
		}
	}
	return h;
}
struct student* xue(struct student* d) //更改学号 
{
	struct student* p;
	p = d;
	printf("\n请输入新的学号:");
	scanf("%d", &p->num);
	return p;
}
struct student* xing(struct student* d)//更改姓名 
{
	struct student* p;
	char s[20];
	p = d;
	printf("\n请输入新的姓名:");
	scanf("%s", &s);
	strcpy(p->name, s);
	return p;
}
struct student* bie(struct student* d)//更改性别 
{
	struct student* p;
	char s[10];
	p = d;
	printf("\n请输入新的性别:");
	scanf("%s", &s);
	strcpy(p->sex, s);
	return p;
}
struct student* nian(struct student* d)//更改年龄 
{
	struct student* p;
	p = d;
	printf("\n请输入新的年龄:");
	scanf("%d", &p->year);
	return p;
}
struct student* cheng(struct student* d)//更改成绩 
{
	struct student* p;
	p = d;
	printf("\n请输入新的成绩:");
	scanf("%f", &p->score);
	return p;
}

二、运行环境
CPU:12th Gen Intel(R) Core(TM) i5-12500H
RAM:16GB
磁盘:NVMe Micron_3400_MTFDKBA512TFH 容量:477 GB
操作系统:Windows 11
IDE:Microsoft Visual Studio Community 2022 (64 位) - Current 版本 17.12.3

三、项目介绍:
这个项目是一个基于C++实现的学生管理系统,主要用于管理学生的信息,包括学生的学号、姓名、性别、年龄和成绩等。系统主要有7个功能:

1.登录功能:用户可以选择登录系统或退出系统,登录后显示可选择的功能。

2.添加学生信息:可以多次添加学生信息,输入学号、姓名、性别、年龄和成绩即可。

3.输入学生信息:可以连续输入学生的学号、姓名、性别、年龄和成绩,输入学号为 0 时停止输入。

4.显示学生信息:将已输入的学生信息以表格形式输出。

5.删除学生信息:根据学号删除指定学生的信息,可多次删除,直到用户选择停止。

6.查询学生信息:根据学号查询学生信息,可多次查询,直到用户选择停止。

7.更改学生信息:根据学号找到学生信息后,可选择更改学号、姓名、性别、年龄或成绩。

四、主要问题

序号 主要问题 解决方案
1 代码结构混乱 将项目代码分为头文件和源文件,头文件中包含结构体定义和函数声明,源文件中包含函数的具体实现,主函数单独放在一个文件中。
2 内存泄漏 在 del 函数中,当找到要删除的节点时,使用 free(p1) 释放该节点的内存。
3 输入缓冲区问题 在使用 getchar 之前,可以使用 while (getchar() != '\n'); 来清空输入缓冲区。
4 部分提示表达不明确 修改了部分提示,让人一目了然。
5 结束创建学生信息链表的方式冗余 修改 create 函数只要输入学号为0按回车即可退出,这样可以更方便操作。
6 全局变量的使用 在头文件中使用 extern 关键字声明全局变量,在源文件中定义全局变量,这样可以避免命名冲突,同时提高代码的可维护性。
7 数据储存 将学生信息的链表储存在txt文件中,再次运行系统时可读取文件

五、重构后的代码
1.student.h

点击查看student.h代码
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


struct student {
    int num;
    char name[20];
    char sex[10];
    int year;
    float score;
    struct student* next;
};

extern int n;
extern struct student* h;

void log();
void record();
struct student* creat();
void print(struct student* head);
void dels();
void adds();
struct student* refers(struct student* h1);
struct student* change(struct student* hl);
struct student* del(struct student* hl, int sum);
struct student* add(struct student** hl, int num, char name[20], char sex[10], int year, float score);
struct student* xue(struct student* d);
struct student* xing(struct student* d);
struct student* bie(struct student* d);
struct student* nian(struct student* d);
struct student* cheng(struct student* d);
void saveToFile(struct student* hl);

2.student.cpp

点击查看student.cpp代码
#include "student.h"

int n;
struct student* h;

void saveToFile(struct student* hl) {
    FILE* fp = fopen("students.txt", "w");
    if (fp == nullptr) {
        printf("无法打开文件!\n");
        return;
    }
    struct student* p = hl;
    while (p != nullptr) {
        fprintf(fp, "%d %s %s %d %.2f\n", p->num, p->name, p->sex, p->year, p->score);
        p = p->next;
    }
    fclose(fp);
}

void log() {
    int i;
    printf("      学生管理系统 \t");
    printf("\n\t1、登录\n\t2、退出\t");

    while (1) { 
        printf("\n\n请输入你要执行的操作:");
        do {
            scanf("%d", &i);
        } while (i != 1 && i != 2);

        if (i == 1) {
            record();
            break;
        }
        else {
            printf("\n你已退出,欢迎使用!");
            break;
        }
    }
}

void record() {
    printf("\n\t1、显示学生信息");
    printf("\n\t2、添加学生信息");
    printf("\n\t3、删除学生信息");
    printf("\n\t4、更改学生信息");
    printf("\n\t5、查询学生信息");
    printf("\n\t6、退出学生系统");
}

struct student* creat() {
    struct student* head = nullptr;
    struct student* p1 = (struct student*)malloc(sizeof(struct student));
    struct student* p2 = p1;

    printf("\n请输入学生学号、姓名、性别、年龄、成绩 :");
    scanf("%d", &p1->num);

    n = 0;
    while (p1->num != 0) {
        scanf("%s%s%d%f", p1->name, p1->sex, &p1->year, &p1->score);
        n++;
        if (n == 1) {
            head = p1;
        }
        else {
            p2->next = p1;
        }
        p2 = p1;
        p1 = (struct student*)malloc(sizeof(struct student));
        printf("请输入学生学号、姓名、性别、年龄、成绩 :");
        scanf("%d", &p1->num);
    }
    p2->next = nullptr;
    return head;
}

void print(struct student* hl) {
    struct student* p = hl;
    if (hl != nullptr) {
        printf("\n\t学号:\t姓名:\t性别:\t年龄:\t成绩:");
        do {
            printf("\n\t%d\t%s\t%s\t%d\t%.2f", p->num, p->name, p->sex, p->year, p->score);
            p = p->next;
        } while (p != nullptr);
    }
}

void dels() {
    int sum;
    int ch;

    while (1) {
        printf("\n你是否需要删除数据(Y/N):");
        do {
            ch = getchar();
        } while (ch != 'Y' && ch != 'N');

        if (ch == 'Y') {
            printf("请输入你要删除的学生的学号:");
            scanf("%d", &sum);
            h = del(h, sum);
            print(h);
        }
        else {
            break;
        }
    }

    printf("删除完毕!最终数据为:\n");
    print(h);
    // 删除数据后保存到文件
    saveToFile(h);
}

struct student* del(struct student* hl, int sum) {
    struct student* p1 = hl;
    struct student* p2 = hl;

    while (p1 != nullptr && p1->num != sum) {
        p2 = p1;
        p1 = p1->next;
    }

    if (p1 != nullptr && p1->num == sum) {
        if (p1 == h) {
            hl = p1->next;
        }
        else {
            p2->next = p1->next;
        }
        free(p1);
    }
    else {
        printf("未找到数据!");
    }
    return hl;
}

void adds() {
    int num;
    char name[20];
    char sex[10];
    int year;
    float score;
    int ch;

    while (1) {
        printf("\n你是否需要添加数据:");
        do {
            ch = getchar();
        } while (ch != 'Y' && ch != 'N');

        if (ch == 'Y') {
            printf("\n请输入学生学号、姓名、性别、年龄、成绩 :");
            scanf("%d%s%s%d%f", &num, name, sex, &year, &score);
            h = add(&h, num, name, sex, year, score);
        }
        else {
            break;
        }
    }

    printf("添加完毕!");
    printf("最终数据为:\n");
    print(h);
    saveToFile(h);
}

struct student* add(struct student** hl, int num, char name[20], char sex[10], int year, float score) {
    struct student* p1 = *hl;
    struct student* p2 = nullptr;

    while (p1 != nullptr && p1->num < num) {
        p2 = p1;
        p1 = p1->next;
    }

    struct student* New = (struct student*)malloc(sizeof(struct student));
    New->num = num;
    strcpy(New->name, name);
    strcpy(New->sex, sex);
    New->year = year;
    New->score = score;
    New->next = p1;

    if (p2 == nullptr) {
        *hl = New;
    }
    else {
        p2->next = New;
    }

    return *hl;
}

struct student* refers(struct student* hl) {
    int num;
    int ch;

    while (1) {
        printf("\n你是否需要查询(Y/N):");
        do {
            ch = getchar();
        } while (ch != 'Y' && ch != 'N');

        if (ch == 'Y') {
            printf("\n请输入你要查询的学号:");
            scanf("%d", &num);

            struct student* p1 = hl;
            while (p1 != nullptr && p1->num != num) {
                p1 = p1->next;
            }

            if (p1 != nullptr && p1->num == num) {
                printf("\n你的查询结果:");
                printf("\n\t学号:\t姓名:\t性别:\t年龄:\t成绩:");
                printf("\n\t%d\t%s\t%s\t%d\t%.2f", p1->num, p1->name, p1->sex, p1->year, p1->score);
            }
            else {
                printf("未找到相关数据!");
            }
        }
        else {
            printf("\n你已退出查询!");
            break;
        }
    }
    return hl;
}

struct student* change(struct student* hl) {
    int num;
    int ch;
    int chan;

    while (1) {
        printf("\n你是否需要更改(Y/N):");
        do {
            ch = getchar();
        } while (ch != 'Y' && ch != 'N');

        if (ch == 'Y') {
            printf("\n请输入你要更改学生的学号:");
            scanf("%d", &num);

            struct student* p1 = hl;
            while (p1 != nullptr && p1->num != num) {
                p1 = p1->next;
            }

            if (p1 != nullptr && p1->num == num) {
                printf("\n1、学号 2、姓名 3、性别 4、年龄 5、成绩");
                printf("\n请输入要更改的属性:");
                scanf("%d", &chan);

                switch (chan) {
                case 1: xue(p1); break;
                case 2: xing(p1); break;
                case 3: bie(p1); break;
                case 4: nian(p1); break;
                case 5: cheng(p1); break;
                default: break;
                }

                printf("\n你更改后的结果:");
                printf("\n\t学号:\t姓名:\t性别:\t年龄:\t成绩:");
                printf("\n\t%d\t%s\t%s\t%d\t%.2f", p1->num, p1->name, p1->sex, p1->year, p1->score);
            }
            else {
                printf("未找到相关数据!");
            }
        }
        else {
            printf("\n你已退出更改!");
            break;
        }
    }
    saveToFile(hl);
    return hl;
}

struct student* xue(struct student* d) {
    printf("\n请输入新的学号:");
    scanf("%d", &d->num);
    return d;
}

struct student* xing(struct student* d) {
    char s[20];
    printf("\n请输入新的姓名:");
    scanf("%s", s);
    strcpy(d->name, s);
    return d;
}

struct student* bie(struct student* d) {
    char s[10];
    printf("\n请输入新的性别:");
    scanf("%s", s);
    strcpy(d->sex, s);
    return d;
}

struct student* nian(struct student* d) {
    printf("\n请输入新的年龄:");
    scanf("%d", &d->year);
    return d;
}

struct student* cheng(struct student* d) {
    printf("\n请输入新的成绩:");
    scanf("%f", &d->score);
    return d;
}

3.main.cpp

点击查看main.cpp代码
#include "student.h"


int main() {
    int in1, in2;

    log();
    while (1) {
        printf("\n请输入你的操作命令:");
        do {
            scanf("%d", &in1);
        } while (in1 != 1 && in1 != 2 && in1 != 3 && in1 != 4 && in1 != 5 && in1 != 6);
        if (in1 == 1 || in1 == 2 || in1 == 3 || in1 == 4 || in1 == 5) {
            printf("\n未储存有数据!\n请输入数据!");
            break;
        }
        else {
            printf("你已退出!欢迎使用!");
            break;
        }
    }

    h = creat();
    print(h);

A: {
    printf("\n**********************************************************");
    printf("\n1、返回界面  2、添加  3、删除  4、更改  5、查询  6、退出");
    printf("\n请输入你的操作命令:");
    scanf("%d", &in2);
    switch (in2) {
    case 1: {
        log();
        break;
    }
    case 2: {
        adds();
        goto A;
        break;
    }
    case 3: {
        dels();
        goto A;
        break;
    }
    case 4: {
        change(h);
        goto A;
        break;
    }
    case 5: {
        refers(h);
        goto A;
        break;
    }
    case 6: {
        printf("\n你已退出!欢迎使用!");
        break;
    }
    default: printf("\n输入错误!"); printf("\n你已退出!欢迎使用!"); break;
    }
    }

return 0;
}

六、重构软件后的测试截图
1.输入学生信息

2..删除学生信息

3.更改学生信息

4.添加学生信息

七、总结
1.难点:
(1)代码结构重组:原代码逻辑耦合度高,函数和全局变量混杂。将其拆分为头文件和多个源文件时,需合理规划函数声明、结构体定义和全局变量的作用域,确保模块间正确调用,这对整体架构的理解和设计能力提出了较高要求。

(2)内存泄漏修复:原删除函数未释放节点内存,导致内存泄漏。需在删除逻辑中精确追踪节点指针,确保每次删除后正确释放内存,同时避免因指针操作错误引发程序崩溃。

(3)全局变量重构:将原全局变量改为 extern 声明时,需确保多文件间的编译链接正确性,避免重复定义或未定义错误,这需要反复验证头文件包含关系和编译命令。

2.耗时较长的部分:
(1)输入缓冲区处理:原代码使用 getchar 时未清空缓冲区,导致交互逻辑异常。需插入 while (getchar() != '\n'); 清除残留输入,这对输入流机制的深入理解是关键。

(2)数据文件储存:新增文件存储功能时,需设计文件读写格式(如文本或二进制),确保链表数据与文件内容双向转换的一致性,同时处理文件打开失败等异常情况。

(3)链表操作调试:在实现添加、删除和修改功能时,链表指针的指向容易出错(如头节点处理、中间节点断裂),需通过逐行调试和打印节点信息验证逻辑正确性。

(4)交互逻辑优化:原代码的输入提示不明确,例如创建链表时需反复输入学号0才能退出。调整为“学号为0即终止”后,需重构输入循环结构,并处理输入格式错误(如非数字输入)导致的死循环问题。

3.对软件逆向工程的思考:
(1)理解原有逻辑:逆向工程需从代码的功能缺陷倒推设计意图。例如,通过分析原删除函数未释放内存的代码,推断作者可能忽视了动态内存管理的基本原则。

(2)渐进式重构:在保持功能不变的前提下,优先修复严重问题,再逐步优化结构。例如,先解决内存泄漏再拆分文件,避免同时修改多处引发不可控错误。

(3)扩展性与健壮性:逆向工程不仅是修复,更是提升。例如,新增文件存储功能时,需在不破坏原有链表逻辑的基础上,设计数据序列化方式,同时考虑未来可能的字段扩展。

posted @   fuku  阅读(30)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示