• 《C++ Primer》第5章 语句


    参考资料

    • 《C++ Primer》第5版
    • 《C++ Primer 习题集》第5版

    5.1 简单语句(P154)

    在一个表达式的末尾加上 ; 就构成了表达式语句,其作用是执行表达式并丢弃结果。

    空语句

    由单独的 ; 构成的语句为空语句。空语句常用于语法上需要一条语句但逻辑上不需要的场景:

    while(cin>>a)
        ;    // 空语句
    
    • 1
    • 2

    使用空语句时应加上注释

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

    while(iter != svec.end());    // 有害空语句
    	++iter;
    
    • 1
    • 2

    复合语句

    复合语句指用 {} 括起来的语句序列,也称作。一个块就是一个作用域。

    块不以分号结束

    如果语法上需要一条语句,而逻辑上需要多条语句,就需要使用复合语句。例如,whilefor循环体必须是一条语句,所以我们常常使用复合语句。

    空块是没有任何语句的 {} ,其作用等价于空语句。

    5.2 语句作用域(P155)

    可以在 ifswitchwhilefor 语句控制结构内部定义变量,作用域仅限于该条语句

    while(int i = get_num()){
    	cout<<i;    // 合法,i在while语句内部有效
    }
    cout<<i;    // 错误
    
    • 1
    • 2
    • 3
    • 4

    奇怪了,上述语句的控制结构里也不是语句啊?

    5.3 条件语句(P156)

    5.3.1 if语句(P156)

    if 语句包括两种格式:简单 if 语句和 if else 语句:

    // 简单if语句
    if(condition)
        statement
        
    // if else语句
    if(condition)
        statement1
    else
        statement2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    其中,condition 可以是条件表达式,也可以是初始化了的变量声明。

    嵌套if语句

    悬垂else

    如何知道某个 else 和哪个 if 匹配,这个问题称作悬垂 else 。C++ 规定,else离它最近尚未匹配if 语句。

    5.3.2 switch语句(P159)

    例子:

    switch(ch){
        case 'a':
            ++aCnt;
            break;
        case 'e':
            ++eCnt;
            break;
        default:
            ++cnt;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    switch 语句首先对括号里的表达式求值(也可以是初始化的变量声明),表达式的值转化为整数类型,然后与 case 中的每个标签比较,如果和某个 case 匹配成功,则从该标签后的,直到 switch 语句结尾或者遇到 break 语句。如果没有匹配成功,则会执行 switch 语句后的第一条语句。

    case 标签必须是整型的常量表达式。

    switch内部的控制流

    switch(ch){
        case 'a': case 'e': case 'i': case 'o': case 'u':
            ++cnt;
    }
    
    • 1
    • 2
    • 3
    • 4

    default标签

    如果 switch 想以一个空的 default 标签作为结束,则必须在 default 标签后跟上空语句或空块。

    switch(ch){
        case 'a':
            cout<<'a';
        default:    // default标签不是必须也在最后
            cout<<'b';
        case 'c':
            cout<<'c';
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    switch内部的变量定义

    如果某处一个带有初值的变量位于作用域之,在另一处该变量位于作用于之,则从前一处条跳转到后一处是非法行为,因为 C++ 不允许跨过变量的初始化语句直接跳转到该变量的作用域内。

    case true:
    	int i;
    	int j = 0;    // 错误
    	string str;    // 错误,str被隐式初始化了
    case false:
    	;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    需要注意的是,即使后面并没有用到前面初始化的变量,这种跳转也是不合法的。

    5.4 迭代语句(P165)

    5.4.1 while语句(P165)

    while(condition)
        statement
    
    • 1
    • 2

    condition 不能为空,只要 condition 的求值结果为真,就重复执行循环体。

    5.4.2 传统for语句(P166)

    for(init-statement;condition;expression)
        statement
    
    • 1
    • 2

    init-statement 必须是声明语句、表达式语句或空语句。

    for语句头中的多重定义

    init-statement 中可以声明多个对象,但只能有一条声明语句,所以所有对象的类型必须相同

    省略for语句头中的某些部分

    省略 condition 等价于在条件部分写了一个 true

    5.4.3 范围for语句(P168)

    for (declaration : expression)
        statement
    
    • 1
    • 2

    expression 必须是一个序列,如用花括号括起来的初始值列表、数组、vector 对象,这些类型的共同特点是有能返回迭代器的 beginend 成员。

    declaration 定义一个变量,且每次循环都会重新定义循环控制变量,并将其初始化为序列中的下一个值。

    范围 for 语句中预存了序列 end() 的值,如果在循环中添加或删除序列元素,可能会导致 end 函数的值失效。

    5.4.4 do while语句(P169)

    do
        statement
    while(condition);
    
    • 1
    • 2
    • 3

    do while 语句允许在 condition 内定义变量,conditon 使用的变量必须定义在循环体之外。

    5.5 跳转语句(P170)

    5.5.1 break语句(P170)

    break 负责终止离它最近的迭代语句和 switch 语句。

    5.5.2 continue语句(P171)

    continue 语句可以在迭代语句中使用,负责终止当前迭代并立即开始下一次迭代。

    5.5.3 goto语句(P172)

    goto label;
    label: statement
    
    • 1
    • 2

    label 是标识一条语句的标识符,可以与程序中的其他实体重名。goto 语句和目标标签的语句必须位于同一个函数之内

    5.6 try语句块和异常处理(P172)

    当程序某部分检测到一个无法处理的问题时,应该发出某种信号表明程序遇到了故障,然后交由异常处理部分处理。

    5.6.1 throw表达式(P173)

    throw 表达式能引发一个异常,如:

    throw runtime_error("Date must refer to same ISBN");
    
    • 1

    runtime_error 时标准库异常类型的一种,定义在 stdexcept 头文件中,runtime_error 对象必须初始化,方式是提供 string 对象或者 C 风格字符串。

    5.6.2 try语句块

    try{
        program-statements
    } catch(exception-declaration){
        handler-statements
    } catch(exception-declaration){
        handler-statements
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    catch 子句包括三部分:关键字 catch 、括号一个对象的声明、一个块。当某个 catch 子句处理异常后,执行其块,完成后跳转到最后一个 catch 子句的之后的语句执行。

    try 语句块组成程序的正常逻辑,其中定义的变量无法在 catch 子句中访问。

    int i = 0;
    try{
        cin >> i;
        if(i <= 0) throw runtime_error("i must be positive");
    } catch(runtime_error err){
        cout << err.what() << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    what()runtime_error 类的一个成员函数,每个标准库异常类都定义了 what() 成员,这些函数都没有参数,返回值为 C 风格字符串。

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

    当异常抛出时,首先检查抛出该异常的函数,如果没找到匹配的 catch 子句,则终止该函数,然后在调用该函数的函数中继续寻找,以此类推。特别地,那些没有包含在 try 语句块中的异常认为在当前函数没有 catch 子句与之匹配。如果最终也没能找到匹配的 catch ,程序将转到名为 terminate 的标准库函数,执行该函数通常会导致程序非正常退出。

    5.6.3 标准异常(P176)

    C++ 定义了一组类,用于报告程序遇到的问题。

    image-20231008195745729

    exceptionbad_allocbad_cast 对象只能默认初始化,其他对象则必须提供初始值。

    异常类型只定义了一个 what() 成员函数,对于没有初始值的对象,what() 函数的返回值由编译器决定。

  • 相关阅读:
    以太坊 layer2: optimism 源码学习 (一)
    希尔伯特变换与SSB调制
    835. Trie字符串统计,836。最大异或对,(Tire树,字典树)
    eslint如何支持uniapp的全局对象uni 和 H5+的plus 以及浏览器的全家对象 windows等...
    GO 语言处理并发的时候我们是选择sync还是channel
    代码整洁之原则
    8月4日农历七夕
    百题千解计划【CSDN每日一练】Ctrl+X,Ctrl+V(附解析+多种实现方法:Python、Java、C、C++、go、C#、JavaScript)
    基于Python实现的英文文本信息检索系统
    问道管理:历史市净率在哪看?
  • 原文地址:https://blog.csdn.net/MaTF_/article/details/133689580