C语言-学生成绩管理

前言

这篇文章和代码是专门针对下方学生成绩管理这个题目,使用的语言为C
全部的代码为博主独立完成,不存在抄袭的情况,如有雷同纯属巧合。
本代码可能含有BUG,若出现BUG的话可在文章下方评论。

一、题目信息

有N名学生,每名学生含有如下信息:学号、姓名、某四门课的成绩,并计算其总分,用一结构体数组表示之。然后实现以下功能:
(1)将这些数据存放至文件stuf.dat中;
(2)将文件中的数据读出至结构体数组中,并显示之;
(3)输出总分最高分和最低分的名字;
(4)输出总分在340分,单科成绩不低于80分的名单;
(5)求出各科平均分数;
(6)按总分排名;
(7)输出补考名单并存入文件。

二、生成测试数据-C语言

  • 因为每次输入学生数据的时候很费力,得一直打,还容易打错,所以就弄了一个可随机的学生数据。
  • 生成测试数据的代码生成的学生数据仅在本题目中使用,使用到了随机数生成的知识。

C语言笔记-指定范围下随机数的生成
1.1
1.2
在这里插入图片描述

/*
代码作者:小狐狸
代码介绍:
生成的学生数据student.txt仅在学生信息管理系统中使用,
你可以在生成学生数据后打开student.txt文件直接复制黏贴即可.

生成stuf.dat文件与student.txt文件的内容相同,
stuf.dat可移动到学生信息管理主程序.c的目录下使用.


生成从a~(a+b-1)的随机数赋值给Y:
1. srand((int)time(NULL))
2. Y=rand()%b+a;
*/
#include<stdio.h>
#include<stdlib.h>  //随机数、清屏使用需要的文件头
#include<time.h>    //随机数需要的文件头
#define OK 1
#define ERROR -1
#define Max 99
int CreateTest(int N,int Len)//创建测试学生数据,并存入student.txt和stuf.dat文件,N为学生个数,Len为学生学号长
{
    char Name[Max]={'f','o','x'};//若需要变更学生姓名在此处变更即可
    FILE *op,*op2;//文件指针
    op=fopen("student.txt","w");//以重建模式打开文件
    op2=fopen("stuf.dat","w");//以重建模式打开文件
    int i,j;
    srand((int)time(NULL));//设置随机数种子
    fprintf(op,"%d\n",N);//第一行为文件中学生的总数
    fprintf(op2,"%d\n",N);//第一行为文件中学生的总数
    for(i=1;i<=N;i++)//学生总测试数
    {
        for(j=1;j<=Len;j++)//学号
        {
            int fox;//临时变量
            if(j==1)//首位不为0,从1-9选择
            {
                fox=rand()%9+1;//生成从1-9的随机数
                fprintf(op,"%d",fox);//存入student.txt
                fprintf(op2,"%d",fox);//存入stuf.dat
            }
            else//从0-9选择
            {
                fox=rand()%9;//生成从0-9的随机数
                fprintf(op,"%d",fox);//存入student.txt
                fprintf(op2,"%d",fox);//存入stuf.dat
            }
        }
        fprintf(op," ");
        fprintf(op2," ");
        int score1,score2,score3,score4;
        score1=rand()%100+1;//生成从1-100的随机数
        score2=rand()%100+1;
        score3=rand()%100+1;
        score4=rand()%100+1;
        //student.txt文件操作
        fprintf(op,"%s%d ",Name,i);//姓名
        fprintf(op,"%d ",score1);//成绩1
        fprintf(op,"%d ",score2);//成绩2
        fprintf(op,"%d ",score3);//成绩3
        fprintf(op,"%d\n",score4);//成绩4
        //stuf.dat文件操作
        fprintf(op2,"%s%d ",Name,i);//姓名
        fprintf(op2,"%d ",score1);//成绩1
        fprintf(op2,"%d ",score2);//成绩2
        fprintf(op2,"%d ",score3);//成绩3
        fprintf(op2,"%d\n",score4);//成绩4
    }
    fclose(op);
    return OK;
}
int main()
{

    while(1)
    {
        int fox;//临时变量
        printf("---------------<学生随机数据生成系统>-----------------\n");
        printf("|       0. 退出系统                                  |\n");
        printf("|       1. 生成新的数据存入student.txt和stuf.dat文件 |\n");
        printf("|       2. 清屏                                      |\n");
        printf("------------------------------------------------------\n");
        scanf("%d",&fox);
        if(fox==0) break;
        else if(fox==1)
        {
            int N;//学生总数
            int Len;//学号长度
            printf("测试学生总数: ");
            scanf("%d",&N);
            printf("学生学号长度: ");
            scanf("%d",&Len);
            CreateTest(N,Len);
            printf("创建成功,请到student.txt中查看!\n");
        }
        else system("cls");
    }
    return OK;
}

