第五章 语句
5.1 简单语句
一个表达式在结尾加上分号就变成了表达式语句 。 表达式语句的作用是执行表达式并丢弃掉求值结果。
ival + 5 ;
cout << ival;
空语句 只含有一个单独的分号。使用空语句时应该加上注释。
;
ival = vl + v2; ;
while ( iter!= svec. end ( ) ) ;
{
++ iter;
}
复合语句 是指用花括号括起来的语句和声明的序列,复合语句也被称作块 。一个块 就是一个作用域。
while ( val <= 10 )
{
sum += val;
++ val;
}
while ( cin >> s && s != sought)
{ }
5.2 语句作用域
可以在if、switch、while和for语句的控制结构内定义变量。定义在控制结构当中的变量只在相应语句的内部可见,一旦语句结束,变量也就超出其作用范围了。
while ( int i = get_num ( ) )
{
cout << i << endl;
}
i = 0 ;
如果其他代码也需要访问控制变量,则变量必须定义在语句的外部。
auto beg = v. begin ( ) ;
while ( beg != v. end ( ) && * beg >= 0 )
{
++ beg;
}
if ( beg == v. end ( ) )
5.3 条件语句
C++语言提供了两种按条件执行的语句:if语句 、switch语句 。
5.3.1 if语句
if语句 的作用是判断一个指定的条件是否为真,根据判断结果决定是否执行另外一条语句。
if ( )
{
}
if ( )
{
}
else
{
}
if ( )
{
}
else if ( )
{
}
悬垂else 规定else与离它最近的尚未匹配的if匹配,从而消除了程序的二义性。
if ( )
{
if ( )
{
}
}
else if ( )
{
if ( )
{
}
}
5.3.2 switch语句
switch 提供了一条便利的途径使得我们能够在若干固定选项中做出选择。
# include <iostream>
using namespace std;
int reused = 42 ;
int main ( )
{
unsigned aCnt = 0 , eCnt = 0 , iCnt = 0 , oCnt = 0 , uCnt = 0 ;
char ch;
while ( cin >> ch)
{
switch ( ch)
{
case 'a' : ++ aCnt; break ;
case 'e' : ++ eCnt; break ;
case 'i' : ++ iCnt; break ;
case 'o' : ++ oCnt; break ;
case 'u' : ++ uCnt; break ;
}
if ( ch== '/' )
{
break ;
}
}
cout << "Number of vowel a:" << aCnt << endl;
cout << "Number of vowel e:" << eCnt << endl;
cout << "Number of vowel i:" << iCnt << endl;
cout << "Number of vowel o:" << oCnt << endl;
cout << "Number of vowel u:" << uCnt << endl;
}
a
e
e
i
i
i
o
/
Number of vowel a: 1
Number of vowel e: 2
Number of vowel i: 3
Number of vowel o: 1
Number of vowel u: 0
case关键字和它对应的值被称为case标签 ,case标签必须是整型常量表达式。 如果某个case标签匹配成功,将从该标签开始往后顺序执行所有case分支,除非程序显式地中断了这一过程,否者直到switch结尾才会停下来。 大多数在下一个case标签之前应该有一条break语句来防止case穿透。 漏写break容易引发BUG 。
# include <iostream>
using namespace std;
int reused = 42 ;
int main ( )
{
unsigned aCnt = 0 , eCnt = 0 , iCnt = 0 , oCnt = 0 , uCnt = 0 ;
char ch;
while ( cin >> ch)
{
switch ( ch)
{
case 'a' : ++ aCnt;
case 'e' : ++ eCnt;
case 'i' : ++ iCnt;
case 'o' : ++ oCnt;
case 'u' : ++ uCnt;
}
if ( ch== '/' )
{
break ;
}
}
cout << "Number of vowel a:" << aCnt << endl;
cout << "Number of vowel e:" << eCnt << endl;
cout << "Number of vowel i:" << iCnt << endl;
cout << "Number of vowel o:" << oCnt << endl;
cout << "Number of vowel u:" << uCnt << endl;
}
a
e
e
i
i
i
o
/
Number of vowel a: 1
Number of vowel e: 3
Number of vowel i: 6
Number of vowel o: 7
Number of vowel u: 7
如果没有任何一个case标签能匹配上switch表达式的值,程序将执行紧跟在default标签 后面的语句。
# include <iostream>
using namespace std;
int reused = 42 ;
int main ( )
{
unsigned aCnt = 0 , eCnt = 0 , iCnt = 0 , oCnt = 0 , uCnt = 0 ;
char ch;
while ( cin >> ch)
{
switch ( ch)
{
case 'a' : ++ aCnt; break ;
case 'e' : ++ eCnt; break ;
case 'i' : ++ iCnt; break ;
case 'o' : ++ oCnt; break ;
case 'u' : ++ uCnt; break ;
default : cout<< "GG" << endl; return 0 ;
}
}
}
/
GG
switch中允许跳过变量的定义,但不允许跳过变量的初始化。
case true :
string file_name;
int ival = 0 ;
int jval;
break ;
case false :
jval = next_num ( ) ;
if ( file_name. empty ( ) )
{
}
如果需要为某个case分支定义并初始化一个变量,我们应该把变量定义在块内。
case true :
{
string file_name = get_file_name ( ) ;
}
break ;
case false :
if ( file_name. empty ( ) )
5.4 迭代语句
迭代语句通常称为循环,它重复执行操作直到满足某个条件才停下来。
5.4.1 while语句
while ( )
{
}
当不确定到底要迭代多少次时,使用while循环比较合适。
vector< int > v;
int i;
while ( cin >> i)
{
v. push_back ( i) ;
}
auto beg = v. begin ( ) ;
while ( beg != v. end ( ) && * beg >= 0 )
{
++ beg;
}
if ( beg = v. end ( ) )
5.4.2 传统的for语句
init-statement 必须是以下三种形式中的一种:声明语句、表达式语句或者空语句。condition 作为循环控制的条件。只要condition 为真,就执行一次stalement 。 如果condition 第一次的求值结果就是false, 则statement 一次也不会执行。 expression 负责修改init-statement 初始化的变量。
for ( ; ; )
{
}
for ( decltype ( s. size ( ) ) index = 0 ; index != s. size ( ) && ! isspace ( s[ index] ) ; ++ index)
{
s[ index] = toupper ( s[ index] ) ;
}
for ( decltype ( v. size ( ) ) i = 0 , sz = v. size ( ) ; i != sz; ++ i)
{
v. push_back ( v[ i] ) ;
}
auto beg = v. begin ( ) ;
for ( ; beg != v. end ( ) && * beg >= O; ++ beg)
{
;
}
for ( int i = O; ; ++ i)
{
}
vector< int > v;
for ( int i; cin >> i; )
{
v. push_back ( i) ;
}
5.4.3 范围for语句
C++ll新标准引入了一种种更简单的for语句。 expression 表示的必须是个序列,如用花括号括起来的初始值列表、数组、或者vector或string等类型的对象。这些序列的共同特点是拥有能返回迭代器的begin和end成员。 declaration 定义个变星,序列中的每个元素都得能转换成该变量的类型。确保类型相容最简单的办法是使用auto 类型说明符。
for ( : )
{
}
vector< int > v = { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 } ;
for ( auto & r : v)
{
r *= 2 ;
}
for ( auto beg = v. begin ( ) , end = v. end ( ) ; beg != end; ++ beg)
{
auto & r = * beg;
r *= 2 ;
}
5.4.4 do while语句
do while语句 和while语句非常相似,唯一的区别是,do while语句 先执行循环体后检查条件。
do
{
} while ( ) ;
条件部分检查用户做出的回答,如果用户没有回答,或者用户的回答以字母n开始,循环都将终止。否则循环继续执行。
string rsp;
do
{
cout << "please enter two values: " ;
int val1 = 0 , val2 = 0 ;
cin >> val1 >> val2;
cout << "The sum of " << val1 << "and" << val2
<< ";" << vall + val2 << "\n\n"
<< "More? Enter yes or no: " ;
cin >> rsp;
} while ( ! rsp. empty ( ) && rsp ( O] != 'n' ) ;
因为对于do while 来说先执行语句或者块,后判断条件,所以不允许在条件部分。
do
{
mumble ( foo) ;
} while ( int foo = get_foo ( ) ) ;
5.5 跳转语句
C++语言提供了4种跳转语句:break、continue、goto、return 。
5.5.1 break语句
break语句 负责终止离它最近的while、do while、for、switch语句。
string buf;
while ( cin >> buf && ! buf. empty ( ) )
{
switch ( buf[ 0 ] )
{
case '-' :
{
for ( auto it = buf. begin + 1 ; it != buf. end ( ) ; ++ it)
{
if ( * it == ' ' )
{
break ;
}
}
}
break ;
case '+' :
}
}
5.5.2 continue语句
continue语句 终止最近的循环中的当前迭代并立即开始下一次迭代。
string buf;
while ( cin >> buf && ! buf. empty ( ) )
{
if ( buf[ O] != '_' )
{
continue ;
}
}
5.5.3 goto语句
goto语句 的作用是从goto语句无条件跳转到同一函数内的另一条语句。每天一个离职小技巧,不要在程序中使用goto语句,因为它使得程序既难理解又难修改。
goto end;
int ix = 10 ;
end :
ix = 42 ;
向后跳过一个已经执行的定义是合法的。跳回到变量定义之前意味着系统将销毁该变量,然后重新创建它。
begin:
int sz= get_size ( ) ;
if ( sz<= 0 )
{
goto begin;
}
5.6 TRY语句块和异常处理
异常是指存在于运行时的反常行为,这些行为超出了函数正常功能的范围。 处理反常行为可能是设计所有系统最难的一部分。 throw表达式 异常检测部分使用throw表达式来表示它遇到了无法处理的问题。我们说throw引发了异常。try语句块 异常处理部分使用try语句块处理异常。try语句块以关键字try开始,并以一个或多个catch子句 结束。try语句块 中代码抛出的异常通常会被某个catch子句处理。因为catch子句“处理”异常,所以它们也被称作异常处理代码 。
5.6.1 throw表达式
程序的异常检测部分使用throw表达式引发一个异常。
Sales_item item1, item2;
cin >> item1 >> item2;
if ( iteml. isbn ( ) = item2. isbn ( ) )
{
cout << item1 + item2 << endl;
return0;
}
else
{
cerr << "Data must refer to same ISBN" << endl;
return - 1 ;
}
Sales_item item1, item2;
cin >> item1 >> item2;
if ( iteml. isbn ( ) = item2. isbn ( ) )
{
throw runtime_error ( "Data must refer to same ISBN" ) ;
}
5.6.2 try语句块
try语句块的通用语法形式。 catch子句 包括三部分:关键字catch、括号内一个对象的声明(称作异常声明 )、以及一个块。program-statements 组成程序的正常逻辑,像其他任何块一样,可以有包括声明在内的任意C++语句。
try
{
}
catch ( exception - declaration)
{
}
catch ( exception - declaration)
{
}
while ( cin >> item1 >> item2)
{
try
{
}
catch ( runtime_error err)
{
cout << err. what ( ) << "\nTry Again? Enter y or n" << endl;
char c;
cin >> c;
if ( ! cin || c == 'n' )
{
break ;
}
}
}
5.6.3 标准异常
C++标准阵定义了一组类,用于报告标准库函数遇到的问题。 别定义在4个头文件中:
exception头文件定义了最通用的异常类exception。它只报告异常的发生,不提供任何额外信息。 stdexcept头文件定义了几种常用的异常类。 new头文件定义了bad_alloc异常类型。 type_info头文件定义了bad_cast异常类型。