ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 2.1 控制结构(Control Structures) 一个程序的语句往往并不仅限于线性顺序结构。在程序的执行过程中它可能被分成两支执行,可能重复某些语句,也可能根据一些判断结果而执行不同的语句。因此C++ 提供一些控制结构语句 (control structures) 来实现这些执行顺序。 为了介绍程序的执行顺序,我们需要先介绍一个新概念:语句块(block of instructions)。一个语句块(A block of instructions) 是一组互相之间由分号semicolons (;) 分隔开但整体被花括号curly bracket signs: { and }括起来的语句。 本节中我们将看到的大多数控制结构允许一个通用的statement做参数,这个statement根据需要可以是一条语句,也可以是一组语句组成的语句块。如果我们只需要一条语句做statement,它可以不被括在花括号 ({}) 内。但如果我们需要多条语句共同做statement,则必须把它们括在花括号内 ({}) 以组成一个语句块。 ### 条件结构Conditional structure: if and else 条件结构用来实现仅在某种条件满足的情况下才执行一条语句或一个语句块。它的形式是: `if (condition) statement` 这里 condition 是一个将被计算的表达式(expression)。如果表达式值为真,即条件(condition)为true,statement 将被执行。否则,statement 将被忽略(不被执行),程序从整个条件结构之后的下一条语句继续执行。 例如,以下程序段实现只有当变量x存储的值确实为100的时候才输出"x is 100": if (x == 100) cout 如果我们需要在条件condition为真true的时候执行一条以上的语句,我们可以花括号{}将语句括起来组成一个语句块: if (x == 100) { cout << "x is "; cout << x; } 我们可以用关键字else 来指定当条件不能被满足时需要执行的语句,它需要和if 一起使用,形式是: `if (condition) statement1 else statement2` 例如: if (x == 100) cout << "x is 100"; else cout 以上程序如果x的值为100,则在屏幕上打出x is 100,如果x不是100,而且也只有在x不是100的时候,屏幕上将打出x is not 100。 多个if + else 的结构被连接起来使用来判断数值的范围。以下例子显示了如何用它来判断变量 x中当前存储的数值是正值,负值还是既不正也不负,即等于0 。 if (x > 0) cout << "x is positive"; else if (x < 0) cout << "x is negative"; else cout 记住当我们需要执行多条语句时,必须使用花括号{}将它们括起来以组成一个语句块block of instructions。 ### 重复结构 Iteration structures 或循环loops 循环Loops 的目的是重复执行一组语句一定的次数或直到满足某种条件。 #### while 循环 格式是: `while (表达式expression) 语句statement` 它的功能是当expression 的值为真true时重复执行statement。 例如,下面我们将用while循环来写一个倒计数程序: ~~~ | // custom countdown using while #include int main () { int n; cout "; cin >> n; while (n>0) { cout << n << ", "; --n; } cout << "FIRE!"; return 0; } | Enter the starting number > 8 8, 7, 6, 5, 4, 3, 2, 1, FIRE! | ~~~ 程序开始时提示用户输入一个倒计数的初始值。然后while 循环开始,如果用户输入的数值满足条件n>0 (即 n 比0 大),后面跟的语句块将会被执行一定的次数,直到条件 (n>0) 不再满足(变为false)。 以上程序的所有处理过程可以用以下的描述来解释: 从**main**开始: 1. 用户输入一个数值赋给n. 2. while语句检查(n>0)是否成立,这时有两种可能: * true: 执行statement (到第3步) * false: 跳过statement. 程序直接执行第5步. 3. 执行statement: `cout << n << ", "; --n;` (将n 的值打印在屏幕上,然后将n 的值减1). 4. 语句块结束,自动返回第2步。 5. 继续执行语句块之后的程序:打印 FIRE! ,程序结束。 我们必须考虑到循环必须在某个点结束,因此在语句块之内(loop的statement之内) 我们必须提供一些方法使得条件condition 可以在某个时刻变为假 false,否则循环将无限重复下去。在这个例子里,我们用语句--n;使得循环在重复一定的次数后变为false :当 n 变为0, 倒计数结束。 #### do-while 循环 格式: `do 语句statement while (条件condition);` 它的功能与while 循环一抹一样,除了在do-while循环中是先执行statement 然后才检查条件condition ,而不想while循环中先检查条件然后才执行statement。这样,即使条件condition从来没有被满足过,statement 仍至少被执行一次。例如,下面的程序重复输出(echoes)用户输入的任何数值,直到用户输入0为止。 ~~~ | // number echoer #include int main () { unsigned long n; do { cout << "Enter number (0 to end): "; cin >> n; cout << "You entered: " << n << "\n"; } while (n != 0); return 0; } | Enter number (0 to end): 12345 You entered: 12345 Enter number (0 to end): 160277 You entered: 160277 Enter number (0 to end): 0 You entered: 0 | ~~~ *do-while* 循环通常被用在判断循环结束的条件是在循环语句内部被决定的情况下,比如以上的例子,在循环的语句块内用户的输入决定了循环是否结束。如果用户永远不输入0,则循环永远不会结束。 #### for 循环 格式是: `for (initialization; condition; increase) statement;` 它的主要功能是当条件condition 为真**true**时重复执行语句statement ,类似while 循环。但除此之外,for 还提供了写初始化语句initialization 和增值语句increase 的地方。因此这种循环结构是特别为执行由计数器控制的循环而设计的。 它按以下方式工作: 1. 执行初始化initialization 。通常它是设置一个计数器变量(counter variable)的初始值,初始化仅被执行一次。 2. 检查条件condition ,如果条件为真true,继续循环,否则循环结束循环中语句statement 被跳过。 3. 执行语句statement 。像以前一样,它可以是一个单独的语句,也可以是一个由花括号{ }括起来的语句块。 4. 最后增值域(increase field)中的语句被执行,循环返回第2步。注意增值域中可能是任何语句,而不一定只是将计数器增加的语句。例如下面的例子中计数器实际为减1,而不是加1。 下面是用for循环实现的倒计数的例子: ~~~ | // countdown using a for loop #include int main () { for (int n=10; n>0; n--) { cout << n << ", "; } cout << "FIRE!"; return 0; } | 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, FIRE! | ~~~ 初始化initialization 和增值increase 域是可选的(即可以为空)。但这些域为空的时候,它们和其他域之间间隔的分号不可以省略。例如我们可以写:for (;n<10;)来表示没有初始化和增值语句;或for (;n<10;n++) 来表示有增值语句但没有初始化语句。 另外我们也可以在for循环初始化或增值域中放一条以上的语句,中间用逗号 coma(,)隔开。例如假设我们想在循环中初始化一个以上的变量,可以用以下的程序来实现: for ( n=0, i=100 ; n!=i ; n++, i-- ) { // whatever here... } 这个循环将被执行50 次,如果n 和i 在循还内部都不被改变的话: ![](https://box.kancloud.cn/2015-09-06_55ebeebd1dd6f.gif) **n**初始值为**0**,**i**初始值为**100**,条件是**(n!=i)**(即**n**不能等于**i**)。因为每次循环**n**加**1**,而且**i**减**1**,循环的条件将会在第50次循环之后变为假**false**(**n** 和 **i** 都等于**50**)。 ### 分支控制和跳转(Bifurcation of control and jumps) #### break 语句 通过使用**break**语句,即使在结束条件没有满足的情况下,我们也可以跳出一个循环。它可以被用来结束一个无限循环(infinite loop),或强迫循环在其自然结束之前结束。例如,我们想要在倒计数自然结束之前强迫它停止(也许因为一个引擎故障): ~~~ | // break loop example #include int main () { int n; for (n=10; n>0; n--) { cout << n << ", "; if (n==3) { cout << "countdown aborted!"; break; } return 0; } | 10, 9, 8, 7, 6, 5, 4, 3, countdown aborted! | ~~~ #### continue 语句 **continue**语句使得程序跳过当前循环中剩下的部分而直接进入下一次循环,就好像循环中语句块的结尾已经到了使得循环进入下一次重复。例如,下面例子中倒计数时我们将跳过数字5的输出: | // continue loop example include int main () { for (int n=10; n>0; n--) { if (n==5) continue; cout << n << ", "; } cout << "FIRE!"; return 0; } | 10, 9, 8, 7, 6, 4, 3, 2, 1, FIRE! | #### goto 语句 通过使用goto语句可以使程序从一点跳转到另外一点。你必须谨慎只用这条语句,因为它的执行可以忽略任何嵌套限制。 跳转的目标点可以由一个标示符(label)来标明,该标示符作为goto语句的参数。一个标示符(label)由一个标识名称后面跟一个冒号colon (:)组成。 通常除了底层程序爱好者使用这条语句,它在结构化或面向对象的编程中并不常用。下面的例子中我们用goto来实现倒计数循环: | // goto loop example include int main () { int n=10; loop: cout << n << ", "; n--; if (n>0) goto loop; cout << "FIRE!"; return 0; } | 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, FIRE! | #### exit 函数 **exit**是一个在[cstdlib (stdlib.h)](http://www.cplusplus.com/ref/cstdlib)库中定义的函数。 **exit**的目的是一个特定的退出代码来结束程序的运行,它的原型(prototype)是: `void exit (int exit code);` **exit code**是由操作系统使用或被调用程序使用。通常**exit code**为**0**表示程序正常结束,任何其他值表示程序执行过程中出现了错误。 ### 选择结构The selective Structure: switch **switch** 语句的语法比较特殊。它的目标是对一个表达式检查多个可能常量值,有些像我们在本节开头学习的把几个if 和else if 语句连接起来的结构。它的形式是: switch (expression) { case constant1: block of instructions 1 break; case constant2: block of instructions 2 break; . . . default: default block of instructions } 它按以下方式执行: switch 计算表达式expression 的值,并检查它是否与第一个常量constant1相等,如果相等,程序执行常量1后面的语句块block of instructions 1 直到碰到关键字break ,程序跳转到switch 选择结构的结尾处。 如果expression 不等于constant1,程序检查表达式expression 的值是否等于第二个常量constant2, 如果相等,程序将执行常量2后面的语句块block of instructions 2 直到碰到关键字break。 依此类推,直到最后如果表达式expression 的值不等于任何前面的常量(你可以用case语句指明任意数量的常量值来要求检查),程序将执行默认区default: 后面的语句,如果它存在的话。default: 选项是可以省略的。 下面的两段代码段功能相同: | *switch* example | *if-else* equivalent | | switch (x) { case 1: cout << "x is 1"; break; case 2: cout << "x is 2"; break; default: cout << "value of x unknown"; } | if (x == 1) { cout << "x is 1"; } else if (x == 2) { cout << "x is 2"; } else { cout << "value of x unknown"; } | 前面已经提到**switch**的语法有点特殊。注意每个语句块结尾包含的**break**语句。这是必须的,因为如果不这样做,例如在语句块block of instructions 1 的结尾没有**break**,程序执行将不会跳转到**switch**选择的结尾处 (**}**) ,而是继续执行下面的语句块,直到第一次遇到**break**语句或到**switch**选择结构的结尾。因此,不需要在每一个case 域内加花括号**{ }** 。这个特点同时可以帮助实现对不同的可能值执行相同的语句块。例如: switch (x) { case 1: case 2: case 3: cout << "x is 1, 2 or 3"; break; default: cout << "x is not 1, 2 nor 3"; } **注意****switch**只能被用来比较表达式和不同常量的值constants。因此我们不能够把变量或范围放在case之后,例如 (case (n*2):) 或 (case (1..3):) 都不可以,因为它们不是有效的常量。 如果你需要检查范围或非常量数值,使用连续的if 和else if 语句。