三、学生成绩管理-C语言

代码所必须的注释都已经写在代码开头和代码中,删除注释代码前请先浏览一遍注释。
考虑到课设老师可能会要求多写一些功能,所以就添加了一个功能10,用于查找各科不及格学生

[1]. 除了文件导入功能的效果展示

2.1

[2]. 文件导入功能展示

在这里插入图片描述

[3]. 代码

/*
代码作者:小狐狸
代码介绍:
若作为作业进行提交的话,建议对某些变量名进行变更.
此代码仅为了实现题目要求的功能,需要拓展的话可自己设计新的函数.
对菜单函树Menu()进行提示修改,并添加到main()主函数的switch()语句中即可.

各个函数是按菜单中数字顺序进行放置,可根据主菜单中所需功能查找对应函数位置
代码开头的注释可自行删除.
经过测试若学号或姓名达到8位或8位以上的字符时,数据将会不对齐

若使用%s进行输入字符串时,取址符'&'可进行省略,
strcpy(字符串A,字符串B),将字符串B复制给字符串A.
文件当中仅保存学生总数、学号、姓名、成绩1、成绩2、成绩3、成绩4

排序部分使用的是冒泡排序,若想要运算的效率更高的话,
可以采用基数排序、归并排序、快速排序、堆排序、简单选择排序、希尔排序、直接插入排序算法.

Windows系统下OS命令行中清屏: cls
c语言中清屏: system('cls');

文件操作全流程:
1. FILE *文件指针=fopen("文件路径","操作方式")
常用操作方式有以下三种。
w: 为重新创建文件并写入
r: 为只读取文件,不对文件内容进行修改,要求文件必须存在否则返回NULL
a: 为追加内容到文件末尾
+: 可读可写,和w、r、a进行组合而不能单独存在,即w+、a+、r+

2.
将变量内容存入: fprintf(文件指针,"%s",变量);  //%s表示字符串型变量
读取内容到变量: fscanf(文件指针,"%s",变量);
每次的存入和读取类似于排队,前者被存入或读取后,
下一次的存入或读取将会跳过已操作的那些,
文件中以空白符为两个不同内容的分隔,
空格、换行、制表符(tab)都算是空白符
如: tu r中tu和r被空格隔开,tu若被fscanf()取出一次后,
    下一次的fscanf()读取的是r,fprintf()与fscanf()类似

3. 关闭文件: fclose(文件指针);
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define OK 1
#define ERROR -1
#define Max 99
struct
{
    char Number[Max];//学号
    char Name[Max];//姓名
    int Score1;//成绩1
    int Score2;//成绩2
    int Score3;//成绩3
    int Score4;//成绩4
    int All;//四科成绩总分
    int Avg;//平均分
}STU[Max],FOX[Max],NEW[Max];//学生结构体数组,下标从1开始
//STU用于存储学生数据,FOX、NEW为临时使用的结构体数组
int Menu();//菜单显示
int InputStudent(int N);//输入学生信息,N为学生总数
int PrintStudent(int N);//显示学生信息,N为学生总数
int Upload(int N);//将结构体数组中的数据存入文件,N为学生总数
int AddUpload(int N);//将学生信息存入文件末尾,N为学生总数
int Download();//将文件数据读出至结构体数组,返回值为学生总数
int HighLowName(int N);//输出最高分和最低分的名字,N为学生总数
int PrintSix(int N);//输出总分在340分,单科成绩不低于80分的名单
int PrintAverage(int N);//计算所有学生的平均分并显示
int PrintLevel(int N);//按总分进行排名并打印,N为学生总数
//未使用的函数:int PrintLevel2(int N);//按总分进行排名并打印,N为学生总数
int UploadFail(char loser[],char course[]);//将需要补考的名单存入文件fail.txt,loser存储不及格学生的姓名,course为该学生不及格的科目.
int Fail(int N);//将需要补考的名单进行打印
int ScoreFail(int N);//打印指定科目不及格的学生
int main()
{
    int N=0;//学生总数,N不能放于while循环中,否则进行一次循环后.N值将会改变
    while(1)
    {
        int fox;//临时变量
        Menu();//主菜单显示
        printf("请选择: ");
        scanf("%d",&fox);
        if(fox==0) break;//退出操作
        switch(fox)
        {
            case 1://输入学生信息
                {
                    while(1)//确保N值≥0,当N=0时将不会执行输入学生信息
                    {
                        printf("学生总数(退出请输入0): ");
                        scanf("%d",&N);
                        if(N<0)//N为负值时
                            printf("请输入≥0的数!");
                        else break;
                    }
                    InputStudent(N);
                }
                break;
            case 2://显示学生信息
                {
                    if(N==0)//没有学生信息时
                    {
                        printf("请先输入学生信息!\n");
                        break;
                    }
                    else   PrintStudent(N);
                }
                break;
            case 3://将学生数据存入stuf.dat,若已存在则添加至末尾
                {
                    FILE *Fox;//临时文件指针
                    if((Fox=fopen("stuf.dat","r"))!=NULL)//若文件存在时
                    {
                        AddUpload(N);//将数据添加到文件末尾
                    }
                    else//若文件不存在时直接存入
                        Upload(N);
                }
                break;
            case 4://将文件数据读出至结构体
                {
                    FILE *Fox;//临时文件指针
                    if((Fox=fopen("stuf.dat","r"))==NULL)//若文件不存在时
                    {
                        printf("stuf.dat文件不存在,请先创建一个再执行此操作!\n");
                    }
                    else//文件存在时
                    {
                        N=Download();//返回一个文件中的学生总数
                        if(N==0)//当文件中的学生人数为0时
                            printf("stuf.dat文件中没有学生信息!\n");
                    }
                }
                break;
            case 5://输出总分最高分和总分最低分的名字
                {
                    HighLowName(N);
                }
                break;
            case 6://输出总分在340分,单科成绩不低于80分的名单
                {
                    PrintSix(N);
                }
                break;
            case 7://求出每个学生的各科平均数并显示
                {
                    PrintAverage(N);
                }
                break;
            case 8://按总分排名并打印
                {
                    PrintLevel(N);//使用NEW数组来排序和打印
                }
                break;
            case 9://输出补考名单并存入文件fail.txt
                {
                    Fail(N);
                }
                break;
            case 10://打印指定科目不及格的学生
                {
                    ScoreFail(N);
                }
                break;
            case 11://清屏
                {
                    system("cls");//需要使用头文件#include<stdlib.h>才不会报错
                }
                break;
            default: break;
        }
    }
    printf("退出成功!\n");
    return 0;
}
int Menu()//菜单显示
{
    printf("---------------------------------------------------------------\n");
    printf("|       0. 退出系统                                           |\n");
    printf("|       1. 输入学生信息                                       |\n");
    printf("|       2. 显示学生信息                                       |\n");
    printf("|       3. 将学生数据存入stuf.dat,若已有数据则添加至末尾      |\n");
    printf("|       4. 将文件数据导出至结构体数组                         |\n");
    printf("|       5. 输出总分最高分和最低分的名字                       |\n");
    printf("|       6. 输出总分在340分,单科成绩不低于80分的名单           |\n");
    printf("|       7. 求出各科平均分数并打印                             |\n");
    printf("|       8. 按总分排名并打印                                   |\n");
    printf("|       9. 输出补考名单并存入文件fail.txt                     |\n");
    printf("|       10.打印指定科目不及格的学生名单                       |\n");
    printf("|       11. 清屏                                              |\n");
    printf("---------------------------------------------------------------\n");
    return OK;
}
int InputStudent(int N)//输入学生信息,N为学生总数
{
    int i;
    if(N<=0)
        return ERROR;
    printf("请按学号 姓名 成绩1 成绩2 成绩3 成绩4填写!\n");
    for(i=1;i<=N;i++)//将所有学生数据存入结构体数组
    {
        printf("第%d名学生:\n",i);
        scanf("%s",STU[i].Number);//学号
        scanf("%s",STU[i].Name);//姓名
        scanf("%d",&STU[i].Score1);//成绩1
        scanf("%d",&STU[i].Score2);//成绩2
        scanf("%d",&STU[i].Score3);//成绩3
        scanf("%d",&STU[i].Score4);//成绩4
        STU[i].All=STU[i].Score1+STU[i].Score2+STU[i].Score3+STU[i].Score4;//计算总分
    }
    return OK;
}
int PrintStudent(int N)//显示学生信息,N为学生总数
{
    int i;
    if(N<=0)
        return ERROR;
    printf("=============================================<分隔线>=======================================================\n");
    printf("学号\t\t姓名\t\t成绩1\t\t成绩2\t\t成绩3\t\t成绩4\t\t总分\n");
    for(i=1;i<=N;i++)
    {
        printf("%s\t\t",STU[i].Number);//学号
        printf("%s\t\t",STU[i].Name);//姓名
        printf("%d\t\t",STU[i].Score1);//成绩1
        printf("%d\t\t",STU[i].Score2);//成绩2
        printf("%d\t\t",STU[i].Score3);//成绩3
        printf("%d\t\t",STU[i].Score4);//成绩4
        STU[i].All=STU[i].Score1+STU[i].Score2+STU[i].Score3+STU[i].Score4;//计算总分
        printf("%d\n",STU[i].All);//总分
    }
    printf("=============================================<分隔线>=======================================================\n");
    printf("显示成功!\n");
    return OK;
}
int Upload(int N)//将结构体数组中的数据存入文件,N为学生总数
{
    FILE *op;//文件指针,
    if((op=fopen("stuf.dat","w"))==NULL)//文件指针创建失败时
        return ERROR;
    int i;
    fprintf(op,"%d\n",N);//将学生人数存入文件第一行
    for(i=1;i<=N;i++)//将学生信息存入文件
    {
        fprintf(op,"%s ",STU[i].Number);//学号
        fprintf(op,"%s ",STU[i].Name);//姓名
        fprintf(op,"%d ",STU[i].Score1);//第一门成绩
        fprintf(op,"%d ",STU[i].Score2);//第二门成绩
        fprintf(op,"%d ",STU[i].Score3);//第三门成绩
        fprintf(op,"%d ",STU[i].Score4);//第四门成绩
    }
    fclose(op);
    return OK;
}
int AddUpload(int N)//将学生信息存入文件末尾,N为学生总数
{//使用此函数前需保证stuf.dat已存在
    if(N<=0)
        return ERROR;
    FILE *op;//文件指针
    int i,j;
    int n;//文件当中的学生数
    op=fopen("stuf.dat","r");//只读形式
    fscanf(op,"%d",&n);//由于需要变更文件首行的学生总数,所以需要重建文件
    for(i=1;i<=n;i++)//将文件内容先暂存FOX数组
    {
        fscanf(op,"%s",FOX[i].Number);//学号
        fscanf(op,"%s",FOX[i].Name);//姓名
        fscanf(op,"%d",&FOX[i].Score1);//成绩1
        fscanf(op,"%d",&FOX[i].Score2);//成绩2
        fscanf(op,"%d",&FOX[i].Score3);//成绩3
        fscanf(op,"%d",&FOX[i].Score4);//成绩4
    }
    fclose(op);
    for(i=N+1,j=2;i<=N+n;j++,i++)//将STU数据添加到FOX数据中
    {
        strcpy(FOX[i].Number,STU[j].Number);//学号
        strcpy(FOX[i].Name,STU[j].Name);//姓名
        FOX[i].Score1=STU[j].Score1;//成绩1
        FOX[i].Score2=STU[j].Score2;//成绩2
        FOX[i].Score3=STU[j].Score3;//成绩3
        FOX[i].Score4=STU[j].Score4;//成绩4
        FOX[i].All=STU[j].All;//总分
    }
    N+=n;//添加学生总数
    op=fopen("stuf.dat","w");//重建形式
    fprintf(op,"%d\n",N);
    for(i=1;i<=N;i++)//将学生信息存入文件
    {
        fprintf(op,"%s ",FOX[i].Number);//学号
        fprintf(op,"%s ",FOX[i].Name);//姓名
        fprintf(op,"%d ",FOX[i].Score1);//成绩1
        fprintf(op,"%d ",FOX[i].Score2);//成绩2
        fprintf(op,"%d ",FOX[i].Score3);//成绩3
        fprintf(op,"%d ",FOX[i].Score4);//成绩4
    }
    fclose(op);
    return OK;
}
int Download()//将文件数据读出至结构体数组,返回值为学生总数
{//因为需要返回N的值,所以使用此函数前.需要先验证文件stuf.dat是否存在
    FILE *op;
    int N=0;
    int i;
    op=fopen("stuf.dat","r");
    fscanf(op,"%d",&N);//读取文件第一行的学生总数
    for(i=1;i<=N;i++)
    {
        fscanf(op,"%s",STU[i].Number);//读取学号
        fscanf(op,"%s",STU[i].Name);//读取姓名
        fscanf(op,"%d",&STU[i].Score1);//读取成绩1
        fscanf(op,"%d",&STU[i].Score2);//读取成绩2
        fscanf(op,"%d",&STU[i].Score3);//读取成绩3
        fscanf(op,"%d",&STU[i].Score4);//读取成绩4
    }
    fclose(op);
    return N;//返回学生总数
}
int HighLowName(int N)//输出最高分和最低分的名字,N为学生总数
{
    if(N<0)
        return ERROR;
    int high;//标记总分最高学生的下标
    int low;//标记总分最低学生的下标
    int i;
    int fox=STU[1].All;//临时变量
    for(i=1;i<=N;i++)//查找总分最高学生的下标
    {
        if(fox<STU[i].All)
        {
            fox=STU[i].All;
            high=i;
        }
    }
    for(i=1;i<=N;i++)//查找总分最低学生的下标
    {
        if(fox>STU[i].All)
        {
            fox=STU[i].All;
            low=i;
        }
    }
    printf("总分最高的学生: %s\n",STU[high].Name);
    printf("总分最低的学生: %s\n",STU[low].Name);
    return OK;
}
int PrintSix(int N)//输出总分在340分,单科成绩不低于80分的名单
{
    if(N<=0)
        return ERROR;
    int i;
    int sum=0;
    int flag=0;//若学生中有符合条件的,flag为1
    printf("总分在340分,且成绩不低于80分的学生如下:\n");
    for(i=1;i<=N;i++)//在STU结构体数组中循环遍历符合条件的学生
    {
        if(STU[i].All==340&&STU[i].Score1>=80&&STU[i].Score2>=80&&STU[i].Score3>=80&&STU[i].Score4>=80)//符合条件时
        {
            printf("%d. %s ",i,STU[i].Name);
            sum++;
            flag=1;
        }
        if(sum%5==0&&flag==1)//每五个学生姓名为一行,当没有符合条件的学生时不需要换行
            printf("\n");
    }
    if(flag==0)
        printf("无符合条件的学生!\n");
    return OK;
}
int PrintAverage(int N)//计算所有学生的平均分并显示
{
    if(N<=0)
        return ERROR;
    int i;
    printf("学生\t\t\t平均分\n");
    for(i=1;i<=N;i++)//总分虽然在输入时已算好了,但是如果是从文件中导入的话就没有总分信息
    {
        STU[i].Avg=(STU[i].Score1+STU[i].Score2+STU[i].Score3+STU[i].Score4)/4;//计算平均分
        printf("%s\t\t\t%d\n",STU[i].Name,STU[i].Avg);//打印平均分
    }
    return OK;
}
int PrintLevel(int N)//按总分进行排名并打印,N为学生总数
{
    //此函数与PrintLevel2的功能一样,但不会打乱原有STU的顺序
    if(N<=0)
        return ERROR;
    int i,j;
    for(i=1;i<=N;i++)//将STU的数据存入NEW
    {
        strcpy(NEW[i].Number,STU[i].Number);//学号
        strcpy(NEW[i].Name,STU[i].Name);//姓名
        NEW[i].Score1=STU[i].Score1;//成绩1
        NEW[i].Score2=STU[i].Score2;//成绩2
        NEW[i].Score3=STU[i].Score3;//成绩3
        NEW[i].Score4=STU[i].Score4;//成绩4
        STU[i].All=STU[i].Score1+STU[i].Score2+STU[i].Score3+STU[i].Score4;//计算总分
        NEW[i].All=STU[i].All;//总分
    }
    for(i=1;i<=N;i++)//使用冒泡排序法对NEW进行递增排序
    {
        for(j=1;j<N;j++)//到达最后一个学生时,不进行判断
        {
            if(NEW[j].All>NEW[j+1].All)若当前学生总分比后者还大则后移
            {//将学生信息互换
                char number[Max];//学号
                char name[Max];//姓名
                int score1;//成绩1
                int score2;//成绩2
                int score3;//成绩3
                int score4;//成绩4
                int all;//总分
                int avg;//平均分
                /*学号互换*/
                strcpy(number,NEW[j].Number);
                strcpy(NEW[j].Number,NEW[j+1].Number);
                strcpy(NEW[j+1].Number,number);
                /*姓名互换*/
                strcpy(name,NEW[j].Name);
                strcpy(NEW[j].Name,NEW[j+1].Name);
                strcpy(NEW[j+1].Name,name);
                /*成绩1互换*/
                score1=NEW[j].Score1;
                NEW[j].Score1=NEW[j+1].Score1;
                NEW[j+1].Score1=score1;
                /*成绩2互换*/
                score2=NEW[j].Score2;
                NEW[j].Score2=NEW[j+1].Score2;
                NEW[j+1].Score2=score2;
                /*成绩3互换*/
                score3=NEW[j].Score3;
                NEW[j].Score3=NEW[j+1].Score3;
                NEW[j+1].Score3=score3;
                /*成绩4互换*/
                score4=NEW[j].Score4;
                NEW[j].Score4=NEW[j+1].Score4;
                NEW[j+1].Score4=score4;
                /*总分互换*/
                all=NEW[j].All;
                NEW[j].All=NEW[j+1].All;
                NEW[j+1].All=all;
            }
        }
    }
    printf("=============================================<分隔线>=======================================================\n");
    printf("学号\t\t姓名\t\t成绩1\t\t成绩2\t\t成绩3\t\t成绩4\t\t总分\n");
    for(i=1;i<=N;i++)//PrintStudent函数只显示STU结构体数组的信息,而此处需要打印的是NEW的信息,不能直接调用函数PrintStudent
    {
        printf("%s\t\t",NEW[i].Number);//学号
        printf("%s\t\t",NEW[i].Name);//姓名
        printf("%d\t\t",NEW[i].Score1);//成绩1
        printf("%d\t\t",NEW[i].Score2);//成绩2
        printf("%d\t\t",NEW[i].Score3);//成绩3
        printf("%d\t\t",NEW[i].Score4);//成绩4
        NEW[i].All=NEW[i].Score1+NEW[i].Score2+NEW[i].Score3+NEW[i].Score4;//计算总分
        printf("%d\n",NEW[i].All);//总分
    }
    printf("=============================================<分隔线>=======================================================\n");
    return OK;
}

