软件开发与创新第一次作业--学生信息管理系统改进

《学生信息管理系统》改进

一、项目名称与来源

某同学大作业

二、原项目运行

运行环境:
系统:Windows11 24H2
cpu:i7-13700
编译器:Dev c++ 5.11
运行结果:
image
image
image
image

点击查看代码
#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);
}
五、实现效果:

image
image
image
image

6、总结

输入验证
难点:用户输入可能包含非法字符(如字母、符号),直接使用 scanf 会导致程序崩溃。
解决:使用 fgets 和 sscanf 组合实现安全的输入验证。对字符串输入进行长度检查,避免缓冲区溢出。
花时间比较久的部分:件读写
原因:二进制文件的读写需要确保数据格式一致,调试文件操作问题耗时较长。解决:通过打印调试信息和逐步测试,确保文件读写正确。

在实现学生信息管理系统的过程中,可以从逆向软件工程的角度思考以下问题:
模块化设计
思考:如何将系统拆分为独立的模块(如数据管理、文件操作、界面显示等),以便于维护和扩展。
实践:将数据管理封装为独立模块。
将文件操作封装为独立模块。
将界面显示封装为独立模块。
错误处理
思考:如何在系统中处理各种错误(如文件打开失败、内存分配失败等),确保系统的健壮性。
实践:在文件操作和内存分配中添加错误检查。在用户输入中添加输入验证。

posted @ 2025-02-24 20:13  江寒懿  阅读(27)  评论(0)    收藏  举报