一、题目回顾
这是一个经典的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; // 结果保留小数
六、拓展思考
如果你想继续完善这个系统,可以考虑以下功能:
- 添加最高分和最低分:找出每门课程的最高分和最低分
- 成绩等级评定:将平均分转换为优秀/良好/及格/不及格
- 排序功能:按总分从高到低排名
- 成绩查找:根据学号查找某个学生的成绩
- 文件存储:将成绩保存到文件或从文件读取
总结:本题虽然简单,但涵盖了C语言中二维数组、函数参数、格式化输出等多个重要知识点,是非常好的入门练习题。希望这篇博客对你学习C语言有所帮助!
踩过无数坑整理出来的,写文真的不容易,觉得有用的话点个赞支持一下,你们的支持是我持续更新的动力!
如果有任何问题,欢迎在评论区留言交流!

2150

被折叠的 条评论
为什么被折叠?