int PrintLevel2(int N)//按总分进行排名并打印,N为学生总数
{
    //此函数与PrintLevel的功能相同,只不过没有使用到NEW数组
    //此函数将会打乱原有的STU数组的顺序为递增,直接显示可以直接调用PrintStudent函数
    int i,j;
    for(i=1;i<=N;i++)//对STU数组进行递增排序
    {
        for(j=1;j<N;j++)//j=N时不需要后移
        {
            STU[j].All=STU[j].Score1+STU[j].Score2+STU[j].Score3+STU[j].Score4;//计算总分
            STU[j+1].All=STU[j+1].Score1+STU[j+1].Score2+STU[j+1].Score3+STU[j+1].Score4;//计算总分
            if(STU[j].All>STU[j+1].All)//若第j个学生总分较大则后移
            {
                char number[Max];//学号
                char name[Max];//姓名
                int score1;//成绩1
                int score2;//成绩2
                int score3;//成绩3
                int score4;//成绩4
                int all;//总分
                int avg;//平均分
                /*学号互换*/
                strcpy(number,STU[j].Number);
                strcpy(STU[j].Number,STU[j+1].Number);
                strcpy(STU[j+1].Number,number);
                /*姓名互换*/
                strcpy(name,STU[j].Name);
                strcpy(STU[j].Name,STU[j+1].Name);
                strcpy(STU[j+1].Name,name);
                /*成绩1互换*/
                score1=STU[j].Score1;
                STU[j].Score1=STU[j+1].Score1;
                STU[j+1].Score1=score1;
                /*成绩2互换*/
                score2=STU[j].Score2;
                STU[j].Score2=STU[j+1].Score2;
                STU[j+1].Score2=score2;
                /*成绩3互换*/
                score3=STU[j].Score3;
                STU[j].Score3=STU[j+1].Score3;
                STU[j+1].Score3=score3;
                /*成绩4互换*/
                score4=STU[j].Score4;
                STU[j].Score4=STU[j+1].Score4;
                STU[j+1].Score4=score4;
                /*总分互换*/
                all=STU[j].All;
                STU[j].All=STU[j+1].All;
                STU[j+1].All=all;
            }
        }
    }
    PrintStudent(N);//对STU数组直接打印
    return OK;
}
int UploadFail(char loser[],char course[])//将需要补考的名单存入文件fail.txt,loser存储不及格学生的姓名,course为该学生不及格的科目.
{
    //failt.txt文件中不含学生总数,需要建立读取fail.txt函数的话,可以在传入文件的末尾中添加一个特殊字符来判断是否读取完文件
    FILE *read,*op;
    if((read=fopen("file.txt","r"))==NULL)//若fail.txt文件不存在时已重建形式打开文件
        op=fopen("file.txt","w");
    else op=fopen("file.txt","a+");//否则以追加形式打开文件
    fprintf(op,"%s %s\n",loser,course);//文件中每行为一个学生补考信息,补考姓名+补考科目
    fclose(read);
    fclose(op);
    return OK;
}
int Fail(int N)//将需要补考的名单进行打印
{
    if(N<=0)
        return ERROR;
    int i;
    printf("\n==============<分割线>====================\n");
    printf("不及格学生\t不可格课程\n");
    for(i=1;i<=N;i++)
    {
        if(STU[i].Score1<60)//学科1不及格时
        {
            UploadFail(STU[i].Name,"科目1");
            printf("%s\t\t科目1\n",STU[i].Name);
        }
        if(STU[i].Score2<60)//学科2不及格时
        {
            UploadFail(STU[i].Name,"科目2");
            printf("%s\t\t科目2\n",STU[i].Name);
        }
        if(STU[i].Score3<60)//学科3不及格时
        {
            UploadFail(STU[i].Name,"科目3");
            printf("%s\t\t科目3\n",STU[i].Name);
        }
        if(STU[i].Score4<60)//学科4不及格时
        {
            UploadFail(STU[i].Name,"科目4");
            printf("%s\t\t科目4\n",STU[i].Name);
        }
    }
    printf("==============<分割线>====================\n\n");
    return OK;
}
int ScoreFail(int N)//打印指定科目不及格的学生
{//因为Fail函数已经实现了打印所有不及格的学生名单,在此函数仅提供显示指定科目不及格的学生
    while(1)
    {
        printf("------------------------------------\n");
        printf("|       0. 返回主菜单              |\n");
        printf("|       1. 打印科目1不及格的学生   |\n");
        printf("|       2. 打印科目2不及格的学生   |\n");
        printf("|       3. 打印科目3不及格的学生   |\n");
        printf("|       4. 打印科目4不及格的学生   |\n");
        printf("------------------------------------\n");
        int fox;//临时变量
        int i;
        int sum=0;
        scanf("%d",&fox);
        if(fox!=1&&fox!=2&&fox!=3&&fox!=4) break;//返回主菜单
        for(i=1;i<=N;i++)//打印不及格学生
        {
            int flag=0;//当flag=1时表示该同学有不及格的科目
            if(fox==1&&STU[i].Score1<60)//科目1不及格
            {
                printf("%s ",STU[i].Name);
                flag=1;
                sum++;
            }
            if(fox==2&&STU[i].Score2<60)//科目2不及格
            {
                printf("%s ",STU[i].Name);
                flag=1;
                sum++;
            }
            if(fox==3&&STU[i].Score3<60)//科目3不及格
            {
                printf("%s ",STU[i].Name);
                flag=1;
                sum++;
            }
            if(fox==4&&STU[i].Score4<60)//科目4不及格
            {
                printf("%s ",STU[i].Name);
                flag=1;
                sum++;
            }
            if(sum%5==0&&flag==1)//每五个学生为一组且仅当该学生某科目不及格时换行
                printf("\n");
        }
        printf("\n显示完成!\n");
    }
    return OK;
}

