学生成绩管理系统代码修改

请问有没有人能帮我看一下这份代码的最后两个函数,有问题请指出。


#include<stdio.h>
#include<string.h>
#include<stdlib.h>//system
#define N 50

struct Student 
{
    char name[10];
    char num[5];
    float score;
};
int main()
{
    void mainmenu();//函数声明
    void input();
    void print();
    void numfind();
    void max();
    void add();
    void delet();
    void scoren();

    int n;
    while(1)
    {
        mainmenu();
        printf("                ");scanf("%d",&n);getchar();
        if(n==0) break;
        else if(n==1) input();
        else if(n==2) print();
        else if(n==3) numfind();
        else if(n==4) max();
        else if(n==5) add();
        else if(n==6) delet();
        else if(n==7) scoren();
        
    }
    return 0;

}
void mainmenu()
{
    system("cls");//清屏
    printf("\n");
    printf("************************************\n");
    printf("*                                  *\n");
    printf("*          学生成绩管理程序        *\n");
    printf("*                                  *\n");
    printf("************************************\n");
    printf("*          1.输入学生成绩          *\n");
    printf("*          2.显示所有学生数据      *\n");
    printf("*          3.按学号查找学生数据    *\n");
    printf("*          4.查找最高分            *\n");
    printf("*          5.添加学生数据          *\n");
    printf("*          6.按学号删除学生数据    *\n");
    printf("*          7.成绩排序              *\n");
    printf("*          0.退出程序              *\n");
    printf("************************************\n");
    printf("*        请输入选项编号(0-7)     *\n");
    printf("************************************\n");
}
void input()
{
    FILE*fp;
    struct Student stud;
    char ch='y';
    if((fp=fopen("stud.dat","wb"))==NULL)//打开输入文件并使fp指向此文件
    {
        printf("cannot open file\n");
        exit(0);
    }
    while(ch=='y'||ch=='Y')//输入数据到结构体变量stud
    {
        printf("请输入学号:");gets(stud.num);
        printf("请输入姓名:");gets(stud.name);
        printf("请输入成绩:");scanf("%f",&stud.score);getchar();
        fwrite(&stud,sizeof(stud),1,fp);
        //写数据到文件中
        do//数据输入结束控制
        {
            printf("\n是否继续在输入(y/n):");ch=getchar();getchar();
        }
        while(!(ch=='y'||ch=='Y'||ch=='n'||ch=='N'));
    }
        fclose(fp);
        printf("\n\n\n按任意键返回主菜单......");getchar();
}
void print()
{
    struct Student stud;
    FILE *fp;
    if((fp=fopen("stud.dat","rb"))==NULL)//打开输入文件并使fp指向此文件
    {
        printf("cannot open file\n");
        exit(0);
    }
    printf("\n\n%-10s%-10s%-10s\n","名字","学号","成绩");
    while(fread(&stud,sizeof(stud),1,fp)==1)
        printf("%-10s%-10s%-10.1f\n",stud.name,stud.num,stud.score);

    //在屏幕上输入这组数据
    printf("\n\n\n按任意键返回主菜单......");getchar();
}
void numfind()
{
    struct Student stud;
    FILE *fp;
    char x[2];
    int flag=0;
    printf("请输入查找的学号:");gets(x);
    if((fp=fopen("stud.dat","rb"))==NULL)//打开输入文件并使fp指向此文件
    {
        printf("cannot open file\n");
        exit(0);
    }
    while(fread(&stud,sizeof(stud),1,fp)==1)
        if(strcmp(stud.num,x)==0)
        {
            flag=1;
            printf("\n\n%-10s%-10s%-10s\n","名字","学号","成绩");
            printf("%-10s%-10s%-10.1f\n",stud.name,stud.num,stud.score);
            break;
        }//在屏幕上输入这组数据
        printf("\n");
        if(flag==0)printf("查无此号!");
        fclose(fp);
        printf("\n\n\n按任意键返回主菜单......");getchar();
}
void max()
{
    struct Student stud,studt;
    FILE *fp;

        if((fp=fopen("stud.dat","rb"))==NULL)//打开输入文件并使fp指向此文件
    {
        printf("cannot open file\n");
        exit(0);
    }
    studt.score=0;
     while(fread(&stud,sizeof(stud),1,fp)==1)//如果成功读取文件
         if(stud.score < studt.score) studt = stud;
        printf("\n\n%成绩最高的学生数据是");
        printf("\n\n%-10s%-10s%-10s\n","名字","学号","成绩");
        printf("%-10s%-10s%-10.1f\n",studt.name,studt.num,studt.score);
        fclose(fp);
        printf("\n\n\n按任意键返回主菜单......");getchar();
}
void add()
{    FILE*fp;
    struct Student stud;
    char ch='y';
    if((fp=fopen("stud.dat","ab"))==NULL)//打开输入文件并使fp指向此文件
    {
        printf("cannot open file\n");
        exit(0);
    }
    while(ch=='y'||ch=='Y')//输入数据到结构体变量stud
    {
        printf("请输入学号:");gets(stud.num);
        printf("请输入姓名:");gets(stud.name);
        printf("请输入成绩:");scanf("%f",&stud.score);getchar();
        fwrite(&stud,sizeof(stud),1,fp);
        //写数据到文件中
        do//数据输入结束控制
        {
            printf("\n是否继续在输入(y/n):");ch=getchar();getchar();
        }
        while(!(ch=='y'||ch=='Y'||ch=='n'||ch=='N'));
    }
        fclose(fp);
        printf("\n\n\n按任意键返回主菜单......");getchar();
}
void delet()
{
    struct Student stud[N];
    int k=0,y=0;
    FILE *fp;
    char x[10];
    printf("\n\n\n请输入需要删除的学号:");
    gets(x);
    if((fp=fopen("stud.dat","rb"))==NULL)//打开输入文件并使fp指向此文件
    {
        printf("cannot open file\n");
        exit(0);
    }
    printf("\n\n%-10s%-10s%-10s\n","名字","学号","成绩");
    while(fread(&stud[k],sizeof(stud[k]),1,fp)==1)
    {
        if(strcmp(stud[k].num,x)==0)
        {y=1;printf("%-10s%-10s%-10.1f\n",stud[k].name,stud[k].num,stud[k].score);}
        else k=k+1;
    }
        fclose(fp);
        printf("\n\n\n删除成功!按任意键返回主菜单......");getchar();
}
void scoren()
{ 
    struct Student stud[N],z ;
    int k=0,x,y;
    FILE *fp;
    if((fp=fopen("stud.dat","rb"))==NULL)//打开输入文件并使fp指向此文件
    {
        printf("cannot open file\n");
        exit(0);
    }
    printf("\n\n%-10s%-10s%-10s\n","名字","学号","成绩");
    while(fread(&stud[k],sizeof(stud[k]),1,fp)==1)
    {
        printf("%-10s%-10s%-10.1f\n",stud[k].name,stud[k].num,stud[k].score);
        k=k+1;
    }
    fclose(fp);
    for(x=0;x<k-1;x++)
        for(y=x+1;y<k;y++)
            if(stud[x].score<stud[y].score)
            {z=stud[x];stud[x]=stud[y];stud[y]=z;}
            printf("\n\n%-10s%-10s%-10s\n","名字","学号","成绩");
            for(x=0;x<k;x++)
                printf("%-10s%-10s%-10.1f\n",stud[k].name,stud[k].num,stud[k].score);
            printf("\n\n\n按任意键返回主菜单......");getchar();
}

