声明和流控制
一个简单的C ++语句是由每个单独指令组成的程序,比如前面部分中看到的变量声明和表达式。它们总是以分号(;
)结尾,并按照它们在程序中出现的顺序执行。
但是程序不仅限于线性序列的陈述。在其过程中,程序可以重复代码段,或者做出决定和分叉。为此,C ++提供了流控制语句,用于指定何时以及在何种情况下程序必须完成的操作。
本节中解释的许多流控制语句都需要通用(子)语句作为其语法的一部分。该语句可以是简单的C ++语句,例如单个指令,以分号结尾(;
) - 或复合语句,复合语句是一组语句(每个语句都以它自己的分号结尾),但是所有语句都在一个块中组合在一起,用大括号括起来:{};
{ statement1; statement2; statement3; }
上面的整个语句被认为是一个整体语句(它由多个子语句组成)。每当泛型语句是流控制语句的语法的一部分时,它可以是简单语句或复合语句。
选择语句:if和else
该if
关键字用于执行语句或块中,意思是如果,且仅当一个条件被满足。它的语法是:
if (condition) statement
这里condition
是正在判断的表达式。如果condition是true
,则statement部分的代码
执行。如果为false,statement
则不执行(只是忽略它),程序在整个选择语句之后继续执行。
例如,以下代码片段(x is 100)
仅在存储在x
变量中的值确实为100 时才打印消息:
if (x == 100)
cout << "x is 100";
如果x
不是加好为100,则忽略此语句,并且不打印任何内容。
如果要在满足条件时要包含多个执行的语句,则这些语句应括在大括号({}
)中,形成一个块:
if (x == 100)
{
cout << "x is ";
cout << x;
}
像往常一样,代码中的缩进和换行没有任何效果,因此上面的代码相当于:
if (x == 100) { cout << "x is "; cout << x; }
选择语句if
还可以通过使用else
关键字引入替代语句来指定在未满足条件时发生的情况。它的语法是:
if (condition) statement1 else statement2
statement1只有在condition的值是true的情况下才会执行,而当condition为false的情况下statement2才执行。
例如:
if (x == 100)
cout << "x is 100";
else
cout << "x is not 100";
上面的代码,当x的值为100的时候会输出x is 100,当x不是100,且仅当x==100的值为false的时候,程序代替的会输出x is not 100。
if+else的结构可以好几个接连使用,以便检查一些列的值:
if (x > 0)
cout << "x is positive";
else if (x < 0)
cout << "x is negative";
else
cout << "x is 0";
这个语句通过连接的两个if+else来输出x is positive、negtive或0,同样也可以将它们用{}分成各个块,每个块中可以有多个执行语句。
迭代语句
C++通过引入while
,do
和for关机子
。当满足条件时,循环重复一次语句一定次数。
while循环
最简单的循环是while循环。它的语法是:
while (expression) statement
当while后面的expression是true的时候执行statement,执行结束后重新判断expression是否为真直至其为假不再循环statement,继续执行while语句块之后的语句,例如,让我们看看使用while循环的倒计时:
// custom countdown using while
#include <iostream>
using namespace std;
int main ()
{
int n = 10;
while (n>0) {
cout << n << ", ";
--n;
}
cout << "liftoff!\n";
结果是:
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, liftoff!
main语句块中
n的第一个语句为值10.这是倒计时中的第一个数字。然后while循环开始:如果该值满足条件n>0
(n大于零),则执行条件之后的块,并且只要条件(n>0
)保持为真,就重复该条件。
可以根据以下脚本(从头开始main
)解释前一个程序的整个过程:
n
被赋予一个值- 该
while
条件被选中(n>0
)。此时有两种可能性:- condition为true:执行语句(到第3步)
- condition为false:忽略语句并在其后继续(到第5步)
- 执行语句:( 打印值减1 并减1)
cout << n << ", ";
--n; - 结束语句块。自动返回第2步。
- 在程序段后立即继续执行程序:
打印liftoff!
并结束程序。
while循环要考虑的一点是循环应该在某个点结束,因此语句应该以某种方式改变在条件中检查的值,以便在某些时候强制它变为false。否则,循环将继续循环(无限循环)。在上面这种情况下,循环包括--n
,将条件(n
)中正在计算的变量的值减1;这将最终使条件(n>0
)在一定数量的循环迭代后变为假。更具体地说,在10次迭代之后,n
变为0,使条件不再为真,并结束while循环。
请注意,这个循环的复杂性对于计算机来说是微不足道的,因此整个倒计时是立即执行的,计数的元素之间没有任何实际的延迟(如果感兴趣,请参阅http://www.cplusplus.com/reference/thread/this_thread/sleep_for/(sleep_for
)具有延迟的倒计时示例)。
do-while循环
一个非常相似的循环是do-while循环,其语法是:
do statement while (condition);
它的行为类似于while循环体,只是判断是在执行statement之后而不是之前,保证至少执行一次,即使condition的值从未实现过过,一旦当while后的condition为true则结束循环。例如,以下示例程序回显用户引入的任何文本,直到用户进入goodbye:
// echo machine
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str;
do {
cout << "Enter text: ";
getline (cin,str);
cout << "You entered: " << str << '\n';
} while (str != "goodbye");
}
结果是:
Enter text: hello
You entered: hello
Enter text: who's there?
You entered: who's there?
Enter text: goodbye
You entered: goodbye
statement
需要至少执行一次,例如当在循环语句本身内确定检查到循环结束的条件时,do-while循环通常优于while循环。在前面的示例中,块内的用户输入将决定循环是否结束。因此,即使用户想要通过输入尽快结束循环再见,循环中的块需要至少执行一次以提示输入,实际上,条件只能在执行后才能确定。
for循环
for
循环被设计为迭代多次。它的语法是:
for (initialization; condition; increase) statement;
像while循环一样,当condition为true的时候这个循环重复。此外,for循环提供了包含一个初始值(initialization)和一个表达式(increase)的特定位置,分别在循环开始第一次之前和每次迭代之后执行。因此,使用计数器变量特别有用。 它的工作方式如下:
initialization
被执行。通常,这会声明一个计数器变量,并将其设置为某个初始值。这在循环开始时执行一次。condition
检查。如果是,则循环继续; 否则,循环结束,并statement
跳过,直接进入步骤5。statement
被执行。像往常一样,它可以是单个语句,也可以是用花括号括起来的块{ }
。increase
执行,循环返回到步骤2。- 循环结束:执行后继续执行下一个语句。
这是使用for循环的倒计时示例:
// countdown using a for loop
#include <iostream>
using namespace std;
int main ()
{
for (int n=10; n>0; n--) {
cout << n << ", ";
}
cout << "liftoff!\n";
}
结果是:
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, liftoff!
for循环中的三个字段是可选的。它们可以留空,但在所有情况下都都不能省略它们之间的分号。例如,for (;n<10;)
是一个没有初始化和增加的循环(相当于一个while循环); 而for (;n<10;++n)
是一个增加的循环,但没有初始化(可能因为变量在循环之前已经初始化)。没有条件的循环等同于具有true
条件的循环(即,无限循环)。
因为每个字段中在一个循环的生命周期的特定时间被执行时,它可以在多于一个单一表达式作为任何的是执行有用初始化,条件或声明。不幸的是,这些不是语句,而是简单的表达式,因此不能被块替换。但是,作为表达式,它们可以使用逗号运算符(,
):此运算符是表达式分隔符,可以分隔多个表达式,其中通常只需要一个表达式。例如,使用它,for循环可以处理两个计数器变量,初始化和增加两个:
for ( n=0, i=100 ; n!=i ; ++n, --i )
{
// whatever here...
}
如果在循环内没有修改n或i,则该循环将执行50次:
n
以值0开始,并且i等于
100,条件是n!=i
(即,n
不等于i
)。因为每次迭代n
增加一,并且i减少一
,循环的条件将第50次迭代后成为假,此时两个变量n
和i的值
都等于50。
基于范围的循环
for循环有另一种语法,它专门用于范围:
for ( declaration : range ) statement;
这种for循环遍历所有元素,其中声明declaration变量能够获取该range范围内元素的值。 范围是元素序列,包括数组,容器和支持函数begin和end的任何其他类型。大多数这些类型尚未在本教程中介绍,但我们已经熟悉至少一种范围:字符串,它们是字符序列。
使用字符串的基于范围的for循环的示例:
// range-based for loop
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str {"Hello!"};
for (char c : str)
{
cout << "[" << c << "]";
}
cout << '\n';
}
输出结果:
[H][e][l][l][o][!]
注意for循环中冒号(:)之前的内容是char变量的声明(字符串中的元素是char类型)。 然后,我们在语句块中使用此变量c来表示范围中每个元素的值。
此循环是自动的,不需要显式声明任何计数器变量。
基于范围的循环通常还使用类型推导来表示具有auto的类型元素。 通常,上面的基于范围的循环也可以写成:
for (auto c : str)
cout << "[" << c << "]";
这里,类型c
被自动推断为元素的类型str
。
跳转声明
跳转语句允许通过跳转到特定位置来改变程序的流程。
break声明:
break
即使不满足其结束条件,也跳出一个循环。它可用于结束无限循环,或强制它在自然结束之前结束。例如,让我们在自然结束前停止倒计时:
// break loop example
#include <iostream>
using namespace std;
int main ()
{
for (int n=10; n>0; n--)
{
cout << n << ", ";
if (n==3)
{
cout << "countdown aborted!";
break;
}
}
}
结果:
10, 9, 8, 7, 6, 5, 4, 3, countdown aborted!
continue语句
该continue
语句使程序跳过当前迭代中的其余循环,就好像已到达语句块的结尾一样,导致它跳转到下一次迭代的开始。例如,让我们在倒计时中跳过5:
// continue loop example
#include <iostream>
using namespace std;
int main ()
{
for (int n=10; n>0; n--) {
if (n==5) continue;
cout << n << ", ";
}
cout << "liftoff!\n";
}
结果是:
10, 9, 8, 7, 6, 4, 3, 2, 1, liftoff!
结果中少了5。
goto语句(慎用,一般不用)
goto
允许绝对跳转到程序中的另一个点。此无条件跳转忽略嵌套级别,并且不会导致任何自动堆栈展开。因此,小心使用是一个特征,最好是在同一个语句块中,特别是在存在局部变量的情况下。
目标点由标签标识,然后将其用作goto
语句的参数。甲标签的情况下(一个有效标识符,后跟一个冒号的:
)。goto
通常被认为是低级功能,在通常与C ++一起使用的现代高级编程范例中没有特定的用例。但是,举个例子,这是我们使用goto的倒计时循环的一个版本:
// goto loop example
#include <iostream>
using namespace std;
int main ()
{
int n=10;
mylabel:
cout << n << ", ";
n--;
if (n>0) goto mylabel;
cout << "liftoff!\n";
}
结果是:
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, liftoff!
另外一个选择声明:switch
switch语句的语法有点奇怪。其目的是检查许多可能的常量表达式中的值。它类似于连接if
- else
语句,但仅限于常量表达式。其最典型的语法是:
switch (expression)
{
case constant1:
group-of-statements-1;
break;
case constant2:
group-of-statements-2;
break;
.
.
.
default:
default-group-of-statements
}
它的工作方式如下:switch
评估expression
并检查它是否等同于constant1
; 如果是,则执行group-of-statements-1
直到找到该break
语句。当它找到这个break
语句时,程序跳转到整个switch
语句的结尾(结束括号)。
如果表达式不等于constant1
,则对其进行检查constant2
。如果它等于这个,它将执行group-of-statements-2
直到break
找到a,当它跳转到开关的末尾。
最后,如果表达式的值与之前指定的任何常量都不匹配(可能有任何数量的这些),程序将执行default:
标签后面包含的语句(如果存在)(因为它是可选的不一定要有)。
以下两个代码片段都具有相同的行为,演示了switch语句的if-else等价的例子:(CSDN变成表格后会比较奇怪)
switch example | if-else equivalent |
---|---|
| |
该switch
语句有一些从第一个C编译器的早期继承的特殊语法,因为它使用标签而不是块。在最典型的用法中(如上所示),这意味着break
在特定标签的每组语句之后需要语句。如果break
不包括在内,则也会执行该案例后面的所有语句(包括任何其他标签下的语句),直到达到switch块或跳转语句(例如break
)的结尾。
如果上面的示例在第一个案例一之后缺少break语句,则程序在打印后不会自动跳转到switch块的末尾,x is 1
而是在两个案例中继续执行语句(因此也打印x is 2
)。然后它将继续这样做,直到break
遇到一个语句或switch
块结束。这使得不必将每个案例的语句括在大括号中{}
,并且对于为不同的可能值执行相同的语句组也是有用的。例如:
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
仅限于将其计算的表达式与作为常量表达式的标签进行比较。不能将变量用作标签或范围,因为它们不是有效的C ++常量表达式。
要检查非常量的范围或值,最好使用if
和else if
语句的连接而不是switch。