视频讲解



第5章结构化程序设计二——设计学生成绩统计器二

本章的项目所实现的功能同第4章的项目相类似,都是实现一个用于学生成绩统计的程序。但是,在本项目中,系统功能通过循环结构和switch分支结构来实现学生成绩统计的功能。通过本项目的学习和实践,可以掌握通过循环结构,解决一些必须通过重复工作来完成的问题。
5.1项目案例功能介绍
每门课程考试完成之后,任课教师要对考试成绩进行汇总、分析,成绩的汇总是分析的基础。假设全班人数为已知的,所需要统计的信息主要涉及全班的最高分、最低分、0~59区间分数的人数及其所占的比例、60~69区间分数的人数及其所占的比例、70~79区间分数的人数及其所占的比例、80~89区间分数的人数及其所占的比例、90~100区间分数的人数及其所占的比例。
本项目采用控制台程序,实现依次接收每个同学的成绩,最后输出上述汇总信息。
5.2项目设计思路
在本项目中,项目设计思路包括以下步骤。
(1) 项目分析与算法流程设计。
(2) 程序代码设计。
(3) 系统运行与效果测试。
5.3关键技术
5.3.1循环结构

程序设计中的循环结构,是指在程序中从某处开始有规律地反复执行某一语句块的结构,并把重复执行的语句块称为循环体。
循环结构是一种常见的基本结构。循环结构按其循环体是否有嵌套从属的子循环结构,可分为单循环结构和多重循环结构。

循环结构可以在很大程度上简化程序设计,并解决采用其他结构而不易解决的问题。例如,计算1+2+3+…+100的和,采用顺序结构来解决非常不便。若采用循环结构来编写这种程序,就相当简单,只需要几条语句即可。C#中提供了4种类型的循环结构,分别适用于不同的情形。
5.3.2while语句与do…while语句
while语句和do…while语句用于循环次数不固定时,相当高效、简洁。
1.  while语句
while语句的一般语法格式为: 

while(条件表达式)

{

循环体;

}


说明: while语句在执行时,首先判定条件表达式的值。如果while后面括号中的条件表达式的值为true,即执行循环体,

然后再回到while语句的开始处,再判定while后面括号中的表达式的值是否为true,只要表达式一直为true,那么就重复执行循环体,直到while后面括号中的条件表达式的值为false时,才退出循环,并执行下一条语句。
while语句的程序流程图如图51所示。

2.  do…while语句
do…while语句与while语句功能相似,但和while语句不同的是,do…while语句的判定条件在后面,这和while语句不同。do…while循环不论条件表达式的值是什么,do…while循环都至少要执行一次。do…while语句的一般语法格式如下。

do

{

循环体;

}

while(条件表达式);

说明: 当循环执行到do语句后,先执行循环体语句; 执行完循环体语句后,再对while语句括号中的条件表达式进行判定。若表达式的值为true,则转向do语句继续执行循环体语句; 若表达式的值为false,则退出循环,执行程序的下一条语句。
do…while语句的程序执行流程图如图52所示。


图51while循环结构




图52do…while循环结构



5.3.3for循环语句和foreach语句
for语句和foreach语句都是固定循环次数的循环语句。
1.  for语句
for语句是一种功能强大的循环语句,它比while语句和do…while语句更为灵活。它的一般语法格式为: 

for(表达式1;表达式2;表达式3)

{

循环体;

}

for语句的执行过程如下。


图53for循环结构


(1) 首先计算表达式1的值。
(2) 判定表达式2的值,若其值为true,则执行循环体中的语句,然后求表达式3的值; 若表达式2的值为false,则转而执行步骤(4)。
(3) 返回步骤(2)。
(4) 结束循环,执行程序的下一条语句。
for语句的程序执行流程图如图53所示。


2. foreach语句
foreach语句是C#中新增加的循环语句,它对于处理数组及集合等数据类型特别简便。foreach语句用于列举集合中的每一个元素,并且通过执行循环体对每一个元素进行操作。foreach语句只能对集合中的元素进行循环操作。foreach语句的一般语法格式如下。

foreach(数据类型 标识符 in 表达式)

{

循环体;

}

说明: foreach语句中的循环变量是由数据类型和标识符声明的,循环变量在整个foreach语句范围内有效。在foreach语句执行过程中,循环变量就代表当前循环所执行的集合中的元素。每执行一次循环体,循环变量就依次将集合中的一个元素带入其中,直到把集合中的元素处理完毕,跳出foreach循环,转而执行程序的下一条语句。
5.4项目实践
5.4.1项目分析与算法流程设计

由前面所述的项目功能介绍可知,本项目包含以下几部分基本功能。
(1) 接收全班人数。
(2) 依次接收班级每个学生的成绩。

(3) 每接收一个成绩,依据要求进行统计汇总。
由此,可以得到问题的解决思路。该思路如下所述。
(1) 初始化统计信息各个变量。

(2) 接收班级学生人数nStudents。
(3) 初始化已统计成绩的学生人数为i=1。
(4) 判定i<=nStudents,若判定式的值为true,则执行(5); 若判定式的值为false,则执行(9)
(5) 接收下一个成绩。
(6) 比较以前得到的最高、最低成绩与当前接收的成绩的大小关系,并修正统计信息。同时修正各区间成绩的统计信息。
(7) 已统计成绩的学生人数i自增。
(8) 执行(5)。
(9) 格式化输出统计信息。
程序的主流程图如图54所示。


