第六章 语句
6.1 简单语句
C++中,大多数语句以分号结束(块不是以分号结束的)
表达式语句,表达式加上分号,就是表达式语句
空语句,只有一个单独的分号,如果在程序的某个地方,语法上需要一个语句,但逻辑上并不需要,此时应该使用空语句,这种用法常见于在循环条件判断部分就能完成全部循环工作的情况
6.2 声明语句
6.3 复合语句(块)
复合语句(compound statement),通常被称为块,是用一对花括号括起来的语句序列(也可以为空),块标识了一个作用域,与其他大多数语句不同,块并不是以分号结束的,复合语句用在语法规则要求使用单个语句,但程序逻辑却需要不止一个语句的地方
6.4 语句作用域
有些语句允许在它们的控制结构中定义变量,在条件表达式中定义的变量必须初始化,该条件检验的就是初始化对象的值
在语句的控制结构中定义的变量,仅在定义它们的块语句结束前有效,如果程序需要访问某个控制结构中的变量,那么这个变量必须在控制语句外部定义
6.5 if语句
if语句根据特定表达式是否为真有条件地执行另一个语句,if语句有两种形式:其中一种带else分支而另一种则没有,如果在条件表达式中定义了变量,那么变量必须初始化,将初始化的变量转换为bool值,该bool值决定条件是否成立,变量类型可以是算术类型或指针类型,一个类类型是否用在条件表达式中取决于类本身(IO类型可以用作条件,但vector类型和string类型一般不可用作条件)
可以通过花括号将内层的if语句括起来成为复合语句,从而迫使这个else子句与外层的if匹配,来解决悬垂else问题
6.6 switch语句
switch语句提供了一种更方便的方法来实现深层嵌套的if/else逻辑,通过圆括号内表达式的值与其后列出的关键字做比较,实现switch语句的功能,表达式必须产生一个整数结果,其值与每个case的值比较,关键字case和它所关联的值称为case标号,每个case标号的值都必须是一个常量表达式,除此之外,还有一个特殊的case标号--default标号,default标号提供了相当于else子句的功能,一个标号不能独立存在,它必须位于语句之前,如果switch结构以default标号结束,而且default分支不需要完成任何任务,那么该标号后面必须有一个空语句
程序执行匹配的 case标号相关联的语句,从该点开始执行,并跨越case边界继续执行其他语句,直到switch结束或遇到break语句为止
switch求解的表达式可以非常复杂,特别是,该表达式也可以定义和初始化一个变量,变量始终存在于整个switch语句中,在switch结构外面该变量就不再有效
对于switch结构,只能在它的最后一个case标号或default标号后面定义变量,制定整个规则是为了避免出现代码跳过变量的定义和初始化的情况,如果需要为某个特殊的case定义变量,则可以引入块语句,在该块语句中定义变量,从而保证这个变量在使用前被定义和初始化
6.7 while语句
当条件为真时,while语句反复执行目标语句,循环条件不能为空,可以是一个表达式,或者是提供初始化的变量定义,在循环条件中定义的任意变量都只在于while关联的块语句中可见,在循环条件中定义的变量在每次循环里都要经历创建和撤销的过程,while循环内的赋值操作是一种常见的用法
6.8 for循环语句
for语句头中,可以省略初始化语句、条件语句或者表达式中的任何一个或全部,可以在for语句的初始化语句中定义多个对象,但是不管怎样,该处只能出现一个语句,因此所有的对象必须具有相同的一般类型
6.9 do while 语句
与while语句不同,do while语句总是以分号结束,任何在循环条件中引用的变量都必须在do语句之前就已经存在
6.10 break语句
break语句用于结束最近的while do while for switch语句,并将程序的执行权传递给紧接在被终止语句之后的语句
6.11 continue语句
continue语句导致最近的循环语句的当次迭代提前结束,对于while和do while语句,继续求解循环条件,对于for循环,程序流程接着求解for语句头中的expresion表达式
6.12 goto语句
goto语句提供了函数内部的无条件跳转,实现从goto语句跳转到同一函数内某个带标号的语句,goto语句的语法规则如下:goto label;,在任何语句前提供一个标识符和冒号,即带标号的语句,形成标号的标识符只能用作goto的目标
goto语句和获得所转移的控制权的带标号的语句必须位于同一个函数内,goto语句不能跨越变量的定义语句向前跳转,如果确实需要在goto和其跳转对应的标号之前定义变量,则定义必须放在一个块语句中
6.13 try块和异常处理
异常就是运行时出现的不正常,存在于程序的正常功能之外,并要求程序立即处理
异常机制 提供程序中 错误检测与错误处理 部分之间的通讯,C++的异常处理 包括:throw表达式(throw expression),错误检测部分使用这种表达式来说明遇到了不可处理的错误,可以说throw引发了异常条件,try块(try block),错误处理部分使用它来处理异常,try语句块以try关键字开始,并以一个或多个catch子句结束,由标准库定义的一组异常类(exception class)用来在throw和相应catch之间传递有关的错误信息
6.13.1 throw表达式
系统通过throw表达式抛出异常,throw表达式由关键字throw以及尾随的表达式组成,通常以分号结束,这样它就成了表达式语句,throw表达式的类型决定了所抛出异常的类型,runtime_error类型是标准库异常类中的一种,在stdexcept头文件中定义
6.13.2 try块
try块以关键字try开始,后面是花括号括起来的语句序列块,try块后面是一个或多个catch子句,每个catch子句包括三个部分:关键字catch,圆括号内单个类型或单个对象的声明,称为 异常说明符,以及通常用花括号括起来的语句块,如果选择了一个catch子句来处理异常,则执行相关的块语句,一旦catch子句执行结束,程序流程立即继续执行紧随着最后一个catch子句的语句,try块里面可以包含任意C++语句,包括变量声明
try{ throw runtime_error("There\n" ); }catch(runtime_error err ){ cout << err.what() << "Here\n"; }
每一个标准库异常类都定义了名为what的成员函数,这个函数不需要参数,返回c风格字符串,what返回的c风格字符串,是用于初始化runtime_error的string对象的副本
寻找处理代码的过程与函数调用链刚好相反,抛出一个异常时,首先要搜索的是抛出异常的函数,如果没有找到匹配的catch,则终止这个函数的执行,并在调用这个函数的函数中寻找相匹配的catch,如果仍然没有找到相应的处理代码,该函数同样要终止,搜索调用它的函数,如此类推,继续按执行路径回退,直到找到适当类型的catch为止,如果不存在处理该异常的catch子句,程序的运行就要跳转到名为terminate的标准库函数,该函数在exception头文件中定义,通常情况下,它的执行将导致程序非正常退出
6.13.3 标准异常
标准库异常类定义在四个头文件中:exception头文件 定义了最常见的异常类,它的类名是exception; stdexcept头文件 定义了几种常见的异常类;new头文件 定义了bad_alloc异常类型,提供因无法分配内存而由new抛出的异常;typeinfo头文件 定义了bad_cast异常类型
标准库异常类只提供很少的操作,包括创建、复制异常类型对象以及异常类型对象的赋值,exeception、bad_alloc以及bad_cast类型只定义了默认构造,无法创建这些类型的对象时为它们提供初值,其他的异常类型则只定义了一个使用string初始化式的构造函数,当需要定义这些异常类型的对象时,必须提供一个string参数,异常类型只定义了一个名为what的操作,这个函数不需要任何参数,并且返回const char*类型的值
/* #include <stdexcept> #include <new> #include <typeinfo> */ try{ throw// exception(); //bad_alloc(); //bad_cast(); //logic_error("found_logic_error" ); "const char* "; }/* catch(bad_alloc ba){ cout << ba.what(); } catch(bad_cast bc){ cout << bc.what(); } */ catch(const char* cc){ cout << cc; } catch(exception& e){ cout << e.what(); }
6.14 使用预处理器进行调试
#include <iostream> using namespace std; int main() { //#define NDEBUG //关闭 #ifndef NDEBUG cerr << "main starting" << endl; #endif return 0; }
#include <cassert> #include <iostream> using namespace std; int main() { //#define NDEBUG //关闭 #ifndef NDEBUG assert(1>2 ); //表达式 1>2 "不可能发生的事情" 会输出信息并终止程序的执行 //如果表达式非零值,则assert不做任何操作 #endif return 0; }