C#从入门到精通(第2版)
上QQ阅读APP看书,第一时间看更新

第6章 程序的基本结构

本章视频教学录像:38分钟

一个C#应用程序是由许多语句组合而成的。在C#程序设计中如何组织程序语句,实现程序功能,这是我们需要掌握的基本技能。程序中的语句可以逐条执行,也可以根据某一条件的不同取值选择执行不同的代码,或者根据条件重复执行一段代码,本章介绍的顺序结构、分支结构和循环结构就能满足这些要求。

本章要点(已掌握的在方框中打钩)

□ 顺序结构

□ 分支结构

□ 循环结构

6.1 顺序结构

本节视频教学录像:2分钟

顺序结构是程序代码中最基本的结构,简单地说就是逐条执行程序中的语句,从程序开始执行到程序结束为止。例如,

    01 double x;                      //定义一个double型变量x
    02 int y=3;                      //定义一个int型变量y,让y的值为3,可以读为把3赋给y
    03 int z=8;                       //定义一个int型变量z,把8赋给z
    04 x=y+z+Math.Sin(3.65);         //将表达式的结果赋给x,Math.Sin是使用Math类库中的Sin
                                  方法求正弦值

程序中包含4条语句,构成一个顺序结构的程序。语句1定义一个double型变量x,语句2定义int型变量y并赋值,语句3定义int型变量z并赋值,语句4根据y、z的值进行运算并将结果赋值给x。

可以看出,顺序结构中,每一条语句都需要执行并且只执行一次,语句执行的先后次序与语句在顺序结构程序中出现的先后次序一致。

提示

当程序中的语句符合顺序结构的特点时,即每条语句都需要执行且只需要执行一次,则可以使用顺序结构。

6.2 分支结构

本节视频教学录像:12分钟

与我们日常生活中的许多情况类似,程序设计过程中,经常需要根据条件进行判断,然后选择要执行的语句序列。分支结构就是根据条件的不同选择执行程序中的不同分支,每个分支对应一个语句序列。本节主要介绍实现分支结构的条件语句,有时也称为选择语句。

6.2.1 条件语句

条件语句就是对条件进行判断,根据判断结果选择执行不同的分支。C#中提供了多种形式的条件语句,包括if语句、if…else语句和switch语句。

⑴ 单分支结构的if语句。

语法格式如下。

    if(条件表达式)
    {语句序列}

如果条件成立(条件表达式的值为true),就执行条件表达式后面的语句序列中的语句。如果条件不成立(条件表达式的值为false),则跳过语句序列,继续执行if语句之后的语句。一般情况下,语句序列要用花括号括起来。例如,

    01 int score=int.Parse(Console.ReadLine());   //输入成绩,保存在变量score中
    02 if(score>=60)                             //条件为score大于等于60
    03 {
    04    Console.WriteLine("及格!");            //条件成立,则输出"及格!"
    05 }
    06 if(score<60)                              //条件为score小于60
    07 {
    08    Console.WriteLine("不及格!");          //条件成立,则输出"不及格!"
    09 }

使用ReadLine()方法从键盘输入成绩,调用int.Parse()方法将输入值转换为int类型,保存在变量score中。第一个if语句的条件表达式为“score >= 60”,当条件成立,输出“及格! ”;条件不成立则跳过第一个if语句,转去执行第二个if语句。第二个if语句的条件表达式为“score < 60”,当条件成立,输出“不及格! ”;条件不成立则跳过第二个if语句,程序结束。两个if语句的条件表达式是相互独立,互不影响的。

提示

if语句中的条件表达式的值应为bool型,表达式的值为true则条件成立,表达式的值为false则条件不成立。

下面的例子进一步说明了if语句的使用。

【范例6-1】 输入学生成绩,输出学生的成绩等级。

⑴ 在Visual Studio 2013中新建控制台应用程序,项目名称为“ScoreByIf”。

⑵ 在program.cs的main方法中输入以下代码。

        01  Console.WriteLine("请输入成绩(0-100):");
        02  int score=int.Parse(Console.ReadLine());
    03  if(score>=90)
    04  {
    05         Console.WriteLine("优秀!");
    06  }
    07  if(score>=80&&score<90)
    08  {
    09         Console.WriteLine("良好!");
    10  }
    11  if(score>=70&&score<80)
    12  {
    13         Console.WriteLine("中等!");
    14  }
    15  if(score>=60&&score<70)
    16  {
    17         Console.WriteLine("及格!");
    18  }
    19  if(score<60)
    20  {
    21         Console.WriteLine("不及格!");
    22  }
    23  Console.ReadKey();

