C语言基础小项目——简单的学生成绩管理系统(含视频讲解)

概述

学完了C语言基础部分,根据现有知识点写了这个小项目。功能要求实现学生成绩的录入、输出、排序、平均分计算以及按学号查找成绩,另外,还要有基本的帮助菜单、清屏、退出功能。

思路

创建学生结构体,结构体成员包括学号id、语文、数学、英语三科成绩和平均分,再将各个功能通过函数进行封装,通过主函数的循环调用以达到要求的功能。另外,最近正好学了LinuxC高级,可以采用分文件编程,将封装的函数放在student.c中,函数声明放在student.h中,主函数放在main.c里面,最后,再用makefile进行工程管理(这里用个人感觉杀鸡用牛刀,以后工程文件多了应该用得多)。

结构体的构建

typedef struct
{
    int id;
    float chinese;
    float math;
    float english;
    float average;
} Student;

这里用typedef对结构体重命名,方便以后调用。结构体定义应该放在student.h文件中,如果和放到student.c中的话会导致主函数找不到这个结构体,因为我们在main.c中只对.h类型的头文件进行引用,而不会对.c文件进行引用。

函数

主函数

#include <stdio.h>
#include student.h
#include <stdlib.h>

int main()
{
    Student stu[99];
    int stunum = 0;
    char mod;
    menu();
    while (1)
    {
        printf(请输入命令=);
        scanf( %c, &mod);
        if (mod == 'T')
        {
            if (stunum == 0)
                Type(stu, &stunum);
            else
                printf(成绩已录入,请勿重复录入!);
        }
        else if (mod == 'A')
        {
            if (stunum == 0)
                printf(成绩表为空!请先使用命令T录入学生成绩。\n);
            else
                Average(stu, &stunum);
        }
        else if (mod == 'L')
        {
            if (stunum == 0)
                printf(成绩表为空!请先使用命令T录入学生成绩。\n);
            else
                List(stu, &stunum);
        }
        else if (mod == 'P')
        {
            if (stunum == 0)
                printf(成绩表为空!请先使用命令T录入学生成绩。\n);
            else
                Sort(stu, &stunum);
        }
        else if (mod == 'S')
        {
            if (stunum == 0)
                printf(成绩表为空!请先使用命令T录入学生成绩。\n);
            else
                Search(stu, &stunum);
        }
        else if (mod == 'H')
            menu();
        else if (mod == 'C')
            system(clear);
        else if (mod == 'Q')
            break;
        else
            printf(命令有误,请重新输入!\n);
    }
    return 0;
}

主函数主要是对结构体数组、学生人数和输入命令的定义。命令的判断则分为两类,第一类是需要判断成绩是否录入,如:录入、输出、排序、平均分计算以及按学号查找,第二类则是无需判断成绩是否录入,如:菜单、清屏和退出。如果没有录入成绩,输入命令T则调用Type函数录入成绩,输入命令A、L、T、S则输出“成绩表为空!请先使用命令T录入学生成绩。“;如果已经录入了成绩,输入命令T输出成绩已录入,请勿重复录入!,输入命令A、L、T、S则调用响应的函数实现对应功能;输入命令H、C、Q无需判断,直接执行响应功能语句。

帮助菜单

void menu()
{
    for (int i = 0; i < 46; i++)
        printf(*);
    printf(\n);
    printf(  *       学生成绩管理系统——帮助菜单       *  \n);
    for (int i = 0; i < 46; i++)
        printf(*);
    printf(\n);
    printf(  *         H = 显示帮助菜单               *  \n);
    printf(  *         T = 成绩录入                   *  \n);
    printf(  *         A = 计算学生平均分             *  \n);
    printf(  *         L = 列出成绩表                 * \n);
    printf(  *         P = 按平均由高到低排序         *  \n);
    printf(  *         S = 按学号查询学生成绩         *  \n);
    printf(  *         C = 清屏                       *  \n);
    printf(  *         Q = 退出系统                   *  \n);
    for (int i = 0; i < 46; i++)
        printf(*);
    printf(\n);
    printf(  *   Copyright <C> 2024.07.10 By  name  *  \n);
    for (int i = 0; i < 46; i++)
        printf(*);
    printf(\n);
}

