链式成绩管理系统

/*
名称:成绩管理系统(单链表实现)

功能:学生信息的添加、修改、删除、查找及显示

特点:加入两种查找方式,登录成绩管理系统需要密码
且密码,且有管理员和学生两种权限
(管理员账号:admin,管理员密码:admin
学生账号:student,学生密码:student);

update:
2013.5.20---成绩管理系统beta1(实现基本功能)
2013.5.29---成绩管理系统beta2(加入文件,内置
                                    网工三班前12号成绩(仅作者乱打的数据)
                                    修复删除了人之后不能马上添加的bug)
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>

struct student
{
  long long no;//比如学号为:121052030*
  char name[20];//比如姓名为:蒲*
  float score[3];//数据结构,高数,英语三门学科成绩
  float sum;//总分
  float ave;//平均分
  struct student *next;//指向下一节点的指针
};

//初始化,有头结点
student *Init()
{
    student *stu;
    stu = (student *)malloc(sizeof(student));//动态分配内存
    stu->next = NULL;
    return stu;
}

//登陆函数
int Login()
{
    char Name[20];//用户名
    char Password[20];//密码
    printf("|*************************************|\n");
    printf("|*****欢迎进入Neusoft成绩管理系统*****|\n");
    printf("|*****         登陆              *****|\n");
    printf("       用户名:_____\b\b\b\b\b");
    scanf("%s", Name);
    printf("       密码:_____\b\b\b\b\b");
    scanf("%s", Password);
    printf("|*************************************|\n\n");
    //判断用户名和密码是否正确,以及权限
    if (!strcmp("admin", Name) && !strcmp("admin", Password))
    {
        return 2;
    }
    else if(!strcmp("student", Name) && !strcmp("student", Password))
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

//菜单函数
int Menu()
{
    int select;
    printf("|*************************************|\n");
    printf("|*****欢迎进入Neusoft成绩管理系统*****|\n");
    printf("|*****       1.录入新学生信息    *****|\n");
    printf("|*****       2.查找学生信息      *****|\n");
    printf("|*****       3.修改学生信息      *****|\n");
    printf("|*****       4.删除学生信息      *****|\n");
    printf("|*****       5.显示学生信息      *****|\n");
    printf("|*****       6.退出              *****|\n");
    printf("|*************************************|\n");
    do//如果输入不合法的选项,就一直进行输入,知道输入正确的选项
    {
        printf("请输入你的选择:");
        scanf("%d", &select);
    }while (select>6 || select<1);
    return select;
}

//载入文件
void load(student *stu)
{
    FILE *fp;
    student *stuTemp;//哨兵指针
    student *stuNew;//新节点指针
    stuTemp = stu;

    //判断文件是否能正常打开
    if ((fp = fopen("student_list", "rb")) == NULL)
    {
        printf("Can't open file!\n");
        exit (0);
    }

    //到文件结束前,一次读取文件放到链表中
    while (!feof(fp))
    {
        stuNew = (student *)malloc(sizeof(student));
        if (fread(stuNew, sizeof(student), 1, fp)!=1)
        {
            if (feof(fp))
            {
                fclose(fp);
                return ;
            }
            printf("File read error!\n");
        }
        else
        {
            stuTemp->next = stuNew;
            stuTemp = stuNew;
        }
    }
    stuTemp = NULL;
    fclose(fp);//关闭文件
}

//信息写入文件函数
void save(student *stu)
{
    FILE *fp;
    student *stuTemp;//哨兵指针
    stuTemp = stu->next;//指向第一个信息节点
    //判断文件是否能正常打开
    if ((fp = fopen("student_list", "wb")) == NULL)
    {
        printf("Can't open file!\n");
        exit (0);
    }

    //循环到链表,末尾,依次写入到文件
    while (stuTemp!=NULL)
    {
        if (fwrite(stuTemp, sizeof(student), 1, fp)!=1)
        {
            printf("File write error!\n");
            break;
        }
        else
        {
            stuTemp = stuTemp->next;
        }
    }
    fclose(fp);//关闭文件

}

//录入学生信息,此实现一次录入一个学生的功能
void Ent(student *stu, long long inNo, char inName[], float inScore[])
{
    student *stuTemp;
    student *stuTempJ;//检查遍历指针
    student *stuNew;//创建一个新学生的节点
    stuTemp = stu;
    stuNew = (student *)malloc(sizeof(student));//为新学生节点动态分配内存空间
    stuNew->next = NULL;
    stuTempJ = stu->next;
    stuNew->no = inNo;
    strcpy(stuNew->name, inName);//姓名是字符串,所以要用strcpy函数,当然c++的string类支持直接=
    float inSum = 0.0, inAve;
    int i;
    for (i=0; i<3; i++)
    {
        stuNew->score[i] = inScore[i];
        inSum += inScore[i];
    }
    inAve = inSum/3.0;//计算平均分
    stuNew->sum = inSum;
    stuNew->ave = inAve;
    stuTemp->next = stuNew;//将原始链表与新节点连接起来
}

//按学号查找函数
void SearchNo(student *stu, long long inNo)
{
    student *stuTemp;
    stuTemp = stu->next;//哨兵指针指向第一个有信息的节点
    while (stuTemp!=NULL)
    {
        if (inNo == stuTemp->no)
        {
            printf("|你查找的学生信息如下:                                                        |\n");
            printf("|*****************************************************************************|\n");
            printf("|    学号   ||  姓名  ||  数据结构  ||  高数  ||  英语  ||  总分  ||  平均分  |\n");
            //-代表向左对其,小数左边代表一共多少位占用,右边代表小数点的位置
            printf("|%-11lld||%-8s||%-12.2f||%-8.2f||%-8.2f||%-8.2f||%-10.2f|\n",
                       stuTemp->no, stuTemp->name,
                       stuTemp->score[0], stuTemp->score[1], stuTemp->score[2],
                       stuTemp->sum, stuTemp->ave);
            printf("|*****************************************************************************|\n");
            break;
        }
        else
        {
            stuTemp = stuTemp->next;
        }
    }
    //查找到链表末尾都没找到,即不存在
    if (stuTemp==NULL)
    {
        printf("|*****************************************************************************|\n");
        printf("|你查找的学生不存在!                                                         |\n");
        printf("|*****************************************************************************|\n");
    }
    stuTemp = NULL;
}

//按姓名查找函数
void SearchName(student *stu, char inName[])
{
    student *stuTemp;
    stuTemp = stu->next;//哨兵指针
    while (stuTemp!=NULL)
    {
        if (!strcmp(stuTemp->name, inName))
        {
            printf("|你查找的学生信息如下:                                                        |\n");
            printf("|*****************************************************************************|\n");
            printf("|    学号   ||  姓名  ||  数据结构  ||  高数  ||  英语  ||  总分  ||  平均分  |\n");
            //-代表向左对其,小数左边代表一共多少位占用,右边代表小数点的位置
            printf("|%-11lld||%-8s||%-12.2f||%-8.2f||%-8.2f||%-8.2f||%-10.2f|\n",
                       stuTemp->no, stuTemp->name,
                       stuTemp->score[0], stuTemp->score[1], stuTemp->score[2],
                       stuTemp->sum, stuTemp->ave);
            printf("|*****************************************************************************|\n");
            break;
        }
        else
        {
            stuTemp = stuTemp->next;
        }
    }
    //查找到链表末尾都没找到,即不存在
    if (stuTemp==NULL)
    {
        printf("|*****************************************************************************|\n");
        printf("|你查找的学生不存在!                                                         |\n");
        printf("|*****************************************************************************|\n");
    }
    stuTemp = NULL;
}

//查找选择函数
void Search(student *stu)
{
    int sel;
    printf("|~~~~~~~~~~~~~~~~~~|\n");
    printf("|    1.按学号查找  |\n");
    printf("|    2.按姓名查找  |\n");
    printf("|~~~~~~~~~~~~~~~~~~|\n");
    do//如果输入不合法的选项,就一直进行输入,知道输入正确的选项
    {
        printf("请输入你的选择:");
        scanf("%d", &sel);
    } while (sel<1 || sel>2);
    long long inNo;
    char inName[20];
    //选择1就按学号查找
    if (sel == 1)
    {
        printf("请输入学生的学号(eg:1231052030*):");
        scanf("%lld", &inNo);
        //printf("inNo==%lld\n", inNo);
        SearchNo(stu, inNo);

    }
    //选择2按姓名查找
    else if (sel == 2)
    {
        getchar();//由于gets要吃回车符,所以在sel==2时,输入sel2会产生一个回车符,要在gets输入之前被吃掉
        printf("请输入学生的姓名(eg:蒲*):");
        gets(inName);
        SearchName(stu, inName);
    }
}

//学生信息的修改函数,由于学号的唯一性,所以我们修改就只按照学号修改
void Mod(student *stu, long long inNo, char inName[], float inScore[])
{
    student *stuTemp;
    stuTemp = stu->next;//哨兵指针
    float inSum = 0.0, inAve;
    int i;
    while (stuTemp!=NULL)
    {
        //学号相等判断
        if (inNo == stuTemp->no)
        {
            strcpy(stuTemp->name, inName);//姓名是字符串,所以要用strcpy函数,当然c++的string类支持直接=
            for (i=0; i<3; i++)
            {
                stuTemp->score[i] = inScore[i];//循环赋值
                inSum += inScore[i];//求和
            }
            inAve = inSum/3.0;//求平均
            stuTemp->sum = inSum;
            stuTemp->ave = inAve;
            break;
        }
        else
        {
            stuTemp = stuTemp->next;//哨兵指针遍历
        }
    }
    //查找到链表末尾都没找到,即不存在
    if (stuTemp==NULL)
    {
        printf("|*****************************************************************************|\n");
        printf("|你要修改的学生不存在!                                                       |\n");
        printf("|*****************************************************************************|\n");
    }
    stuTemp = NULL;
}

//学生信息删除函数
void Delete(student *stu, long long inNo)
{
    student *stuTemp;
    student *stuFront;
    stuTemp = stu->next;//哨兵指针
    stuFront = stu;
    while (stuTemp!=NULL)
    {
        if (stuTemp->no == inNo)
        {
            stuFront->next = stuTemp->next;
            free(stuTemp);//释放内存
            stuTemp = stu;//由于后面要判断是否删除不存在的人,所以让哨兵指针指向一个地址
            break;
        }
        else
        {
            stuFront = stuTemp;
            stuTemp = stuTemp->next;
        }
    }
    if (stuTemp==NULL)
    {
        printf("|*****************************************************************************|\n");
        printf("|你要删除的学生不存在!                                                       |\n");
        printf("|*****************************************************************************|\n");
    }
}

//按学号排序,使用的是冒泡排序,当然你有其他更好的选择
void Sort(student *stu)
{
    student *p, *q;
    //凡是以t打头的都是零时变量,后面交换用
    long long tNo;
    char tName[20];
    float tScore[3];
    float tSum, tAve;
    p=stu->next;
    q=stu->next;
    for (; p->next!=NULL; p=p->next)
    {
        for (q=stu->next; q->next!=NULL; q=q->next)
        {
            //判断后面的学号是否比前面学号小
            if (q->no>q->next->no)
            {
                //赋值给零时变量
                tNo = q->no;
                strcpy(tName, q->name);
                for (int i=0; i<3; i++)
                {
                    tScore[i] = q->score[i];
                }
                tSum = q->sum;
                tAve = q->ave;

                //下面三段代码都是交换操作,可能冒泡有点繁琐,当然推荐使用其他
                q->no = q->next->no;
                strcpy(q->name, q->next->name);
                for (int i=0; i<3; i++)
                {
                    q->score[i] = q->next->score[i];
                }
                q->sum = q->next->sum;
                q->ave = q->next->ave;

                q->next->no = tNo;
                strcpy(q->next->name, tName);
                for (int i=0; i<3; i++)
                {
                    q->next->score[i] = tScore[i];
                }
                q->next->sum = tSum;
                q->next->ave = tAve;
            }
        }
    }
}

//显示学生信息
void Print(student *stu)
{
    student *stuTemp;
    Sort(stu);
    stuTemp = stu->next;
    printf("|*****************************************************************************|\n");
    printf("|    学号   ||  姓名  ||  数据结构  ||  高数  ||  英语  ||  总分  ||  平均分  |\n");
    //循环到链表末尾,显示所有信息
    while (stuTemp!=NULL)
    {
        //-代表向左对其,小数左边代表一共多少位占用,右边代表小数点的位置
        printf("|%-11lld||%-8s||%-12.2f||%-8.2f||%-8.2f||%-8.2f||%-10.2f|\n",
                   stuTemp->no, stuTemp->name,
                   stuTemp->score[0], stuTemp->score[1], stuTemp->score[2],
                   stuTemp->sum, stuTemp->ave);
        stuTemp = stuTemp->next;//指针遍历
    }
    printf("|*****************************************************************************|\n");
}

//主函数入口
int main()
{
    student *stu;//声名一个student的指针变量(本人习惯使用指针变量,当然你可以直接声名一个student的变量)
    stu = Init();//初始化学生信息链表
    load(stu);//载入文件
    student *stuTemp;

    int sel;
    long long inNo;
    char inName[20];
    float inScore[3];

    int lg;
    while (1)
    {
        lg = Login();
        if (lg == 2)
        {
            printf("登陆成功,你的权限为:管理员.\n");
            break;
        }
        else if (lg == 1)
        {
            printf("登陆成功,你的权限为:学生.\n");
            break;
        }
        else
        {
            printf("账号密码错误,请重新输入!\n");
        }
    }

    //死循环,进行多次操作,退出可选择6即可
    while (1)
    {
        sel = Menu();//sel接收菜单函数的返回值,然后进入switch case语句判断

        //管理员权限
        if (lg == 2)
        {
            switch (sel)
            {
                case 1:
                    printf("请输入学生的学号(eg:1231052030*):");
                    scanf("%lld", &inNo);
                    getchar();
                    printf("请输入学生的姓名(eg:蒲*):");
                    gets(inName);
                    printf("请输入学生的数据结构成绩(eg:98.5):");
                    scanf("%f", &inScore[0]);
                    printf("请输入学生的高数成绩(eg:98.5):");
                    scanf("%f", &inScore[1]);
                    printf("请输入学生的英语成绩(eg:98.5):");
                    scanf("%f", &inScore[2]);
                    for (stuTemp = stu; stuTemp->next!=NULL; stuTemp=stuTemp->next);//扫描到最后一个信息节点
                    Ent(stuTemp, inNo, inName, inScore);//把指向最后一个节点的指针传入录入信息函数
                    break;
                case 2:
                    Search(stu);
                    break;
                case 3:
                    printf("请输入要修改的学生的学号(eg:1231052030*):");
                    scanf("%lld", &inNo);
                    getchar();
                    printf("请输入修改后的学生的姓名(eg:蒲*):");
                    gets(inName);
                    printf("请输入修改后的学生的数据结构成绩(eg:98.5):");
                    scanf("%f", &inScore[0]);
                    printf("请输入修改后的学生的高数成绩(eg:98.5):");
                    scanf("%f", &inScore[1]);
                    printf("请输入修改后的学生的英语成绩(eg:98.5):");
                    scanf("%f", &inScore[2]);
                    Mod(stu, inNo, inName, inScore);
                    break;
                case 4:
                    printf("请输入要删除的学生的学号(eg:1231052030*):");
                    scanf("%lld", &inNo);
                    Delete(stu, inNo);
                    break;
                case 5:
                    Print(stu);
                    break;
                case 6:
                    save(stu);
                    exit(0);//结束,需要包含头文件stdlib.h
            }
        }
        else if (lg == 1)
        {
            switch (sel)
            {
                case 1:
                    printf("您没有权限\n");
                    break;
                case 2:
                    Search(stu);
                    break;
                case 3:
                    printf("您没有权限\n");
                    break;
                case 4:
                    printf("您没有权限\n");
                    break;
                case 5:
                    Print(stu);
                    break;
                case 6:
                    save(stu);
                    exit(0);//结束,需要包含头文件stdlib.h
            }
        }
    }

    return 0;
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值