⑶ 双分支结构的if…else语句。

语法格式如下。

    if(条件表达式)
    {语句序列1}
    else
    {语句序列2}

其作用是如果条件表达式值为true,执行if后面的语句序列1;如果条件表达式值为false,执行else后面的语句序列2。

    int score=int.Parse(Console.ReadLine());      //输入成绩,保存在变量score中
    if(score>=60)                                //条件为score大于等于60
    {
        Console.WriteLine("及格!");             //条件成立,则输出"及格!"
    }
    else
    {
        Console.WriteLine("不及格!");           //条件不成立,则输出"不及格!"
    }

对比if语句的例子,可以看出,以上代码实现了使用一个if…else语句体现两个if语句的功能。思考一下,什么时候可以这样做?

⑷ 多分支结构。

if语句实现多分支结构的语法如下。

    if(表达式1)
    { 语句序列1        //表达式1的值为true时执行的语句}
    else if(表达式2)
    { 语句序列2        //表达式2的值为true时执行的语句}
    …
    else if(表达式n)
    {语句序列n         //表达式n的值为true时执行的语句}
    else
    {语句序列n+1       //表达式1到n的值都为false时执行的语句}

注意,当表达式1的值为true,执行语句序列1,然后if语句的执行结束。只有当表达式1的值为false时,才需要考虑表达式2的值,表达式2的值为true,则执行语句序列2,然后结束if语句。只有当表达式2的值为false,才需要考虑表达式3的值。依此类推,只有表达式1、2、3…n-1的值都为false时,才需要考虑表达式n的值,这时如果表达式n的值为true,则执行语句序列n,然后结束if语句,否则执行语句序列n+1。

【范例6-2】 使用多分支结构实现成绩等级评定。

⑴ 在Visual Studio 2013中新建控制台应用程序,项目名称为“ScoreByIfelse”。

⑵ 在program.cs的main方法中输入以下代码。

    01  Console.WriteLine("请输入成绩(0-100):");
    02  int score=int.Parse(Console.ReadLine());
    03  if(score>=90)
    04  {
    05         Console.WriteLine("优秀!");
    06  }
    07  else if(score>=80)
    08
    09         Console.WriteLine("良好!");
    10  }
    11  else if(score>=70)
    12  {
    13         Console.WriteLine("中等!");
    14  }
    15  else if(score>=60)
    16  {
    17         Console.WriteLine("及格!");
    18  }
    19  else
    20  {
    21         Console.WriteLine("不及格!");
    22  }
    23  Console.ReadKey();

【范例分析】

使用多分支结构可以让程序看起来更加简洁,但是要注意多分支结构中多个条件表达式之间的关系。例如,上面的代码中要执行条件表达式“score >= 80”后的语句“Console.WriteLine("良好!");”的前提是条件表达式“score >= 90”为false,也就是说,当条件score >= 80 && score < 90成立时才执行语句“Console.WriteLine("良好!");”

6.2.2 switch语句

分支结构也可以使用switch语句来实现,switch语句能够根据表达式的值来选择要执行的代码。if语句只能测试单个条件,如果需要测试多个条件,则需要书写冗长的代码。而switch语句能有效地避免冗长的代码,并能测试多个条件。switch语句的语法如下。

    switch (表达式)
    {
        case  常量表达式1: 语句序列1
        break;
        case  常量表达式2: 语句序列2
        break;
        …
        case  常量表达式n: 语句序列n
        break;
        default:             语句序列n+1
        break;
    }

switch语句的执行过程是:计算switch语句中表达式的值,再依次与1~n个常量比较,当表达式的值与某个case后面的常量相等时,则执行该case后面的语句,然后执行break语句,跳出switch结构。程序执行时,从匹配常量的相应case处入口,一直执行到break语句或到达switch结构的末尾为止。如果几个常量都不等于switch中表达式的值,则执行default处的语句。

每个case后面的语句可以是单条语句或空语句,也可以是多条语句,而构成一个程序段。这里的语法上允许有多条语句,因此不必加花括号写成复合语句的形式。

【范例6-3】 使用switch语句实现成绩等级评定。

⑴ 在Visual Studio 2013中新建控制台应用程序,项目名称为“ScoreBySwitch”。

⑵ 在program.cs的main方法中输入以下代码。

    01   Console.WriteLine("请输入成绩(0-100):");
    02   int score=int.Parse(Console.ReadLine());
    03   switch(score/10)
    04   {
    05         case 10:
    06         case 9:
    07         Console.WriteLine("优秀!");
    08         break;
    09         case 8:
    10         Console.WriteLine("良好!");
    11         break;
    12         case 7:
    13         Console.WriteLine("中等!");
    14         break;
    15         case 6:
    16         Console.WriteLine("及格!");
    17         break;
    18         default:
    19         Console.WriteLine("不及格!");
    20         break;
    21   }
    22   Console.ReadKey();

【范例分析】

在这个程序中,从键盘上输入学生成绩,存入变量score中,使用score/10作为switch语句的表达式,表达式的值为整型,与case后的常量表达式的值类型相同。当表达式score/10的值与某个case后的常量表达式的值相等时,跳转到该case结构后的语句序列开始执行,直到switch语句结束或者遇到break语句。可以多种情况共用一个语句序列,如score/10的值为9和10两种情况,学生成绩等级都是“优秀”,case 10后面为空,与case 9共用一个语句序列。这种特性的使用需要特别注意,需要在每个语句序列的最后加上break语句,保证被执行语句序列得到执行后跳转到switch语句的结束位置。

6.3 循环结构

本节视频教学录像:11分钟

在程序开发中,经常需要反复执行某段代码。为了避免重复输入相同代码,同时提高程序代码的可读性,引入了循环结构,需要反复执行的代码称为循环体。循环结构使用循环条件控制循环体代码的执行与否,循环条件中通常使用一个特殊的变量——循环变量,根据循环变量的值来确定循环条件是否成立。C#提供的循环语句有for语句、while语句、do_while语句和foreach语句。

6.3.1 for循环

for循环语句语法为:

    for(表达式1;表达式2;表达式3)
    {
    循环体
    }

for语句的执行过程如下。

① 计算表达式1,为循环变量赋初值。

② 计算表达式2,检查循环条件,若表达式2的值为true, 则执行一次循环体;若其为false,控制转出循环结构。

③ 执行完一次循环体后,计算表达式3,对控制变量进行增量或减量操作,再重复第⑵步操作。

提示

for后面括号中的3个表达式之间用分号(“;”)分开。表达式1和表达式3一般为赋值表达式,表达式1为循环控制变量赋初值,表达式3改变循环变量的值。表达式2一般为关系表达式或逻辑表达式,作为控制循环体结束条件,当表达式值为true时,循环继续;当表达式值为false时,循环停止。

【范例6-4】 用for循环计算1+2+3+…+100的和。

⑴ 在Visual Studio 2013中新建控制台应用程序,项目名称为“SumByFor”。

⑵ 在program.cs的main方法中输入以下代码。

        01 int sum; //定义累加变量sum
    02 sum=0;                        //累加变量赋初始值为0
    03 Console.WriteLine("计算1+2+3+…+100的和:");
    04 for(int i=1;i<=100;i++)        //循环变量i从1开始到100变化循环,i每次增1
    05  {                            //循环,累加求和
    06    sum=sum+i;                 //累加求和
    07  }
    08  Console.WriteLine("1+2+3+…+100={0}",sum);
    09  Console.ReadKey();

【范例分析】

在这个程序中,表达式1(int i=1)为循环变量i赋初值1,该表达式只在for循环开始时执行一次。表达式2(i<= 100)是循环条件,循环的每次执行都要先判断循环条件是否成立,成立则执行循环体,这里是把i的当前值累加到变量sum上。表达式3(i++)在循环的每一次执行结束后得到执行,保证每次循环i的值都比上一次加1,使得最终循环条件不成立,循环终止。

6.3.2 while循环

while循环的语法为:

    while (表达式)
    {
        循环体
    }

while循环执行的过程是:先计算while后面圆括号内表达式的值,判断循环条件是否成立。当表达式值为true时,执行循环体,然后再次判断表达式的值;当表达式的值仍为“true”时,则再次执行循环体语句,重复上述执行过程;当表达式的值为false时则退出循环。

【范例6-5】 用while循环计算1+2+3+…+100的和。

⑴ 在Visual Studio 2013中新建控制台应用程序,项目名称为“SumByWhile”。

⑵ 在program.cs的main方法中输入以下代码。

    01 int i,sum;              //定义int变量i用于控制循环次数,sum用于累加求和
    02 i=1;                   //循环变量赋初始值为1
    03 sum=0;                 //累加器变量sum赋初值为0
    04 while(i<=100)          //while循环,当i小于等于100时循环
    05 {                      //循环体,累加求和
    06    sum=sum+i;          //累加求和
    07    i++;                //循环变量的值增1
    08 }
    09 Console.WriteLine("1+2+3+…+100={0}",sum);     //输出累加的结果5050
    10 Console.ReadKey();

提示

while循环中只有一个表达式,相当于for循环的表达式2,即循环条件。为循环变量赋初值需要在while循环之前进行,修改循环变量的值的语句通常放在循环体的最后。按照这一原则,我们可以很方便地实现for循环和while循环的相互转换。

6.3.3 do-while循环

循环语句可以分为两大类,即“当”型循环和“直到”型循环。

for循环和while循环属于“当”型循环,循环执行时,首先判断循环条件是否成立,当条件成立则执行循环体,然后再次判断循环条件,条件成立则再次执行循环体,如此反复,当循环条件不成立时则结束循环。

do-while循环的语法为:

    do
    {
        循环体
    } while (表达式);

do-while语句实现了另一种循环——“直到”型循环,先无条件执行一次循环体,然后判断循环条件,条件成立则再次执行循环体,然后再次判断条件,条件成立则第三次执行循环体,依此类推,直到循环条件不成立结束循环。

【范例6-6】 用do-while循环计算1+2+3+…+100的和。

⑴ 在Visual Studio 2013中新建控制台应用程序,项目名称为“SumByDoWhile”。

⑵ 在program.cs的main方法中输入以下代码。

    01  int i,sum;
    02  i=1;                                          //循环变量赋初始值
    03  sum=0;
    04  do
    05  {                                             //循环体
    06         sum=sum+i;                             //累加求和
    07         i++;                                   //改变循环体变量的值,i每次增1
    08  }while(i<=100);
    09 Console.WriteLine("1+2+3+…+100={0}",sum);     //输出结果
    10  Console.ReadKey();

6.3.4 foreach循环

foreach循环用于遍历整个集合或数组,可以获取集合中的所有对象,不需要给出循环变量和循环条件,也不需要给循环变量赋初值和修改循环变量的值。foreach循环简单易用、代码简洁,在以后的学习中会经常用到。语法如下。

    foreach(数据类型 局部变量in集合或者数组)
    {
        循环体
    }

foreach语句中,需要根据集合或者数组的元素类型,定义一个相同类型的局部变量。foreach语句执行时,首先判断集合中是否存在元素,若存在,则将集合中的第1个元素赋值给局部变量,执行循环体,然后判断集合中是否还有剩余元素。若存在,则将下一个元素赋值给局部变量,再次执行循环体,依此类推,将集合中所有元素逐个赋值给局部变量,根据该局部变量的值执行循环体。

例如,

        //定义数组week,使用foreach循环遍历数组week,输出数组中的每个元素
    01  string[]week={"Mon","Tue","Wed","Thu","Fri","Sat","Sun"};   //定义数组并赋初值
    02  foreach(string s in week)          //遍历数组元素,局部变量s的类型与数组元素类型相同
    03 {
    04         Console.WriteLine(s);    //输出局部变量s的当前值
    05  }

6.4 循环嵌套

本节视频教学录像:6分钟

循环嵌套是C#程序设计的一种高级技巧。循环嵌套就是在循环体中还可以使用循环语句,前面讲过的几种循环都可以互相嵌套。在程序设计过程中使用循环嵌套需要注意区分外层循环和内层循环,外层循环执行一次,内层循环执行一遍。外层循环和内层循环的循环控制要互相独立,互不影响。

【范例6-7】 输出九九乘法表。

⑴ 在Visual Studio 2013中新建控制台应用程序,项目名称为“MultiTable”。

⑵ 在program.cs的main方法中输入以下代码。

    01  for(int i=1;i<=9;i++)
    02  {
    03         for(int j=1;j<=i;j++)
    04         {
    05                Console.Write("{0}*{1}={2}",i,j,i*j);
    06                if(i!=j)Console.Write(",");
    07         }
    08                Console.WriteLine();
    09  }
    10  Console.ReadKey();

程序输出结果如下图所示。

【范例6-8】 输出小于100的素数。一个大于1的自然数,除了1和它本身外,不能被其他自然数整除(除0以外)的数称为素数。

⑴ 在Visual Studio 2013中新建控制台应用程序,项目名称为“PrimeNumber”。

⑵ 在program.cs的main方法中输入以下代码。

    01  Console.WriteLine("小于100之中的素数有:");      //输出提示信息
    02  for(int i=2;i<100;i++)                 //外层循环,i从2到100循环分别判断i是否是素数
    03  {
    04         bool isPrime=true;              //定义isPrime变量,标志某个数是否为素数
    05         for(int j=2;j<i-1;j++)          //内层循环,j从2到i-1循环,看j能否整除i
    06         {
    07                if(i % j==0)                        //如果i能整除以j,说明i不是素数
    08                {
    09                       isPrime=false;             //i不是素数,设置isPrime=false
    10                       break;                     //跳出内层循环,继续外层循环
    11                }
    12         }                                        //内层循环结束
    13         if(isPrime)                              //i如果是素数则输出
    14         {
    15                Console.WriteLine("{0}",i);       //输出素数i
    16         }
    17  }                                               //外层循环结束
    18  Console.ReadKey();

在上面的代码中出现了break语句,它的功能是跳出break语句所处的循环,转去执行循环结构后面的语句。类似的,C#中提供了continue语句,continue语句的功能是结束本次循环,通常配合if语句使用,当某个条件成立则终止本次循环,即忽略循环体中continue后面的语句,接着进入本循环结构的下一次循环。

6.5 高手点拨

本节视频教学录像:4分钟

6.5.1 循环变量的使用

循环变量在循环结构中的作用至关重要,循环变量赋值不当,程序就无法正常执行,多数循环结构程序出错都与循环变量的错误使用有关。要正确使用循环变量,需要注意以下几点。

循环变量的声明和赋初值要在循环体之外,for循环中循环变量的声明和赋初值通常通过for语句后括号内的表达式1实现。如果把为循环变量赋初值的语句放在循环体首部,则循环体每次执行都将为循环变量赋初值,有可能出现死循环。

例如,

    int i;
    while(i<=100)     //while循环,当i小于等于100时循环
    {
        i=1;                //错误,每次执行循环体都将为循环变量赋初值
        …                    //循环体
        i++;
    }

在循环体的最后一般要有语句修改循环变量的值,使循环条件有可能不成立,从而终止循环结构的执行,for循环中通常使用for语句后的表达式3来修改循环变量的值。需要注意的是,如果循环结构在for语句中定义循环变量,该变量被视为局部变量,当循环执行完毕后变量即被释放,在循环语句之外再次引用该循环变量将出错。

例如,

    for(int i=0;i<=100;i++)
    {
        …
    }
    Console.WriteLine(i);     //错误,循环变量i已经不存在

循环嵌套时,外层循环和内层循环的循环变量是相互独立的,必须定义两个不同的循环变量,否则循环嵌套将无法按照我们的预期执行。注意,内层循环体中可以引用外层循环的循环变量,但不能修改外层循环变量的值。

例如,

    for(int i=0;i<=10;i++)
    {
        for(int k=0;k<=10;k++)
        {
              Console.WriteLine(i);     //内层循环引用外层循环的循环变量
        }
    }

6.5.2 特殊形式的循环结构

1. 无条件循环

需要注意的是,while(true){ }形式的循环结构也是经常使用的,循环体无条件执行。但在循环体中通常使用一个条件语句,当某个条件成立时,使用break语句终止当前循环语句,转去执行循环语句之后的语句。

例如,

    while(true)
    {
    …
        if(条件表达式)break;
        …
    }

2.提前终止循环语句或提前终止循环体的一次执行

循环结构中,需要提前终止循环语句,这时通常使用条件语句,当某个条件成立时,使用break语句结束循环语句,转去执行循环体之后的语句。此处与无条件循环中的情况类似。

某次执行循环体时,需要提前终止循环体的该次执行。这时通常使用条件语句,当某个条件成立时,使用continue语句结束循环体的本次执行,转去执行表达式3,修改循环变量,然后根据表达式2的值判断是否继续循环体的下一次执行。

例如,

    for(表达式1;表达式2;表达式3)
    {
        …
        if(条件表达式)continue;
        …
    }

6.6 实战练习

操作题

1. 按照复印中心的收费规定,复印前50张为每张0.5元,以后为每张0.2元。试编写一段程序,要求输入复印张数,然后显示总价格。

2. 编写一段程序,求两个正整数的最大公约数和最小公倍数。