帮助菜单写得比较粗糙,对菜单上下的分割线用for循环,中间的选项只能用printf挨个打印,实在也想不出什么比较简单优雅的方法,在终端运行出来就是下面这样:

成绩录入

void Type(Student *stu, int *stunum)
{
    printf(请输入学生人数:);
    scanf(%d, stunum);
    printf(请输入%d名学生的三门课成绩:\n, *stunum);
    printf(学号 语文 数学 外语\n);
    for (int i = 0; i < *stunum; i++)
    {
        printf(%d    , i + 1);
        stu[i].id = i + 1;
        stu[i].average = 0;
        scanf(%f %f %f, &stu[i].chinese, &stu[i].math, &stu[i].english);
    }
}

要保证函数的正常运行,首先必须要在主函数定义一个Student类型的结构体数组,然后在该函数中循环遍历赋值,循环次数取决于输入的学生人数stunum,学号则是自动生成,第一个录入成绩则是1号,需要注意的是这里的i代表的是结构体数组的下标,所以学号的话还要加1,函数的第二个参数是需要传入stunum的地址,这样才能在函数内部对值进行修改,因为后需要对stunum的值进行判断,判断是否录入了成绩。

成绩输出

void List(Student *stu, int *stunum)
{
    printf(学生成绩如下:\n);
    printf(学号 语文 数学 外语 平均分\n);
    for (int i = 0; i < *stunum; i++)
    {
        printf(%d    %.1f  %.1f  %.1f  %.1f\n, stu[i].id, stu[i].chinese, stu[i].math, stu[i].english, stu[i].average);
    }
}

这里对每个结构体数组每个元素的每个成员进行遍历打印,以达到输出成绩列表的目的。

计算平均分

void Average(Student *stu, int *stunum)
{
    for (int i = 0; i < *stunum; i++)
    {
        stu[i].average = (stu[i].chinese + stu[i].math + stu[i].english) / 3;
    }
    printf(平均分已计算,请使用命令L查看。\n);
}

将结构体数组每个元素的语文成员、数学成员、英语成员相加除以3,再赋值给平均数成员即可。

排序

void Sort(Student *stu, int *stunum)
{
    for (int i = 0; i < *stunum - 1; i++)
    {
        for (int j = 0; j < *stunum - 1 - i; j++)
        {
            if (stu[j].average < stu[j + 1].average)
            {
                Student t;
                t = stu[j];
                stu[j] = stu[j + 1];
                stu[j + 1] = t;
            }
        }
    }
    printf(完成排序。请使用命令L查看。\n);
}

这里采用了冒泡排序,平均分从高到低排序,这里有个点比较容易犯错误,在比较完平均分后不能只交换平均分,要对平均分所在的结构体进行交换。

按学号搜索

void Search(Student *stu, int *stunum)
{
    int stuid;
    printf(请输入要查询的学生学号:);
    scanf(%d, &stuid);
    for (int i = 0; i < *stunum; i++)
    {
        if (stu[i].id == stuid)
        {
            printf(学号 语文 数学 外语 平均分\n);
            printf(%d    %.1f  %.1f  %.1f  %.1f\n, stu[i].id, stu[i].chinese, stu[i].math, stu[i].english, stu[i].average);
        }
    }
}

将输入的学号通过for循环和每一个结构体的id成员遍历比较,相等的话就打印出该结构体的所有成员。

不足

这个小项目还有很多可以改进的地方,比如输入的分数是否合法,按学号查找时成绩列表中是否有该学生,这些都是编写过程中没有想到的,后续我会继续完善这些功能。

哔哩哔哩视频

第一次投稿,有不足的地方请大家多多指教

点我查看

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
下一篇