图54程序主流程图


其中,修正统计信息的执行策略如下。
(1) 最高成绩修正: 将接收得到的成绩temp_score与之前的统计值max_score比较,如果temp_score>max_score,则将新接收的成绩作为目前为止所有接收成绩中的最高值。
(2) 最低成绩修正: 将接收得到的成绩temp_score与之前的统计值min_score比较,如果temp_score<min_score,则将新接收的成绩作为目前为止所有接收成绩中的最低值。
(3) 各区间人数修正: 依次判定所接收的成绩在哪个区间范围内,然后将对应的区间统计值加1。


5.4.2程序代码设计
具体程序代码设计如下。
1. 代码设计
根据项目的描述,可在代码编辑器中完成如下代码的添加。

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;



namespace Score

{

class Program

{

static void Main(string[] args)

{

int nStudents; //定义变量,用于统计学生的人数

int temp_score; //定义变量,接收每次输入的成绩

//定义最大成绩与最小成绩

int max_score = 0, min_score = 0;

//统计成绩各区间内的成绩人数

int score_0_59 = 0, score_60_69 = 0, score_70_79 = 0,

score_80_89 = 0, score_90_100 = 0;

Console.WriteLine("--------学生成绩统计----------");



//接收全班人数

Console.WriteLine("请输入班级人数: nStudents = ");

string s = Console.ReadLine();

nStudents = Int32.Parse(s);



//接收并处理成绩

for (int i = 1; i <= nStudents; i++)

{

//接收成绩

Console.WriteLine("请输入第{0:d}个学生的成绩", i);

temp_score = Int32.Parse(Console.ReadLine());



//修改最高与最低成绩

if (i == 1)

{

max_score = temp_score;

min_score = temp_score;

}

else

{

if (max_score < temp_score)

max_score = temp_score;

if (min_score > temp_score)

min_score = temp_score;

}



//接收成绩所在区间的人数

int temp = temp_score / 10;

switch (temp)

{

case 10:

case 9:

Console.WriteLine("优秀"); //成绩优秀

score_90_100++;

break;

case 8:

Console.WriteLine("良好"); //成绩良好

score_80_89++;

break;

case 7:

Console.WriteLine("中等"); //成绩中等

score_70_79++;

break;

case 6:

Console.WriteLine("及格"); //成绩及格

score_70_79++;

break;

default:

Console.WriteLine("不及格"); //成绩不及格

score_0_59++;

break;

}

}



//统计信息输出

Console.WriteLine("--------学生成绩统计信息输出----------");

Console.WriteLine("全班共{0:d}人,其中最高成绩{1:f2}," +

"最低成绩{2:f2}", nStudents, max_score, min_score);

Console.WriteLine("成绩区间90~100的人数有{0:d}人," +

"所占比例为: {1:f2}%", score_90_100, score_90_100 * 100 / nStudents);

Console.WriteLine("成绩区间80~89的人数有{0:d}人," +

"所占比例为: {1:f2}%", score_80_89, score_80_89 * 100 / nStudents);

Console.WriteLine("成绩区间70~79的人数有{0:d}人," +

"所占比例为: {1:f2}%", score_70_79, score_70_79 * 100 / nStudents);

Console.WriteLine("成绩区间60~69的人数有{0:d}人," +

"所占比例为: {1:f2}%", score_60_69, score_60_69 * 100 / nStudents);

Console.WriteLine("成绩区间0~59的人数有{0:d}人," +

"所占比例为: {1:f2}%", score_0_59, score_0_59 * 100 / nStudents);

Console.ReadLine();

}

}

}

2. 代码分析
(1) 本项目的基本设计思想是依次接收成绩,每接收一个学生成绩后,紧接着做相关的统计、汇总工作。
(2) 对于每次成绩统计、汇总工作而言,其基本操作流程是相同的,因此可以将成绩处理作为一个循环体来处理。
(3) 程序中使用了一个for循环结构,其循环次数控制是通过计数器i来实现的。
(4) 程序中使用了一个switch分支结构,使得程序结构更为清晰,增加了程序的可读性。
5.4.3系统运行
系统运行之后,依据相关提示信息,输入学生的人数及其相应成绩,其运行结果如图55所示。


图55学生成绩统计的运行结果


5.5小结
在C#中提供了4种循环结构语句: for语句、while语句、do…while语句和foreach语句。
对于不同的实际运用,可以灵活选择不同的循环语句加以运用。对于for语句而言,一般用于循环次数明确的情况下; 而while与do…while语句则常常用于循环次数未知的情况下; while与for语句均为“预判定”或“预测试”语句,即在循环体执行前,首先进行是否满足循环的判定,然后才真正执行循环; 而do…while循环则是“后循环”或“后测试”循环,即首先执行一次循环体,然后判定循环是否能够继续进行下去,如可以继续进行,则再次执行循环体; foreach语句则是用于数组或集合元素中。
在所有的循环语句中,都应确保避免“死循环”的发生,这种情况的发生通常是由于循环条件的永久成立而引起的。一种有效控制循环进行的策略就是跳转语句的应用。C#中提供了goto语句、continue语句、break语句和return语句来完成程序控制权的转移。
5.6练一练
(1) 分别用for、while、do…while语句编写程序,求出100之内的自然数之和。
(2) 编写程序,要求输出如图56所示的图形。



图56程序运行结果