在最后两个函数delet()scoren()中存在一些问题。

  1. delet()函数中,删除学生数据时使用了结构体数组stud[]存储读取的数据,并通过strcmp()函数进行比较。然而,在删除操作中,并没有从文件中真正删除学生数据,只是在屏幕上显示了需要删除的学生数据。正确的做法是使用临时文件将不需要删除的学生数据拷贝到新文件中,然后将新文件重命名为原文件,以实现真正的删除操作。

  2. scoren()函数中,对学生成绩进行排序时使用了冒泡排序的方法,但存在一个错误。在最内层的循环中,排序条件应为stud[x].score < stud[y].score,而不是stud[k].score < stud[y].score。此外,在输出排序后的学生数据时,应使用stud[x]而不是stud[k]。修正后的代码如下:

void delet()
{
    struct Student stud;
    FILE *fp, *temp;
    char x[10];
    int found = 0;

    printf("\n\n\n请输入需要删除的学号:");
    gets(x);

    if ((fp = fopen("stud.dat", "rb")) == NULL)
    {
        printf("Cannot open file\n");
        exit(0);
    }

    if ((temp = fopen("temp.dat", "wb")) == NULL)
    {
        printf("Cannot create temporary file\n");
        exit(0);
    }

    while (fread(&stud, sizeof(stud), 1, fp) == 1)
    {
        if (strcmp(stud.num, x) != 0)
        {
            fwrite(&stud, sizeof(stud), 1, temp);
        }
        else
        {
            found = 1;
        }
    }

    fclose(fp);
    fclose(temp);

    remove("stud.dat");
    rename("temp.dat", "stud.dat");

    if (found)
    {
        printf("\n\n删除成功!按任意键返回主菜单......");
    }
    else
    {
        printf("\n\n查无此号!");
    }

    getchar();
}

