《C++Primer》第五章——语句

本文详细介绍了C++中的语句结构,包括简单语句、复合语句(块)、语句作用域、条件语句(if和switch)、迭代语句(for和while)以及跳转语句(break、continue和goto)。此外,还深入讲解了C++的异常处理机制,包括throw表达式、try语句块和标准异常类。异常处理提供了一种处理程序运行时错误的方法,确保了程序的健壮性。
摘要由CSDN通过智能技术生成

第五章:语句

5.1 简单语句

1.复合语句(块):是指用花括号括起来的语句和声明的序列,复合语句也被称作为块,一个块就是一个作用域,在块中引入的名字只能在块内部以及嵌套在块中的子块里访问,名字在有限的区域内可见,该区域从名字定义处开始,到名字所在的块的结尾为止。
注:块不以分好作为结束

5.2 语句作用域

1.可以在 if、switch、while 和 for 语句的控制结构内定义变量,定义在控制结构当中的变量只在相应语句的内部可见,一旦语句结束,变量也就超出其作用范围了。

while(int i = get_num())	//每次迭代时创建并初始化i
	cout << i << endl;
i = 0;	//错误:在循环外部无法方位i

如果其他代码也需要访问控制变量,则变量必须定义在语句的外部

5.3 条件语句

1.C++语言提供了两种按条件执行的语句,一种是 if 语句,它根据条件决定控制流;另一种是 switch 语句,它计算一个整型表达式的值,然后根据这个值从几条执行路径中选择一条。
2.switch 语句:提供了一条便利的途径使得我们能够在若干固定选项中做出选择
1)如果表达式和某个 case 标签的值匹配成功,程序从该标签之后的第一条语句开始执行,直到到达了 switch 的结尾或者是遇到break语句
2)case 关键字和它对应的值一起被称为 case 标签,case 标签必须是整型常量表达式,任何两个 case 标签的值都不能相同
3)一般不要省略 case 分支最后的 break 语句,如果没写 break 语句,最好加一段注释说明清除程序逻辑
4)default标签:若没有任何一个 case 标签能匹配上 switch 表达式的值,程序将执行紧跟在 default 标签后面的语句,即使不准备在 default 标签下做任何工作,定义一个 default 标签也是有用的,其目的是高速读者我们考虑了默认情况只是目前什么也没做
5)若需要为某个 case 分支定义并初始化一个变量,我们应该把变量定义在块内,从而确保后面的所有 case 标签都在变量的作用域之外

case true:
	//因为程序的执行流程可能绕开下面的初始化语句,所以该switch语句不合法
	string file_name;	//错误:控制流绕过一个隐式初始化的变量
	int ival;			//错误:控制流绕过一个显式初始化的变量
	int jval;			//正确:因为jval没有初始化
	break;
case false:
	//正确:jval虽然在作用域内,但是它没有被初始化
	jval = next_num();		//正确:给jval赋一个值
	if(file_name.empty())	//错误:file_name在作用域内,但是没有被初始化
	//...

假设上面这段代码合法,则一旦控制流跳过 false 分支,也就同时略过了变量 file_name 和 ival 的初始化,这两个变量位于作用域中,跟在 false 之后的代码视图在尚未初始化的情况使用它们,这是错误的
因此,若需要为某个 case 分支定义并初始化一个变量,应把变量定义在块内,从而确保后面的所有 case 标签都在变量的作用域之外,如下

case true:
	{
		//正确:声明语句位于语句块内部
		string file_name = get_file_name();
		//...
	}
	break;
case false:

5.4 迭代语句

1.范围 for 语句:C++11新标准引入一种更简单的 for 语句,这种语句可以遍历容器或其他序列的所有元素。
for(declaration : expression)
statement
expression 表示的必须是一个序列,e g:花括号括起来的初始值列表、数组或者 vector 或 string 等类型的对象,这些类型的共同特点是拥有能返回迭代器的 begin 和 end 成员
declaration 定义一个变量,序列中的每个元素都能转换成该变量的类型,可使用 auto 类型说明符,若需要对序列中的元素执行写操作,循环变量必须声明为引用类型
注:在范围 for 语句中,预存了 end() 的值,一旦在序列中添加和删除元素,end 函数的值可能就无效了(3.4.1 p.98,9.3.6 p.315)

5.5 跳转语句

1.跳转语句中断当前的执行过程,C++语言提供了4种跳转语句:break、continue、goto 和 return
2.break 语句:负责终止离它最近的 while、do while、for 或者 switch 语句,并从这些语句之后的第一条语句开始继续执行
3.continue 语句:终止最近的循环的当前迭代并立即开始下一次迭代,continue语句只能出现在 for、while 和 do while 循环内部,或者嵌套在此类循环里的语句或块的内部

