软件开发与创新第一次作业--学生信息管理系统改进
《学生信息管理系统》改进
一、项目名称与来源
某同学大作业
二、原项目运行
运行环境:
系统:Windows11 24H2
cpu:i7-13700
编译器:Dev c++ 5.11
运行结果:




点击查看代码
#include <stdio.h>
#include<string.h>
#include <stdlib.h>
#define LEN sizeof(struct student)
//学生信息结构体
struct student
{int num;
char name[20];
char clas[20];
char sex[5];
float Eng_score;
float C_score;
float total;
//float aver;
float sch;
};
struct student stu[50];
void menu();
void base();
void score();
void text();
void in();
void delet();
void updet();
void select();
void print();
void max();
void cut();
void scholarship();
void goodbye();
//系统操作
int main()
{
int n=9;
while(n)
{
menu();
printf("请选择:\n");
scanf("%d",&n);
if(n>=1&&n<=4)
{
switch(n)
{
case 1:base();break;
case 2:score();break;
case 3:text();break;
case 4:goodbye();break;
}
}
else
{
printf("\n");
printf("请重新输入:");
scanf("%d",&n);
}
}
return 0;
}
//查看奖学金
void scholarship(){
int i,m=0;
FILE *fp;
if((fp=fopen("stu.txt","rb"))==NULL)
{
printf("文件打开失败\n");
return;
}
while(!feof(fp))
{
if(fread(&stu[m],LEN,1,fp)==1)
{
m++;
}
}
fclose(fp);
if(m==0)
{
printf("文件中没有内容\n");
}
printf("学号\t姓名\t班级\t性别\t奖学金\n");
for(i=0;i<m;i++)
{
printf("%3d\t%s\t%s\t%s\t%.2f\n",stu[i].num,stu[i].name,stu[i].clas,stu[i].sex,stu[i].sch);
}
}
//文件管理
void text(){
int n;
printf("\n");
for(int i=0;i<60;i++){
printf("*");
}
printf("\n");
for(int i=0;i<21;i++){
printf(" ");
}
printf("1 浏览学生信息\n");
for(int i=0;i<21;i++){
printf(" ");
}
printf("2 查看奖学金\n");
for(int i=0;i<21;i++){
printf(" ");
}
printf("3 退出\n");
for(int i=0;i<60;i++){
printf("*");
}
printf("\n");
printf("请输入: ");
scanf("%d",&n);
if(n>=1 && n<=3){
switch(n){
case 1:print();break;
case 2:scholarship();break;
case 3:break;}}
else{
printf("\n");
printf("请重新输入:");
text();
}
}
// 退出管理系统
void goodbye()
{
system("cls");
printf("欢迎下次使用学生信息管理系统!");
exit(0);// 结束程序
}
//学生成绩信息
void score(){
int n;
printf("\n");
for(int i=0;i<60;i++){
printf("*");
}
printf("\n");
for(int i=0;i<21;i++){
printf(" ");
}
printf("1 显示最好成绩\n");
for(int i=0;i<21;i++){
printf(" ");
}
printf("2 分组统计成绩\n");
for(int i=0;i<21;i++){
printf(" ");
}
printf("3 退出\n");
for(int i=0;i<60;i++){
printf("*");
}
printf("\n");
printf("请输入: ");
scanf("%d",&n);
if(n>=1 && n<=3){
switch(n){
case 1:max();break;
case 2:cut();break;
case 3:break;}}
else{
printf("\n");
printf("请重新输入:");
score();
}
}
//学生基本信息
void base(){
int n=1;
printf("\n");
for(int i=0;i<60;i++){
printf("*");
}
printf("\n");
for(int i=0;i<21;i++){
printf(" ");
}
printf("1 录入学生信息\n");
for(int i=0;i<21;i++){
printf(" ");
}
printf("2 删除学生信息\n");
for(int i=0;i<21;i++){
printf(" ");
}
printf("3 修改学生信息\n");
for(int i=0;i<21;i++){
printf(" ");
}
printf("4 查询学生信息\n");
for(int i=0;i<21;i++){
printf(" ");
}
printf("5 显示学生信息\n");
for(int i=0;i<21;i++){
printf(" ");
}
printf("6 退出\n");
for(int i=0;i<60;i++){
printf("*");
}
printf("\n");
printf("请输入: ");
scanf("%d",&n);
if(n>=1 && n<=6){
switch(n){
case 1:in();break;
case 2:delet();break;
case 3:updet();break;
case 4:select();break;
case 5:print();break;
case 6:break; }}
else{
printf("\n");
printf("请重新输入:");
base();
}
}
//目录
void menu()
{
printf("\n");
for(int i=0;i<60;i++){
printf("*");
}
printf("\n");
for(int i=0;i<24;i++){
printf(" ");
}
printf("学生管理系统\n");
for(int i=0;i<21;i++){
printf(" ");
}
printf("1 学生基本信息管理\n");
for(int i=0;i<21;i++){
printf(" ");
}
printf("2 学生成绩信息管理\n");
for(int i=0;i<21;i++){
printf(" ");
}
printf("3 文件操作\n");
for(int i=0;i<21;i++){
printf(" ");
}
printf("4 退出\n");
for(int i=0;i<60;i++){
printf("*");
}
printf("\n");
}
//录入学生信息
void in()
{
void print();
FILE *fp;
int i, m=0;
char ch[2];
if((fp=fopen("stu.txt","rb"))==NULL)
{
printf("文件打开失败\n");
return;
}
while(!feof(fp))
{
if(fread(&stu[m],LEN,1,fp)==1)
{
m++;
}
}
fclose(fp);
if(m==0)
{
printf("文件没有内容\n");
}
else
{
print();
}
if((fp=fopen("stu.txt","ab+"))==NULL)
{
printf("文件打开失败\n");
return;
}
printf("输入学生信息(y/n);\n");
scanf("%s",ch);
while(strcmp(ch,"y")==0||strcmp(ch,"Y")==0)
{
printf("number:\n");
scanf("%3d",&stu[m].num);
for(i=0;i<m;i++)
{
if(stu[i].num==stu[m].num)
{
printf("您的信息已存在\n");
fclose(fp);
getchar();
return;
}
}
printf("name:\n");
scanf("%s",stu[m].name);
printf("class:\n");
scanf("%s",stu[m].clas);
printf("sex:\n");
scanf("%s",stu[i].sex);
printf("Eng_score:\n");
scanf("%f",&stu[m].Eng_score);
printf("C_score:\n");
scanf("%f",&stu[m].C_score);
printf("Scholarship:\n");
scanf("%f",&stu[m].sch);
stu[i].total=stu[i].C_score+stu[i].Eng_score;
if(fwrite(&stu[m],LEN,1,fp)!=1)
{
printf("不能保存\n");
getchar();
}
else
{
printf("信息保存成功\n");
m++;
}
printf("是否继续录入学生信息(y/n):");
scanf("%s",ch);
}
fclose(fp);
}
//删除学生信息
void delet()
{
void print();
FILE *fp;
int num,m=0;
int i,j;
int flag=0;
char ch[2];
if((fp=fopen("stu.txt","rb"))==NULL)
{
printf("文件打开失败\n");
return;
}
while(!feof(fp))
{
if(fread(&stu[m],LEN,1,fp)==1)
{
m++;
}
}
fclose(fp);
if(m==0)
{
printf("文件中没有学生信息\n");
}
else
{
print();
printf("请输入需要删除学生信息的学号:");
scanf("%d",&num);
}
for(i=0;i<m;i++)
{
if(stu[i].num==num)
{
printf("该学生已找到,是否删除(y/n):");
scanf("%s",ch);
if(strcmp(ch,"y")==0||strcmp(ch,"Y")==0)
{
for(j=i;j<m;j++)
{
stu[j]=stu[j+1];
}
m--;
flag=1;
if((fp=fopen("stu.txt","wb"))==NULL)
{
printf("文件打开失败\n");
return;
}
for(j=0;j<m;j++)
{
if(fwrite(&stu[j],LEN,1,fp)!=1)
{
printf("不能保存\n");
getchar();
}
}
fclose(fp);
printf("删除成功!\n");break;
}
else
{
printf("学生信息存在,不需要删除。");
break;
}
}
}
if(m==i&&flag==0)
{
printf("未找到该学生");
}
}
//修改学生信息
void updet()
{
void print();
int num;
char name[10];
char clas[20];
char sex[5];
float Eng_score;
float C_score;
float sch;
FILE *fp;
int m=0,a;
int i,j;
if((fp=fopen("stu.txt","rb"))==NULL)
{
printf("文件打开失败\n");
return;
}
while(!feof(fp))
{
if(fread(&stu[m],LEN,1,fp)==1)
{
m++;
}
}
fclose(fp);
if(m==0)
{
printf("文件中没有学生信息\n");
}
else
{
print();
printf("请输入需要修改学生信息的学号:");
scanf("%d",&num);
}
for(i=0;i<m;i++)
{
if(num==stu[i].num)
{
printf("1:学号,2:姓名,3:班级,4:性别,5:英语成绩,6:C语言成绩, 7:奖学金\n");
printf("该学生已被找到,请选择需要修改的内容(1-7):");
scanf("%d",&a);
while(a)
{
switch (a)
{
case 1:
printf("将%d学生的学号修改为:",num);
scanf("%d",&num);
stu[i].num=num;
for(j=i+1;j<m;j++)
{
if(stu[j].num==num)
{
printf("您修改的学号已存在\n");
getchar();
return;
}
}
break;
case 2:
printf("将%d学生的姓名修改为:",num);
scanf("%s",name);
strcpy(stu[i].name,name);
break;
case 3:
printf("将%d学生的班级修改为:",num);
scanf("%s",clas);
strcpy(stu[i].clas,clas);
break;
case 4:
printf("将%d学生的性别修改为:",num);
scanf("%s",sex);
strcpy(stu[i].sex,sex);
break;
case 5:
printf("将%d学生的英语成绩修改为:",num);
scanf("%f",&Eng_score);
stu[i].Eng_score=Eng_score;
stu[i].total=stu[i].C_score+stu[i].Eng_score;
// stu[i].aver=(stu[i].C_score+stu[i].Eng_score)/2;
break;
case 6:
printf("将%d学生的C语言成绩修改为:",num);
scanf("%f",&C_score);
stu[i].C_score=C_score;
stu[i].total=stu[i].C_score+stu[i].Eng_score;
// stu[i].aver=(stu[i].C_score+stu[i].Eng_score)/2;
break;
case 7:
printf("将%d学生的奖学金修改为:",num);
scanf("%f",&sch);
default:
printf("选择错误,请重新选择需要修改的内容:");
scanf("%d",&a);
break;
}
printf("请选择需要修改的内容(如果已修改完成请按0):");
scanf("%d",&a);
}
if((fp=fopen("stu.txt","wb"))==NULL)
{
printf("文件打开失败\n");
return;
}
for(j=0;j<m;j++)
{
if(fwrite(&stu[j],LEN,1,fp)!=1)
{
printf("不能保存\n");
getchar();
}
}
fclose(fp);
printf("修改成功!\n");
break;
}
}
if(m==i)
{
printf("未找到该学生\n");
}
}
//查询学生信息
void select()
{
int num,m=0;
int i;
FILE *fp;
if((fp=fopen("stu.txt","rb"))==NULL)
{
printf("文件打开失败\n");
return;
}
while(!feof(fp))
{
if(fread(&stu[m],LEN,1,fp)==1)
{
m++;
}
}
fclose(fp);
if(m==0)
{
printf("文件没有内容\n");
return;
}
printf("请输入学生学号进行查询:");
scanf("%d",&num);
for(i=0;i<m;i++)
{
if(num==stu[i].num)
{
printf("\n");
printf("该学生信息已被查到;\n");
printf("学号\t姓名\t班级\t性别\t英语成绩\tC语言成绩\t总成绩\t奖学金\n");
printf("%3d\t%s\t%s\t%s\t%.2f\t\t%.2f\t\t%.2f\t %.2f\n",stu[i].num,stu[i].name,stu[i].clas,stu[i].sex,stu[i].Eng_score,stu[i].C_score,stu[i].total,stu[i].sch);
break;
}
}
if(m==i)
{
printf("该学生信息不存在\n");
return;
}
}
//显示学生信息
void print()
{
int i,m=0;
FILE *fp;
if((fp=fopen("stu.txt","rb"))==NULL)
{
printf("文件打开失败\n");
return;
}
while(!feof(fp))
{
if(fread(&stu[m],LEN,1,fp)==1)
{
m++;
}
}
fclose(fp);
if(m==0)
{
printf("文件中没有内容\n");
}
printf("学号\t姓名\t班级\t性别\t英语成绩\tC语言成绩\t总成绩\t奖学金\n");
for(i=0;i<m;i++)
{
printf("%3d\t%s\t%s\t%s\t%.2f\t\t%.2f\t\t%.2f\t %.2f\n",stu[i].num,stu[i].name,stu[i].clas,stu[i].sex,stu[i].Eng_score,stu[i].C_score,stu[i].total,stu[i].sch);
}
}
//最大值
void max()
{
int i,j=0;
FILE *fp;
int m=0;
if((fp=fopen("stu.txt","rb"))==NULL)
{
printf("文件打开失败\n");
return;
}
while(!feof(fp))
{
if(fread(&stu[m],LEN,1,fp)==1)
{
m++;
}
}
fclose(fp);
if(m==0)
{
printf("文件中没有内容\n");
}
for(i=0;i<m;i++)
{
if(stu[i].total>stu[j].total)
j=i;
}
printf("总成绩成绩最高的同学是:\n");
printf("学号\t姓名\t班级\t性别\t英语成绩\tC语言成绩\t总成绩\t奖学金\n");
printf("%3d\t%s\t%s\t%s\t%.2f\t\t%.2f\t\t%.2f\t %.2f\n",stu[j].num,stu[j].name,stu[j].clas,stu[j].sex,stu[j].Eng_score,stu[j].C_score,stu[j].total,stu[j].sch);
}
//分组统计
void cut()
{
int i,j;
float n;
FILE *fp;
int m=0;
if((fp=fopen("stu.txt","rb"))==NULL)
{
printf("文件打开失败\n");
return;
}
while(!feof(fp))
{
if(fread(&stu[m],LEN,1,fp)==1)
{
m++;
}
}
fclose(fp);
if(m==0)
{
printf("文件中没有内容\n");
}
printf("请输入按总成绩分组的值:");
scanf("%f",&n);
printf("总成绩大于%.2f的同学有:\n",n);
printf("学号\t姓名\t班级\t性别\t英语成绩\tC语言成绩\t总成绩\t奖学金\n");
for(i=0;i<m;i++)
{
if(stu[i].total>=n)
printf("%3d\t%s\t%s\t%s\t%.2f\t\t%.2f\t\t%.2f\t %.2f\n",stu[i].num,stu[i].name,stu[i].clas,stu[i].sex,stu[i].Eng_score,stu[i].C_score,stu[i].total,stu[i].sch);
}
printf("总成绩小于%.2f的同学有:\n",n);
printf("学号\t姓名\t班级\t性别\t英语成绩\tC语言成绩\t总成绩t奖学金\n");
for(j=0;j<m;j++)
{
if(stu[j].total<n)
printf("%3d\t%s\t%s\t%s\t%.2f\t\t%.2f\t\t%.2f\t %.2f\n",stu[j].num,stu[j].name,stu[j].clas,stu[j].sex,stu[j].Eng_score,stu[j].C_score,stu[j].total,stu[i].sch);
}
}
三、主要问题
1、输入验证不足
所有菜单选项和输入(如学号、成绩)直接使用 scanf,未处理非数字输入(如字母),会导致程序崩溃或进入死循环。
2、全局数组 stu[50] 的缺陷
学生数量固定为50,无法动态扩展。
多函数直接操作全局变量,耦合度高,易引发数据不一致问题。
3、文件读取问题
使用 while(!feof(fp)) 读取文件会导致最后一条记录重复读取。
原因:feof 在读取结束后才返回 true,最后一次 fread 可能读取到无效数据。
四、优化
1、潜在逻辑错误
Bug 1:在 in() 函数中,录入性别时错误使用 i:
点击查看代码
scanf("%s", stu[i].sex); // 此时 i = m,可能越界
Bug 2:在 cut() 函数中,打印小于分组值的记录时错误引用 i:
点击查看代码
printf("%.2f\t %.2f\n", stu[j].total, stu[i].sch); // 应为 stu[j].sch
2、输入验证改进
方案:封装安全输入函数,使用 fgets + sscanf 处理输入。
点击查看代码
int safe_input_int(const char* prompt) {
char buffer[100];
int value;
while (1) {
printf("%s", prompt);
if (fgets(buffer, sizeof(buffer), stdin)) {
if (sscanf(buffer, "%d", &value) == 1) return value;
}
printf("输入无效,请重新输入!\n");
}
}
3、封改进菜单导航
方案:使用循环代替递归,避免栈溢出。
点击查看代码
void text() {
int n;
do {
// 打印菜单
n = safe_input_int("请输入: ");
switch(n) { ... }
} while (n < 1 || n > 3);
}
4、添加功能
按总成绩排序并显示学生信息
点击查看代码
两三百鸟: 02-24 19:52:38
// 按总成绩排序并显示学生信息
void sortAndPrintByTotal() {
int i, j, m = 0;
struct student temp;
FILE *fp;
if ((fp = fopen("stu.txt", "rb")) == NULL) {
printf("文件打开失败\n");
return;
}
while (!feof(fp)) {
if (fread(&stu[m], LEN, 1, fp) == 1) {
m++;
}
}
fclose(fp);
if (m == 0) {
printf("文件中没有内容\n");
return;
}
// 冒泡排序
for (i = 0; i < m - 1; i++) {
for (j = 0; j < m - i - 1; j++) {
if (stu[j].total < stu[j + 1].total) {
temp = stu[j];
stu[j] = stu[j + 1];
stu[j + 1] = temp;
}
}
}
printf("按总成绩从高到低排序后的学生信息:\n");
printf("学号\t姓名\t班级\t性别\t英语成绩\tC语言成绩\t总成绩\t奖学金\n");
for (i = 0; i < m; i++) {
printf("%3d\t%s\t%s\t%s\t%.2f\t\t%.2f\t\t%.2f\t %.2f\n", stu[i].num, stu[i].name, stu[i].clas, stu[i].sex, stu[i].Eng_score, stu[i].C_score, stu[i].total, stu[i].sch);
}
}
两三百鸟: 02-24 19:52:44
// 统计某班级的学生人数
void countStudentsByClass() {
char targetClass[20];
int i, m = 0, count = 0;
FILE *fp;
if ((fp = fopen("stu.txt", "rb")) == NULL) {
printf("文件打开失败\n");
return;
}
while (!feof(fp)) {
if (fread(&stu[m], LEN, 1, fp) == 1) {
m++;
}
}
fclose(fp);
if (m == 0) {
printf("文件中没有内容\n");
return;
}
printf("请输入要统计的班级:");
scanf("%s", targetClass);
for (i = 0; i < m; i++) {
if (strcmp(stu[i].clas, targetClass) == 0) {
count++;
}
}
printf("%s 班级的学生人数为:%d\n", targetClass, count);
}
统计某班级的学生人数
点击查看代码
void countStudentsByClass() {
char targetClass[20];
int i, m = 0, count = 0;
FILE *fp;
if ((fp = fopen("stu.txt", "rb")) == NULL) {
printf("文件打开失败\n");
return;
}
while (!feof(fp)) {
if (fread(&stu[m], LEN, 1, fp) == 1) {
m++;
}
}
fclose(fp);
if (m == 0) {
printf("文件中没有内容\n");
return;
}
printf("请输入要统计的班级:");
scanf("%s", targetClass);
for (i = 0; i < m; i++) {
if (strcmp(stu[i].clas, targetClass) == 0) {
count++;
}
}
printf("%s 班级的学生人数为:%d\n", targetClass, count);
}
计算所有学生的平均总成绩
点击查看代码
void calculateAverageTotal() {
int i, m = 0;
float totalSum = 0, average;
FILE *fp;
if ((fp = fopen("stu.txt", "rb")) == NULL) {
printf("文件打开失败\n");
return;
}
while (!feof(fp)) {
if (fread(&stu[m], LEN, 1, fp) == 1) {
totalSum += stu[m].total;
m++;
}
}
fclose(fp);
if (m == 0) {
printf("文件中没有内容\n");
return;
}
average = totalSum / m;
printf("所有学生的平均总成绩为:%.2f\n", average);
}
五、实现效果:




6、总结
输入验证
难点:用户输入可能包含非法字符(如字母、符号),直接使用 scanf 会导致程序崩溃。
解决:使用 fgets 和 sscanf 组合实现安全的输入验证。对字符串输入进行长度检查,避免缓冲区溢出。
花时间比较久的部分:件读写
原因:二进制文件的读写需要确保数据格式一致,调试文件操作问题耗时较长。解决:通过打印调试信息和逐步测试,确保文件读写正确。
在实现学生信息管理系统的过程中,可以从逆向软件工程的角度思考以下问题:
模块化设计
思考:如何将系统拆分为独立的模块(如数据管理、文件操作、界面显示等),以便于维护和扩展。
实践:将数据管理封装为独立模块。
将文件操作封装为独立模块。
将界面显示封装为独立模块。
错误处理
思考:如何在系统中处理各种错误(如文件打开失败、内存分配失败等),确保系统的健壮性。
实践:在文件操作和内存分配中添加错误检查。在用户输入中添加输入验证。

浙公网安备 33010602011771号