的基础。接下来就应该对框图中的那些比较抽象的、用文字描述的程序模块作进一步的分析 细化,每次细化的结果仍用结构化框图表示。最后,对如何求解问题的所有细节都弄清楚了, 就可以根据这些框图直接写出相应的程序代码。这就是所谓的“自顶向下,逐步求精”的程 序设计方法。在分析的过程中用结构化框图表示解题思路的优点是框图中的每个程序模块与 其他程序模块之间的关系非常简明,每次可以只集中精力分解其中的一个模块而几乎不影 响整个程序的结构 23C++的控制结构 23.1顺序结构 在用C艹+编写程序时,实现顺序结构的方法非常简单:只需将两个语句顺序排列即可。 如例1-1中交换两个整数的值的程序段 就是顺序结构 232选择结构 C++的选择结构是通过if-else语句实现的。其格式为 if(<表达式>) <内嵌语句1>; <内嵌语句2> 将其与图2-3比较,就会发现“程序模块1”和“程序模块2”分别对应于 if-else语句中的 内嵌语句1”和“内嵌语句2”。一般来说,内嵌语句可以是各种可以执行的语句,甚至包 括if-else语句和后面要介绍的循环语句。但是如果“程序模块1”和“程序模块2”比较复 杂,不能简单地用一条语句实现时怎么办呢?这时可以使用由一对花括号“{}”括起来的程 序段落代替“语句1”和“语句2”,即 if(<表达式>) else 这种用花括号括起来的程序段落又称为分程序。分程序是C++中的一个重要概念。具
第 2 单元 控制结构 - 22 - 的基础。接下来就应该对框图中的那些比较抽象的、用文字描述的程序模块作进一步的分析 细化, 每次细化的结果仍用结构化框图表示。最后, 对如何求解问题的所有细节都弄清楚了, 就可以根据这些框图直接写出相应的程序代码。这就是所谓的“自顶向下, 逐步求精”的程 序设计方法。在分析的过程中用结构化框图表示解题思路的优点是框图中的每个程序模块与 其他程序模块之间的关系非常简明, 每次可以只集中精力分解其中的一个模块而几乎不影 响整个程序的结构。 2.3 C++的控制结构 2.3.1 顺序结构 在用C++编写程序时, 实现顺序结构的方法非常简单: 只需将两个语句顺序排列即可。 如例 1-1 中交换两个整数的值的程序段: r = p; p = q; q = r; 就是顺序结构。 2.3.2 选择结构 C++的选择结构是通过 if-else 语句实现的。其格式为: if(<表达式>) <内嵌语句 1>; else <内嵌语句 2>; 将其与图 2-3 比较, 就会发现“程序模块 1”和“程序模块 2”分别对应于 if-else 语句中的 “内嵌语句 1”和“内嵌语句 2”。一般来说, 内嵌语句可以是各种可以执行的语句, 甚至包 括 if-else 语句和后面要介绍的循环语句。但是如果“程序模块 1”和“程序模块 2”比较复 杂, 不能简单地用一条语句实现时怎么办呢? 这时可以使用由一对花括号“{}”括起来的程 序段落代替“语句 1”和“语句 2”, 即: if(<表达式>) { …... } else { …... } 这种用花括号括起来的程序段落又称为分程序。分程序是C++中的一个重要概念。具
第2单元控制结构 体说来,一个分程序具有下述形式 局部数据声明部分〉 执行语句段落〉 即分程序是由花括号括起来的一组语句。当然,分程序中也可以再嵌套新的分程序。分程序 是C++程序的基本单位之 分程序在语法上是一个整体,相当于一个语句。因此分程序可以直接和各种控制语句直 接结合使用,用以构成C++程序的各种复杂的控制结构。在分程序中声明的变量的作用范围 仅限于该分程序内部 在讧语句中用<表达式>的值来判断程序的流向,如果<表达式>的值不为0,表示条件成 此时执行<内嵌语句1>;否则(即<表达式>的值等于0)执行<内嵌语句2>。作条件用 的表达式中通常含有比较运算符或逻辑运算符,例如 /x大于y则表达式的值非0,否则表达式的值为0 x>=0.0&&x<=1.0//x的值在0和1之间则表达式的值非0,否则为0 其中的逻辑运算符“&&”表示“并且”。这类表达式在其中的比较或逻辑运算的结果为真 时取非0值,为假时取值0,因此正好可以用来在if语句中表示条件。关于这些表达式的使 用方法,还要在42:“逻辑运算符和逻辑表达式”中做比较详细的介绍。 图2-4中的只有一个分支的选择结构可以使用不含else部分的i语句表示 if(<表达式>) <内嵌语句〉 f(<表达式>) 即如果<表达式>的值不为0时执行<内嵌语句>或分程序,否则直接执行if语句后面的其他 语句 233循环结构 hile型循环结构可以使用 while语句实现 while(<表达式>) 循环体〉 其中的<循环体>可以是一个语句,也可以是一个分程序 while(<表达式>)
第 2 单元 控制结构 - 23 - 体说来, 一个分程序具有下述形式 { <局部数据声明部分> <执行语句段落> } 即分程序是由花括号括起来的一组语句。当然, 分程序中也可以再嵌套新的分程序。分程序 是C++程序的基本单位之一。 分程序在语法上是一个整体, 相当于一个语句。因此分程序可以直接和各种控制语句直 接结合使用, 用以构成C++程序的各种复杂的控制结构。在分程序中声明的变量的作用范围 仅限于该分程序内部。 在 if 语句中用<表达式>的值来判断程序的流向, 如果<表达式>的值不为 0, 表示条件成 立, 此时执行<内嵌语句 1>; 否则 ( 即<表达式>的值等于 0 ) 执行<内嵌语句 2>。作条件用 的表达式中通常含有比较运算符或逻辑运算符, 例如 x>y // x 大于 y 则表达式的值非 0, 否则表达式的值为 0 x>=0.0 && x<=1.0 // x 的值在 0 和 1 之间则表达式的值非 0, 否则为 0 其中的逻辑运算符“&&”表示“并且”。这类表达式在其中的比较或逻辑运算的结果为真 时取非 0 值, 为假时取值 0, 因此正好可以用来在 if 语句中表示条件。关于这些表达式的使 用方法, 还要在 4.2:“逻辑运算符和逻辑表达式”中做比较详细的介绍。 图 2-4 中的只有一个分支的选择结构可以使用不含 else 部分的 if 语句表示: if (<表达式>) <内嵌语句>; 或者 if (<表达式>) { …... } 即如果<表达式>的值不为 0 时执行<内嵌语句>或分程序, 否则直接执行 if 语句后面的其他 语句。 2.3.3 循环结构 while 型循环结构可以使用 while 语句实现: while (<表达式>) <循环体> 其中的<循环体>可以是一个语句, 也可以是一个分程序: while(<表达式>)
第2单元控制结构 whle语句的执行过程见图2-5。当表达式的结果不为0时反复执行其循环体内的语句 或者分程序,直到表达式的值为0时退出循环。在设计 while型循环时要注意在其循环体内 应该有修改<表达式>的部分,确保在执行了一定次数之后可以退出循环,否则就成了“死循 环”,一旦程序进入这里,将永远在循环结构中兜圈子而无法结束。 do- while型循环结构可以使用do- while语句实现: <循环体〉 } while(<表达式>); do- while型循环和 while型循环最大的不同是 执行表达式1 do- while循环的循环体最 少执行一次,而 while型循 环的循环体可能一次也不执 行。这一点可以很容易地从 新程序模块 图25和图26的比较中看 执行表达式3 除此而外,C++中还有 种for语句,用来实现一 类比较复杂的循环结构。其 图2-10for循环结构 格式为 for(<表达式1>;<表达式2>;<表达式3》) <循环体〉 其控制流程见图2-10 和 while语句的情况类似,for语句的循环体也可以是一条语句,或者一个分程序。for语 句最常见的用途是构造指定重复次数的循环结构。例如 for(i=0: i<10 1) 用于实现重复10次的循环。虽然用 while循环也可以构造出这样的循环,但使用for语句更 简单、直观。特别是在处理数组时,大多数程序员都喜欢使用for语句
第 2 单元 控制结构 - 24 - { …... } while 语句的执行过程见图 2-5。当表达式的结果不为 0 时反复执行其循环体内的语句 或者分程序, 直到表达式的值为 0 时退出循环。在设计 while 型循环时要注意在其循环体内 应该有修改<表达式>的部分, 确保在执行了一定次数之后可以退出循环, 否则就成了“死循 环”, 一旦程序进入这里, 将永远在循环结构中兜圈子而无法结束。 do-while 型循环结构可以使用 do-while 语句实现: do { <循环体> }while (<表达式>); do-while 型循环和 while 型循环最大的不同是 do-while 循环的循环体最 少执行一次, 而 while 型循 环的循环体可能一次也不执 行。这一点可以很容易地从 图 2-5 和图 2-6 的比较中看 出。 除此而外, C++中还有 一种 for 语句, 用来实现一 类比较复杂的循环结构。其 格式为: for (<表达式 1>; <表达式 2>; <表达式 3>) <循环体> 其控制流程见图 2-10。 和 while 语句的情况类似, for 语句的循环体也可以是一条语句, 或者一个分程序。for 语 句最常见的用途是构造指定重复次数的循环结构。例如 for (i=0; i<10; i=i+1) { …... } 用于实现重复 10 次的循环。虽然用 while 循环也可以构造出这样的循环, 但使用 for 语句更 简单、直观。特别是在处理数组时, 大多数程序员都喜欢使用 for 语句。 执行表达式1 循 环 体 表达式2<>0? 执行表达式3 否 是 新程序模块 图2-10 for循环结构
第2单元控制结构 24伪代码 前面介绍了利用流程图实现自顶向下的程序设计方法。实际上,在使用C++的程序员们 中还流行着一种利用伪代码进行自顶向下程序设计的方法。伪代码使用C++的几种控制语 句和自然语言结合起来描述算法,比画流程图省时省力,且更容易转化为程序。 例2-2编出“验证”哥德巴赫猜想的程序 算法:对图29中的各程序模块作进一步的分解。这一次采用伪代码表示程序求精 分解的结果。“验证”哥德巴赫猜想首先要解决如何生成和测试素数的问题。素数即质数,即 除了1和自身之外没有其他因子的正整数。大多数素数都不能简单地根据某个数学表达式计 算出来,只能通过逐个检验正整数是否符合素数的定义的方法得出。因此,可以先编写一个 生成素数表的函数,用其生成给定范围内所有的素数并存放在一个素数表中,这样“求一个 素数”或检查一个数是否素数的工作就可以转化为对素数表的查询了 我们使用“筛法”来生成素数表,这是生成素数最古老,同时也是最有效的方法,由古 希腊的哲学家兼数学家埃拉托色尼提出。因为准备验证的最大偶数小于M,所以用到的最大 素数也不会超过M。因此,列出0到M之间的所有自然数 0,1,2,3,4,5,6,7,8,…,M- 然后将所有2的倍数,3的倍数,5的倍数,…,直到M2的倍数均从表中删去(置换为0) 即可。 我们用数组 Primelist存放生成的素数。按上法生成的素数表有一个特点,即如果 Primelist[x]≠0,则x为素数,否则x为合数这样,就可以很方便地根据该素数生成素数,或 者判别一个数是否素数了。我们将生成素数表的工作编成一个函数,其原型为 void CreatePrimeList(int PrimeList[) 用伪代码描述生成素数表的算法如下 将 PrimeList的各元素设置为2到M-1之间的自然数 分别从表中去掉已经确定的各素数的倍数(将其置换为0); 第1步可以用一个for型的循环实现 for(i=0: i<M: i=i+1) Primelist[i] =i 第2步稍微复杂些。我们使用工作变量i指示出最后确定的素数的位置,在表中将数组 元素 Prelist[的倍数转换为0: while(i<M/2) for (j=i+l: j<M; j=j+1) if( PrimeList [j]≠0且是 Primelist[i]的倍数)
第 2 单元 控制结构 - 25 - 2.4 伪代码 前面介绍了利用流程图实现自顶向下的程序设计方法。实际上, 在使用C++的程序员们 中还流行着一种利用伪代码进行自顶向下程序设计的方法。伪代码使用C++的几种控制语 句和自然语言结合起来描述算法, 比画流程图省时省力, 且更容易转化为程序。 [例 2-2] 编出“验证”哥德巴赫猜想的程序。 算 法:对图 2-9 中的各程序模块作进一步的分解。这一次采用伪代码表示程序求精 分解的结果。“验证”哥德巴赫猜想首先要解决如何生成和测试素数的问题。素数即质数, 即 除了 1 和自身之外没有其他因子的正整数。大多数素数都不能简单地根据某个数学表达式计 算出来, 只能通过逐个检验正整数是否符合素数的定义的方法得出。因此,可以先编写一个 生成素数表的函数, 用其生成给定范围内所有的素数并存放在一个素数表中, 这样“求一个 素数”或检查一个数是否素数的工作就可以转化为对素数表的查询了。 我们使用“筛法”来生成素数表, 这是生成素数最古老, 同时也是最有效的方法, 由古 希腊的哲学家兼数学家埃拉托色尼提出。因为准备验证的最大偶数小于 M, 所以用到的最大 素数也不会超过 M。因此, 列出 0 到 M 之间的所有自然数: 0, 1, 2, 3, 4, 5, 6, 7, 8, ..., M−1 然后将所有 2 的倍数, 3 的倍数, 5 的倍数, ..., 直到 M/2 的倍数均从表中删去 ( 置换为 0 ) 即可。 我们用数组 PrimeList 存放生成的素数。按上法生成的素数表有一个特点, 即如果 PrimeList[x]≠0, 则 x 为素数, 否则 x 为合数。这样,就可以很方便地根据该素数生成素数, 或 者判别一个数是否素数了。我们将生成素数表的工作编成一个函数, 其原型为: void CreatePrimeList(int PrimeList[]); 用伪代码描述生成素数表的算法如下: 将 PrimeList 的各元素设置为 2 到 M-1 之间的自然数; 分别从表中去掉已经确定的各素数的倍数 ( 将其置换为 0 ) ; 第 1 步可以用一个 for 型的循环实现: for(i=0; i<M; i=i+1) PrimeList[i] = i; 第 2 步稍微复杂些。我们使用工作变量 i 指示出最后确定的素数的位置, 在表中将数组 元素 PrimeList[i]的倍数转换为 0: i = 2; while(i<M/2) { for(j=i+1; j<M; j=j+1) if(PrimeList[j]≠0 且是 PrimeList[i]的倍数)