• C++ Primer 第5章 语句


    5.1 简单语句

    C++语言中的大多数语句都以分号结束,一个表达式,末尾加上分号就变成了表达式语句。表达式语句的作用是执行表达式并丢弃掉求值结果。

    一、空语句

    ; // 空语句
    空语句是最简单的语句,空语句由一个单独的分号构成。如果在程序的某个地方,语法上需要一条语句但是逻辑上不需要,此时应该使用空语句,空语句什么也不做。
    
    • 1
    • 2

    二、别漏写分号,也别多写分号

    三、复合语句(块)

    复合语句是指用花括号括起来的语句和声明的序列,复合语句也被称作块。块不以分号作为结束。

    5.2 语句作用域

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

    5.3 条件语句

    5.3.1 if语句

    if (condition)
    	statement
    
    if (condition)
    	statement
    else 
    	statement2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    一、使用if else语句

    二、嵌套if语句

    三、注意使用花括号

    四、悬垂else

    C++规定else与离它最近的尚未匹配的if匹配。

    五、使用花括号控制执行路径

    5.3.2 switch语句

    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;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    switch语句首先对括号里的表达式求值,该表达式紧跟在关键字switch的后面,可以是一个初始化的变量声明。表达式的值转换成整数类型,然后与每个case标签的值比较(case标签必须是整型常量表达式,任何两个case标签的值不能相同)。如果表达式和某个case标签的值匹配成功,程序从该标签之后的第一条语句开始执行,直到到达了switch的结尾或者是遇到一条break语句为止。

    一、switch内部的控制流

    如果某个case标签匹配成功,将从该标签开始往后顺序执行所有case分支,除非程序显式地中断了这一过程,否则直到switch的结尾处才会停下来。

    unsigned vowelCnt = 0;
    switch (ch) {
    	// 出现了a、e、i、o或u中的任意一个都会将vowelCnt的值加1
    	case 'a':
    	case 'e':
    	case 'i':
    	case 'o':
    	case 'u':
    		++vowelCnt;
    		break;
    }
    
    switch (ch) {
    	// 另一种合法的书写形式
    	case 'a': case 'e': case 'i': case 'o': case 'u':
    		++vowelCnt;
    		break;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    二、漏写break容易引发缺陷

    三、default标签

    如果没有任何一个case标签匹配上switch表达式的值,程序将执行紧跟在default标签后面的语句。

    switch (ch) {
    	// 另一种合法的书写形式
    	case 'a': case 'e': case 'i': case 'o': case 'u':
    		++vowelCnt;
    		break;
    	default:
    		++otherCnt;
    		break;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    三、switch内部的变量定义

    如果在某处一个带有初值的变量位于作用域之外,在另一处该变量位于作用域之内,则从前一处跳转到后一处的行为是非法行为。

    case true:
    	string file_name; // 错误:控制流绕过一个隐式初始化的变量
    	int ival = 0; // 错误:控制流绕过一个显式初始化的变量
    	int jval; // 正确:因为jval没有初始化
    	break;
    case false:
    	jval = next_num(); // 正确:给jval赋一个值
    	if (file_name.empty()) // 
    		// ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
     #include 
    
     using namespace std;
    
     int main()
     {
        bool flag = false;
        switch (flag)
        {
            case true:
                int i = 10; // 报错
                // 解决方式
                // (1)加大括号限制i的使用范围
                // (2)不初始化i,只声明
                // 定义一个变量——编译阶段就会创建
                // 初始化一个变量——真正运行时才会创建
                break;
            case false:
                cout << "Hello World" << endl;
                cout << "&i = " << &i << endl;
        }
    
        return 0;
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    如果需要为某个case分支定义并初始化一个变量,我们应该把变量定义在块内,从而确保后面的所有case标签都在变量的作用域之外。

    case true:
    	{
    		// 正确:声明语句位于语句块内部
    		string file_name = get_file_name();
    	}
    	break;
    case false:
    	if (file_name.empty()) // 错误:file_name不在作用域之内
    		// ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5.4 迭代语句

    5.4.1 while语句

    while的条件部分可以是一个表达式或者是一个带初始化的变量声明
    while (condition)
    	statement
    
    • 1
    • 2
    • 3

    一、使用while循环

    5.4.2 传统的for语句

    for (init-statement; condition; expression)
    	statement
    init-statement必须是以下三种形式中的一种:声明语句、表达式语句、空语句
    
    • 1
    • 2
    • 3

    一、传统for循环的执行过程

    二、for语句头中的多重定义

    init-statement只能有一条声明语句,因此,所有变量的基础类型必须相同。

    三、省略for语句头的某些部分

    for语句头能省略掉init-statement、condition和expression中的任何一个(或者全部)。

    5.4.3 范围for语句

    expression表示的必须是一个序列,比如用花括号括起来的初始值列表、数组或vector或string等类型的对象,这些类型的共同特点是拥有能够返回迭代器的begin和end成员。
    for (declaration : expression)
    	statement
    
    • 1
    • 2
    • 3
    vector<int> v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    for (auto &r : v) 
    	r *= 2;
    
    // 等价于
    for (auto begin = v.begin(), end = v.end(); beg != end; ++beg) {
    	auto &r = *beg;
    	r *= 2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    不能通过范围for语句增加vector对象(或者其他容器)的元素了。在范围for语句中,预存了end()的值。一旦在序列中添加(删除)元素,end函数的值就可能变得无效了。

    5.4.4 do while语句

    do
    	statement
    while(condition);
    condition使用的变量必须定义在循环体之外
    
    • 1
    • 2
    • 3
    • 4

    5.5 跳转语句

    5.5.1 break语句

    break语句负责终止离它最近的while、do while、for或switch语句,并从这些语句之后的第一条语句开始继续执行。

    5.5.2 continue语句

    continue语句终止最近的循环中的当前迭代并立即开始下一次迭代。continue语句只能出现在for、while、do while循环的内部。

    5.5.3 goto语句

    goto语句的作用是从goto语句无条件跳转到同一函数的另一条语句。

    goto label;
    label是用于表示一条语句的标识符
    带标签语句是一种特殊的语句,在它之前有一个标示符以及一个冒号:
    end: return; // 带标签语句,可以作为goto的目标
    
    • 1
    • 2
    • 3
    • 4

    goto语句也不能将程序的控制权从变量的作用域之外转移到作用域之内。

    	goto end;
    	int ix = 10; // 错误:goto语句绕过了一个带初始化的变量定义
    end:
    	// 错误:此处的代码需要使用ix,但是goto语句绕过了它的声明
    	ix = 42;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5.6 try语句块和异常处理

    异常处理:
    (1)throw表达式:异常检测部分使用throw表达式来表示它遇到了无法处理的问题。我们说throw引发了异常
    (2)try语句块:异常处理部分使用try语句块处理异常。try语句块以关键字try开始,并以一个或多个catch子句结束。try语句块中代码抛出的异常通常会被某个catch子句处理。因为catch子句“处理”异常,所以它们也被称作异常处理代码
    (3)一套异常类,用于在throw表达式和相关的catch子句之间传递异常的具体信息。

    5.6.1 throw表达式

    程序的异常检测部分使用throw表达式引发一个异常。throw表达式包含关键字throw和紧随其后的一个表达式,其中表达式的类型就是抛出的异常类型。throw表达式后面通常紧跟一个分号,从而构成一条表达式语句。

    Sales_item item1, item2;
    if (item1.isbn() != item2.isbn()) {
    	throw runtime_error("Data must refer to same ISBN");
    	// 异常是类型runtime_error的对象。抛出异常将终止当前的函数,并把控制权转移给能处理该异常的代码
    	// 类型runtime_error是标准库异常类型的一种,定义在stdexcept头文件中
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    5.6.2 try语句块

    try {
    	program-statements
    } catch (exception-declaration) {
    	handler-statements
    } catch (exception-declaration) {
    	handler-statements
    }
    
    catch子句包括三个部分:关键字catch、括号内一个(可能未命名)对象的声明(异常声明)以及一个块
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    一、编写处理代码

    while (cin >> item1 >> item2) {
    	try {
    		// 执行添加两个Sales_item对象的代码
    		// 如果添加失败,代码抛出一个runtime_error异常
    	} catch (runtime_error err) {
    		cout << err.what() << "\nTry again? Enter y or n" << endl;
    		char c;
    		cin >> c;
    		if (!cin || c == 'n') 
    			break;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    二、函数在寻找处理代码的过程中退出

    当异常被抛出时,首先搜索抛出该异常的函数。如果没找到匹配的catch子句,终止该函数,并在调用该函数的函数中继续寻找。如果还是没有找到匹配的catch子句,这个新的函数也被终止,继续搜索调用它的函数。以此类推,沿着程序的执行路径逐层回退,直到找到适当类型的catch子句为止。
    如果最终还是没能找到任何匹配的catch子句,程序转到名为terminate的标准库函数。该函数的行为与系统有关,一般情况下,执行该函数将导致程序非正常退出。

    5.6.3 标准异常

    (1)exception头文件定义了最通用的异常类exception。它只报告异常的发生,不提供任何额外信息
    (2)stdexcept头文件定义了几种常用的异常类
    在这里插入图片描述
    (3)new头文件定义了bad_alloc异常类型
    (4)type_info头文件定义了bad_cast异常类型
    我们只能以默认初始化的方式初始化exception、bad_alloc和bad_cast对象,不允许为这些对象提供初值。其他异常类型的行为则恰好相反:应该使用string对象或C风格字符串初始化这些类型的对象,但是不允许使用默认初始化的方式。当创建此类对象时,必须提供初始值,该初始值含有错误相关的信息。
    异常类型只定义了一个名为what的成员函数,该函数没有任何参数,返回值是一个指向C风格字符串的const char*。该字符串的目的是提供关于异常的一些文本信息。

    小结

    C++语言提供了有限的语句类型,它们中的大多数会影响程序的控制流程:
    (1)while、for和do while语句,执行迭代操作
    (2)if和switch语句,提供条件分支结构
    (3)continue语句,终止循环的当前一次迭代
    (4)break语句,退出循环或者switch语句
    (5)goto语句,将控制权转移到一条带标签的语句
    (6)try和catch,将一段可能抛出异常的语句序列括在花括号里构成try语句块。catch子句负责处理代码抛出的异常
    (7)throw表达式语句,存在于代码块中,将控制权转移到相关的catch子句
    (8)return语句,终止函数的执行
    除此之外还有表达式语句和声明语句。表达式语句用于求解表达式。

  • 相关阅读:
    DVWA系列4:XSS 跨站脚本攻击之 DOM型 和 反射型
    大一学生期末大作业 html+css+javascript网页设计实例【电影购票项目】html网页制作成品代码
    数据预处理(预备知识)
    Gitee Pages个人简历部署(上)
    《web课程设计》用HTML CSS做一个简洁、漂亮的个人博客网站
    uView自定义图标和普通引入图标(iconfont-阿里巴巴图标库)
    计算机毕业设计JavaWeb闲置服装交易平台(源码+系统+mysql数据库+lw文档)
    Python基础之reduce函数
    盘点im即时通讯开发中Android后台保活方案
    如何通过bat批处理实现快速生成文件目录,一键生成文件名和文件夹名目录
  • 原文地址:https://blog.csdn.net/weixin_42589774/article/details/132945426