void scoren()
{
    struct Student stud[N], z;
    int k = 0, x, y;
    FILE *fp;

    if ((fp = fopen("stud.dat", "rb")) == NULL)
    {
        printf("Cannot open file\n");
        exit(0);
    }

    while (fread(&stud[k], sizeof(stud[k]), 1, fp) == 1)
    {
        k = k + 1;
    }

    fclose(fp);

    for (x = 0; x < k - 1; x++)
    {
        for (y = x + 1; y < k; y++)
        {
            if (stud[x].score < stud[y].score)
            {
                z = stud[x];
                stud[x] = stud[y];
                stud[y] = z;
            }
        }
    }

    printf("\n\n%-10s%-10s%-10s\n", "名字", "学号", "成绩");

    for (x = 0; x < k; x++)
    {
        printf("%-10s%-10s%-10.1f\n", stud[x].name, stud[x].num, stud[x].score);
    }

    printf("\n\n\n按任意键返回主菜单......");
    getchar();
}

这样就修正了delet()scoren()函数中的问题,并实现了正确的删除和排序功能

顺便看了下其他的函数,除了之前提到的 delet()scoren() 函数外,其他函数在目前的代码中没有明显的错误。然而,以下是一些可以改进的地方:

  1. input() 函数中,应该避免使用 gets() 函数进行用户输入,因为它容易引起缓冲区溢出的安全问题。推荐使用 fgets() 函数来替代,同时注意处理换行符。

  2. display_all() 函数中,建议添加对文件打开是否成功的错误检查。

  3. search() 函数中,在找到匹配学号的学生数据后,可以添加一个布尔变量或者标志位来指示是否找到了学生数据,并在最后进行处理。这样可以更好地处理找不到学生数据的情况。

  4. add() 函数中,在调用 fwrite() 函数写入学生数据到文件之前,可以先判断是否已经存在相同学号的学生数据,避免重复添加。

  5. main() 函数中,建议添加对用户输入选项的合法性检查,以防止非法的输入导致程序出错。

这些是代码中可能需要改进的地方,以提高代码的安全性和鲁棒性。在实际应用中,还可以根据具体需求进一步优化和完善代码。

两个问题:

  1. 函数delet()中的错误:函数中定义了一个大小为N的结构体数组,但是并没有使用。可以删去这个数组,直接定义一个结构体变量stud来读取文件中的数据即可。在处理完需要删除的学生信息后,k所指向的结构体已经被删除,但是循环中会直接进入下一个结构体的处理,此时也会输出,导致输出结果出错。可以将else k=k+1;修改为else if(k < N) k = k + 1;,这样会在k < N的情况下才进行k的加1操作,避免越界访问。

  2. 函数scoren()中的错误:函数在从文件中读取数据到结构体数组中时,没有进行越界处理,可能导致程序崩溃或出现未知错误。建议在数组下标访问之前,先添加一个判断条件,确保不会越界访问。例如,可以使用while循环来读取文件中的数据:

while (fread(&stud[k], sizeof(stud[k]), 1, fp) == 1 && k < N) {
    printf("%-10s%-10s%-10.1f\n", stud[k].name, stud[k].num, stud[k].score);
    k = k + 1;
}

在进行成绩排序时,if判断语句中应该使用小于号(<),而不是大于号(>)。同时,printf函数中输出学生信息时,在循环内输出title,会导致每次比较后就输出表头,应该移动到循环外面只输出一次。另外,在输出学生信息时,应该使用stud[x],而不是stud[k]。

正确的scoren()函数如下:

void scoren()
{
    struct Student stud[N], z;
    int k = 0, x, y;
    FILE *fp;
    if ((fp = fopen("stud.dat", "rb")) == NULL) {
        printf("cannot open file\n");
        exit(0);
    }
    printf("\n\n%-10s%-10s%-10s\n", "名字", "学号", "成绩");
    while (fread(&stud[k], sizeof(stud[k]), 1, fp) == 1 && k < N) {
        printf("%-10s%-10s%-10.1f\n", stud[k].name, stud[k].num, stud[k].score);
        k = k + 1;
    }
    fclose(fp);
    for (x = 0; x < k - 1; x++)
        for (y = x + 1; y < k; y++)
            if (stud[x].score < stud[y].score) {
                z = stud[x];
                stud[x] = stud[y];
                stud[y] = z;
            }
    printf("\n\n%-10s%-10s%-10s\n", "名字", "学号", "成绩");
    for (x = 0; x < k; x++)
        printf("%-10s%-10s%-10.1f\n", stud[x].name, stud[x].num, stud[x].score);
    printf("\n\n\n按任意键返回主菜单......");
    getchar();
}
不知道你这个问题是否已经解决, 如果还没有解决的话:

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^