C语言学生成绩统计系统详解:从二维数组到模块化编程

一、题目回顾

这是一个经典的C语言练习题,要求我们实现一个学生成绩统计系统:

  • 输入:5个学生的3门课程成绩(语文、数学、英语)
  • 计算:每个学生的总分和平均分、每门课程的平均分
  • 输出:整齐的成绩单

题目要求使用二维数组存储成绩,并通过函数模块化编程来实现各个功能模块。

二、思路分析

2.1 数据结构设计

首先,我们需要思考如何存储这些数据:

学生有5个,每个学生有3门课程成绩
        语文  数学  英语
学生1   85    92    78
学生2   88    76    95
学生3   83    89    91
学生4   92    88    77
学生5   84    75    90

这种行列式的数据结构非常适合用二维数组来存储:

  • 第一维:表示学生(5个)
  • 第二维:表示课程(3门

所以我们可以声明:int scores[5][3];

2.2 模块划分

按照题目要求,我们把程序划分为4个函数模块:

函数名功能输入输出
input_scores输入成绩scores数组
calculate_student_avg计算学生平均分scores数组student_avg数组
calculate_subject_avg计算科目平均分scores数组subject_avg数组
print_report输出成绩单所有数据屏幕输出

2.3 计算逻辑

学生平均分:把该学生3门课的成绩加起来除以3

学生i的平均分 = (scores[i][0] + scores[i][1] + scores[i][2]) / 3.0

科目平均分:把选修该科目5个学生的成绩加起来除以5

语文平均分 = (scores[0][0] + scores[1][0] + ... + scores[4][0]) / 5.0
数学平均分 = (scores[0][1] + scores[1][1] + ... + scores[4][1]) / 5.0
英语平均分 = (scores[0][2] + scores[1][2] + ... + scores[4][2]) / 5.0

三、完整代码

/*
 * 学生成绩统计系统
 * 功能:输入5个学生的3门课程成绩,计算总分、平均分,输出成绩单
 * 作者:C语言学习者
 * 日期:2024年
 */

#include <stdio.h>

// 常量定义
#define STUDENT_COUNT 5   // 学生数量
#define SUBJECT_COUNT 3   // 课程数量

/*
 * 函数:input_scores
 * 功能:输入5个学生的3门课程成绩
 * 参数:scores - 二维数组,用于存储成绩
 * 返回:无
 */
void input_scores(int scores[][SUBJECT_COUNT])
{
    printf("========================================\n");
    printf("         学生成绩录入系统\n");
    printf("========================================\n");
    printf("请输入5个学生的语文、数学、英语成绩\n");
    printf("(每行输入3个整数,用空格分隔)\n");
    printf("----------------------------------------\n");
    
    for (int i = 0; i < STUDENT_COUNT; i++)
    {
        printf("第 %d 个学生: ", i + 1);
        scanf("%d %d %d", 
              &scores[i][0],   // 语文成绩
              &scores[i][1],   // 数学成绩
              &scores[i][2]);  // 英语成绩
    }
    printf("----------------------------------------\n");
    printf("成绩录入完成!\n\n");
}

/*
 * 函数:calculate_student_avg
 * 功能:计算每个学生的平均分
 * 参数:scores - 成绩二维数组
 *       student_avg - 存储学生平均分的一维数组
 * 返回:无
 */
void calculate_student_avg(int scores[][SUBJECT_COUNT], float student_avg[])
{
    for (int i = 0; i < STUDENT_COUNT; i++)
    {
        // 累加该学生的3门课程成绩
        int sum = 0;
        for (int j = 0; j < SUBJECT_COUNT; j++)
        {
            sum += scores[i][j];
        }
        // 计算平均值(注意用3.0确保浮点运算)
        student_avg[i] = sum / 3.0;
    }
}

/*
 * 函数:calculate_subject_avg
 * 功能:计算每门课程的平均分
 * 参数:scores - 成绩二维数组
 *       subject_avg - 存储科目平均分的一维数组
 * 返回:无
 */
void calculate_subject_avg(int scores[][SUBJECT_COUNT], float subject_avg[])
{
    for (int j = 0; j < SUBJECT_COUNT; j++)
    {
        // 累加选修该课程的所有学生成绩
        int sum = 0;
        for (int i = 0; i < STUDENT_COUNT; i++)
        {
            sum += scores[i][j];
        }
        // 计算平均值(注意用5.0确保浮点运算)
        subject_avg[j] = sum / 5.0;
    }
}

/*
 * 函数:print_report
 * 功能:输出完整的成绩统计报表
 * 参数:scores - 成绩二维数组
 *       student_avg - 学生平均分数组
 *       subject_avg - 科目平均分数组
 * 返回:无
 */
void print_report(int scores[][SUBJECT_COUNT], float student_avg[], float subject_avg[])
{
    printf("\n========================================\n");
    printf("           学生成绩统计报表\n");
    printf("========================================\n\n");
    
    // ========== 打印表头 ==========
    printf("%-6s", "学号");           // 左对齐,学号列宽6
    printf("%-8s", "语文");           // 语文列宽8
    printf("%-8s", "数学");           // 数学列宽8
    printf("%-8s", "英语");           // 英语列宽8
    printf("%-8s", "总分");           // 总分列宽8
    printf("%-8s", "平均分");         // 平均分列宽8
    printf("\n");
    
    // 打印分隔线
    printf("----------------------------------------\n");
    
    // ========== 打印每个学生的成绩 ==========
    for (int i = 0; i < STUDENT_COUNT; i++)
    {
        // 计算该学生的总分
        int total = scores[i][0] + scores[i][1] + scores[i][2];
        
        // 打印学号和成绩
        printf("%-6d", i + 1);                          // 学号(从1开始)
        printf("%-8d", scores[i][0]);                   // 语文成绩
        printf("%-8d", scores[i][1]);                   // 数学成绩
        printf("%-8d", scores[i][2]);                   // 英语成绩
        printf("%-8d", total);                          // 总分
        printf("%-8.1f", student_avg[i]);               // 平均分(保留1位小数)
        printf("\n");
    }
    
    // ========== 打印各科目平均分 ==========
    printf("----------------------------------------\n");
    
    printf("%-6s", "科目平均");              // 左对齐
    printf("%-8.1f", subject_avg[0]);        // 语文平均分
    printf("%-8.1f", subject_avg[1]);        // 数学平均分
    printf("%-8.1f", subject_avg[2]);        // 英语平均分
    printf("%-8s", "");                       // 总分列留空
    printf("%-8s", "");                       // 平均分列留空
    printf("\n");
    
    printf("========================================\n");
}

/*
 * 主函数:程序入口
 */
int main(void)
{
    // 声明二维数组存储成绩:[5个学生][3门课程]
    int scores[STUDENT_COUNT][SUBJECT_COUNT];
    
    // 声明一维数组存储平均分
    float student_avg[STUDENT_COUNT];  // 每个学生的平均分
    float subject_avg[SUBJECT_COUNT];  // 每门课程的平均分
    
    // 调用各个函数完成功能
    input_scores(scores);                              // 1. 输入成绩
    calculate_student_avg(scores, student_avg);       // 2. 计算学生平均分
    calculate_subject_avg(scores, subject_avg);        // 3. 计算科目平均分
    print_report(scores, student_avg, subject_avg);    // 4. 输出报表
    
    return 0;
}

四、运行结果

========================================
         学生成绩录入系统
========================================
请输入5个学生的语文、数学、英语成绩
(每行输入3个整数,用空格分隔)
----------------------------------------
第 1 个学生: 85 92 78
第 2 个学生: 88 76 95
第 3 个学生: 83 89 91
第 4 个学生: 92 88 77
第 5 个学生: 84 75 90
----------------------------------------
成绩录入完成!

========================================
           学生成绩统计报表
========================================

学号    语文      数学      英语      总分      平均分    
----------------------------------------
1       85        92        78        255       85.0      
2       88        76        95        259       86.3      
3       83        89        91        263       87.7      
4       92        88        77        257       85.7      
5       84        75        90        249       83.0      
----------------------------------------
科目平均 86.5      84.0      86.2                      
========================================

五、知识点总结

5.1 二维数组的使用

// 声明方式:int 数组名[行数][列数]
int scores[5][3];

// 访问方式:数组名[行下标][列下标]
scores[0][0] = 85;  // 第1个学生的语文成绩
scores[0][1] = 92;  // 第1个学生的数学成绩
scores[0][2] = 78;  // 第1个学生的英语成绩

为什么二维数组适合存储表格数据?

  • 第一维可以理解为"行",代表不同的学生
  • 第二维可以理解为"列",代表不同的课程
  • scores[i][j] 的含义就是:第 i 个学生的第 j 门课程成绩

5.2 函数与二维数组参数

// 二维数组作为函数参数的形式
void input_scores(int scores[][3])

注意:第二维的大小必须指定,第一维可以写空或写变量。这是因为:

  • 编译器需要知道每一行有多少列,才能正确计算内存地址
  • 第一维的大小在运行时由实参决定

5.3 格式化输出

// %-8d:左对齐,整数,占8个字符宽度
printf("%-8d", 85);

// %-8.1f:左对齐,浮点数,保留1位小数,占8个字符宽度
printf("%-8.1f", 85.67);

为什么用 -8 而不是 8

  • %8d:右对齐(默认),数字靠右显示
  • %-8d:左对齐,数字靠左显示
  • 成绩单通常左对齐更美观

5.4 模块化编程思想

本题展示了良好的模块化编程风格:

优点说明
职责单一每个函数只做一件事
易于维护修改一个功能不影响其他功能
易于调试可以单独测试每个函数
代码复用通用函数可以在其他地方复用

5.5 常见错误提醒

// 错误:除法时使用整数
student_avg[i] = sum / 3;  // 结果会被截断为整数

// 正确:使用浮点数进行除法
student_avg[i] = sum / 3.0;  // 结果保留小数

六、拓展思考

如果你想继续完善这个系统,可以考虑以下功能:

  1. 添加最高分和最低分:找出每门课程的最高分和最低分
  2. 成绩等级评定:将平均分转换为优秀/良好/及格/不及格
  3. 排序功能:按总分从高到低排名
  4. 成绩查找:根据学号查找某个学生的成绩
  5. 文件存储:将成绩保存到文件或从文件读取

总结:本题虽然简单,但涵盖了C语言中二维数组、函数参数、格式化输出等多个重要知识点,是非常好的入门练习题。希望这篇博客对你学习C语言有所帮助!

踩过无数坑整理出来的,写文真的不容易,觉得有用的话点个赞支持一下,你们的支持是我持续更新的动力!

如果有任何问题,欢迎在评论区留言交流!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值