c学生成绩管理系统.rar<br>这次的课程设计和以往写的程序比起来,无论是在篇幅和复杂度上都提高了不少,我在写这个程序的过程,遇到了不少的困难,也积累了不少的知识和经验,特别是在以前的时候我倍感头疼的文件部分,我也有了一定的了解,我想这对我今后的学习和工作是十分有益的。在这里我特意将在我在写程序过程的体验和要注意的问题总结如下:<br>一. 基础知识一定要牢固。<br>在调试程序的过程,有时候程序出了错误,找了半天找不到在哪里。这个时候往往会感觉十分不耐烦,但往往越是一些很小的小错误,越是往往容易被人疏漏,诸如“print”啦,注释引号括号不成对出现,遗漏scanf函数的&符号等等,而这些却可能导致整个程序不运行,从而浪费了不少的时间。等到发现时,只会郁闷不已。因此,对于一个合格的程序员来说,牢固的基础知识是十分重要的。我们虽然没有必要达到那么高的要求,但牢固的基础知识对于程序的熟练编写和时间的节省也是大有裨益的。<br>二.调试程序的过程,经验的积累和技巧的掌握是必要的。<br>在这次的课程设计,由于要编写的程序的篇幅较大,因此不可避免地出现了相当多的错误,调试程序花了我不少的时间。我发现调试程序是有规律和技巧可寻的。/**/注释符号的灵活运用提供了较大的空间。通过程序的分块屏蔽可以很容易地找出错误的所在。函数的运用也是很自然的。因为有时一个临时的功能函数可以让我们很直观地知道一段程序是否正确。当然,有时,错误提示信息可以直接提供错误的所在,但是C语言自动查找错误的功能毕竟是有限的,大多数情况之下,我们还是必须要依靠自己。这时,经验就显的很重要了,我们在平时编写程序时,应多注意有意识地积累一些,会有好处的。<br>三.务求简单<br>我在编写程序的过程发现,在某一个功能多个算法可以实现的时候,最好采用最简单的方案,这样可以减少出错的几率,也可以省去不少的麻烦。在我的程序,有一个例子,可以很好地说明这个问题:在编写score_research()函数的时候,有一个地方可以用排序算法实现,也可以用一个标志变量加101然后在函数的末尾处再减101,这样大大地简化了程序,但是运算量也明显地加大了。然而计算机硬件已经发展到今天这个地步,对于我们写的这种小程序,计算速度已经不是问题,因此,务求简单,减少出错率才是正确的选择。<br>四.函数的运用和程序的模块化。<br> 在这次课程设计里,我终于体会到了模块化带来的方便和优越。通过模块化处理,将最初的程序的功能构想以函数的形式划分成几个模块,模块下再设子模块,一层一层直到程序的功能实现为止。这样,不仅程序易于编写,还易于维护。最重要的是,如果程序出错,还易于查找和修改。<br>以上是我在程序的编写过程的一点心得和体会,虽然很肤浅,但毕竟是通过自己的亲身实践得来的,感受较深。<br><br>另外,在程序的操作还有一些需要注意的问题,主要有以下几点:<br>一.输入数据时,也就是在执行input()和input_2()函数的时候,一定要注意按照程序提供的输入顺序输入数据,否则极有可能导致文件的输入错误;还有,由于学生基本情况文件和成绩文件是由input()和input_2()两个函数先后完成的,所以在输入时一定要注意前后相同学生的姓名一定要相应地一致。如果输入了不同的姓名,虽然不会导致程序出错,但对于程序的结果来说,却是逻辑上的一个大大的错误。<br>二.为了使程序的操作更加简便,人性,我在程序有加进了一个view_two()函数,目的是为了使程序每执行完一项功能之后,都能出现菜单以供选择,可以非常方便地执行下一个功能。另外,在view_two()函数和view()函数,我还设置了exit()子函数。执行这个函数,便可以直接返回原代码界面。操作者若是在操作注意到了这些,将会使操作简单不少。<br>三.当然,不可避免地,由于我的程序大部分是在机房编写和调试完成,时间相对较紧张,再加上我本来就对C语言没有精深的钻研和琢磨,因此程序写得相当粗糙,在有些功能的实现上,只是将其功能大致完成,并未考虑到操作的简便化等问题。例如在input()和input_2()函数的执行,本来每个学生的基本情况和成绩应该是在一起输入的,这样才符合一般人的正常思路,但由于学生的基本情况和成绩是由两个函数分别执行完成的,姓名需要输入两次才能将学生的姓名输入到两个结构体,因为姓名是存储在字符数组里面的,所以用一般的赋值语句是解决不了的。我只好采用了一个原始的办法,把两个结构体里的姓名分别用两个输入语句实现。但这样又导致了另外一个问题,即两次姓名的输入如果不相同时所导致的错误,而且这个问题在学生的数量越多即两次输入离得越远时表现得越突出,但我也想不出更好的办法来解决这个问题了。<br><br>通过这次做课程设计,我感觉我学到了不少的东西,尤其是耐心的培养和在宏观上组织问题的能力让我受益非浅。这不仅是设计程序所必需的,也是今后的学习和工作所不可缺少的。希望我能在这次课程设计的基础上,继续学习更多的C语言的知识,使自己的编程能力更上一层楼。<br>
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦之海岛

创作不易,狐狸叹气

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值