string buf;
while(cin >> buf && !buf.empty()){
	if(buf[0] != '_')
		continue;		//结束本次迭代,读取下一个输入,注意是重新while而不是跳出if语句块
	//程序执行到这里,说明当前的输入是以下划线开始的
}

4.goto 语句:作用是从 goto 语句无条件跳转到同一函数的另一条语句
goto label;
label 是用于标识一条语句的标示符
带标签语句是一种特殊的语句,在它之前有一个标识符以及一个冒号,标签标示符独立于变量或其他标示符的名字,因此,标签标示符可以和程序中其他实体的标示符使用同一个名字而不互相干扰
注:和 switch 语句类似,goto 语句也不能将程序的控制权从变量的作用域之外移动到作用域之内

	//...
	goto end;//此时位于变量ix的作用域之外,goto end会将程序的控制权从变量的作用域之外移动到作用域之内
	int ix = 10;//错误:goto语句绕过了一个带初始化的变量定义
end:
	//错误:此处的代码需要使用ix,但是goto语句跳过了它的声明
	ix = 42;

(与 switch 作用域跳转有相类似的地方)

5.6 try语句块和异常处理

1.异常处理机制为程序中的异常检测和异常处理两部分的协作提供了支持,C++中,异常处理包括:
1)throw 表达式:异常检测部分使用 throw 表达式它遇到了无法处理的问题,throw 引发了异常,中断当前执行路径的表达式,并把控制权转移到能处理该异常最近的 catch 子句
2)try语句块:异常处理部分使用 try 语句块处理异常,try 语句块以关键字 try 开始,并以一个或多个 catch 子句结束;try 语句块中代码抛出的异常通常会被某个 catch 子句处理,否则异常由外围 try 语句块处理,或者程序终止
3)一套异常类:用于在 throw 表达式和相关的 catch 子句之间传递异常的具体信息
2.throw 表达式:throw 表达式包括关键字 throw 和紧随其后的一个表达式,其中表达式的类型就是抛出的异常类型,throw 表达式后面通常紧跟一个分号从而构成一条表达式语句

//检查两条数据是否关于同一种书籍
if(item1.isbn() != item2.isbn())
	//ISBN不同,将抛出异常,该异常是类型runtime_error的对象,抛出异常将终止当前函数,并把控制权转移到能处理该异常的代码
	throw runtime_error("Data must refer to same ISBN");
//执行到此,表明两个ISBN是相同的
cout << item1 + item2 << endl;

3.try 语句块

try{
	program-statements
} catch (exception-declaration){
	handler-statements
} catch (exception-declaration){
	handler-sataements
} //...

以上为 try 语句块的通用语法形式,try 语句块中的 program-statements 可以包括声明在内的任意C++语句
try 块之后的一个或多个 catch 子句,包括关键字 catch,括号内一个(可能未命名的)对象的声明即异常声明以及一个块,当选中了某个catch 子句处理异常之后,执行与之对应的块,catch 一旦完成,程序跳转到 try 语句最后一个 catch 子句之后那条语句执行
try 语句块内的声明的变量在块外部无法访问,特别是在 catch 子句内与无法访问
4.标准异常:C++标准库定义了一组类,用于报告标准库函数遇到的问题,这些异常类也可以在用户编写的程序中使用,分别定义在4个头文件中:
1)exception 头文件,定义了最通用的异常类 exception,只报告异常的发生,不提供任何额外信息
2)stdexcept 头文件,定义了几种常用的异常类
exception 最常见的问题
runtime_error 只在运行时才能检查出的问题
range_error 运行时错误,生成的结果超出了有意义的值域范围
overflow_error 运行时错误:计算上溢
underflow_error 运行时错误:计算下溢
logic_error 程序逻辑错误
domain_error 逻辑错误,参数对应的结果值不存在
invalid_argument 逻辑错误,无效参数
length_error 逻辑错误,试图创建一个超出该类型最大长度的对象
out_of_range 逻辑错误,使用一个超出有效范围的值
3)new 头文件,定义了 bad_alloc 异常类型
4)type_info 头文件,定义了 bad_cast 异常类型

  • 标准库异常类只定义了几种运算,包括创建或拷贝异常类型的对象,以及为异常类型的对象赋值
  • 只能以默认初始化的方式初始化 exception、bad_alloc、bad_cast 对象,不允许提供初始值
  • 而其他异常类型的行为则恰好相反,应该使用 string 对象或者 C 风格字符串初始化这些类型的对象,但不允许使用默认初始化的方式,创建此类对象,必须提供初始值,该初始值含有错误相关的信息
    -异常类型只定义了一个名为 what 的成员函数,该函数没有任何参数,返回值为一个指向C风格字符串的 const char*,以提供关于异常的文本信息,当然若异常类型有一个字符串初始值,则 what 返回该字符串,对于其他无初始值的异常类型,what 返回的内容由编译器决定
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值