《C++Primer》读书笔记(五)语句

简单语句

(1)空语句
- 一种常见情况:当循环的全部工作在条件部分就可以完成时,会用到空语句

// 我们想要读取输入流的内容,直至遇到一个特定值,除此之外什么事情都不做
while(cin>>s&&s!=sought)
    ;

不要漏写分号,也不要在语句未结束时写分号

(2)符合语句(块)

块不以分号作为结束

语句作用域

  • 在if、switch、while和for语句,在控制结构中声明的变量,只有在相应语句的内部可见,语句结束,则变量也超出其作用范围

条件语句

if语句

  • if else语句的形式是
if(condition)
    ststement
else
    statement2
  • 使用if else语句
const vector<string> scores={"F","D","C","B","A","A++"};
string lettergrade;
if (grade<60)
    lettergrade=scores[0];
else
    lettergrade=scores[(grade-50)/10];
  • 嵌套if语句
// 加入的片段
if(grade % 10 > 7)
    lettergrade += '+';
else if (grade % 10 < 3)
    lettergrade += '-';
if(grade < 60)
    lettergrade=scores[0];
else{
    lettergrade=scores[(grade-50)/10];
    if(grade != 100)
        if(grade%10 > 7)
            lettergrade +='+'';
        else if(grade % 10<3)
            lettergrade += '-'
}
  • 悬垂else —— else 将会与最近的if匹配

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标签必须是整型常量表达式

(2)有时,默认的switch行为才是程序真正需要的。每个case标签只能对应一个值,但是有时候我们希望两个或更多个值共享一组操作,因此故意省略掉break语句

unsigned vowelCnt=0;
switch (ch){
    case 'a':
    case 'e':
    case 'i':
    case 'o':
    case 'u';
        ++vowelCnt;
        break;
}

漏写break容易引发缺陷

(3)default标签

(4)switch内部变量的定义
- 一般将变量的定义在case中用块包围,以免造成不必要麻烦

迭代语句

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;

传统for循环的执行流程

for(init-statemen;condition;expression)
    statement

(1)传统for循环的执行流程

(2)for语句头中的多重定义
- init-statement可以定义多个对象,但是只能有一条声明语句

// 记录下v的大小,当达到原来的最后一个元素后结束循环
for(dealtype(v.size()) i=0,sz=v.size() ; i!=sz ; ++i)
    v.push_back(v[i]);

(3)省略for语句头的部分
- 其中一种,省略expression

vector<int> v;
for(int i ; cin>>i ; /*表达式为空*/)  //条件部分能够改变i的值,无需表达式部分
    v.push_back(i);

范围for语句

  • 形式如下
for(declaration : expression)
    statement
  • expression表示的必须是一个序列,比如用花括号括起来的初始值表、数组、vector、string等类型的对象,它们的共同特点是拥有能返回迭代器begin和end成员
  • declaration定义一个变量,序列中每个元素都得能转换成该变量的类型,确保相容的最好办法是auto
vector<int> v={0,1,2,3,4,5,6,7,8,9};
for(auto &r : v)
    r*+2;

do while语句

  • 形式:
do
    statement
while (condition);
  • 小例子:不断提醒用户输入一对数,然后求其和
string rsp;
do{
    cout<<"please enter two values: "
    int val1=0,val2=0;
    cin>>val1>>val2;
    cout<<"The sum of them is: "<<val1+val2<<"\n\n"
        "More?Enter yes or no:";
    cin>>rsp;
}while(!rsp.empty()&&rsp[0]!='n');
  • 因为do while想执行语句块,后判断条件,所以不允许在条件部分定义变量

跳转语句

break语句

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

continue语句

  • continue语句:终止最近的循环中的当前迭代并立即开始下一次迭代
string buf;
while(cin>>buf && !buf.empty())
    if(buf[0] != '_')
        continue; //接着读取下一输入
    //程序处理到此处,即当前输入是以下划线开始的;接着处理buf……
}

goto语句

  • goto语句:从goto语句无条件跳转到同一函数内的另一条语句
    不要在程序中使用goto语句,因为它以理解和修改
goto label;
其中,label是用于标识一条语句的标示符,例如:“`end: return;“`

练习

do{
    int sz=get_size();
}
while(sz<=0);

try语句块和异常处理

  • 异常处理机制 为程序中异常检测和异常处理这两部分的协作提供支持,在C++中,异常处理包括:
    1. throws表达式
      • 异常检测部分使用throw表达式来表示它遇到了无法处理的问题
    2. try语句块
      • 异常处理部分使用try语句块处理异常
      • try语句块以关键字try开始,并以一个或多个catch子句结
      • try语句块中代码抛出的异常通常会被某一个catch字句处理
    3. 一套异常类
      • 用于在throw表达式和相关的catch字句之间传递异常信息

throw表达式

if(item1.isbn() != item2.isbn())
    throw runtime_error("Data must refer to same ISBN");
// 程序执行到此,道标isbn号相同
cout<<item1+item2<<endl;
  • 该异常是类型runtime_error的对象,其定义在stdexcept头文件中

try语句块

  • 形式如下:
try{
    program-statement
}catch(exception-declaration){
    handler-statements
}catch(exception-declaration){
    handler-statements
}//……

(1)编写处理代码

while(cin>>item1>>item2){
    try{
        //添加两个Sales_item对象的代码
        //如果添加失败,代码抛出一个runtime_error异常
    }catch(runtime_error err){
        //提醒用户两个isbn必须一致
        cout<<err.what()
            <<"\n Try agin? Enter yes or no"<<endl;

        char c;
        cin>>c;
        if(!cin || c=='n')
            break; //跳出while循环
    }
}

(2)函数在寻找处理代码的过程中退出
- 在寻找处理代码的过程与函数调用链刚好相反。当异常被抛出时,首先搜索抛出异常的函数。如果没有招到匹配的catch子句,终止该函数,并在调用该函数的函数中继续寻找。如果还是没有找到匹配的catch子句,这个新的函数也被终止,继续搜索调用它的函数。以此类推,沿着程序的执行路径逐层回退,直到招到适当类型的catch子句为止
- 如果最终还是没有找到任何匹配的catch子句,程序将自动转到名为terminate的标准库函数。该函数行为与系统有关,一般都将导致程序非正常退出

标准异常

  • exception头文件定义了最常用的异常类exception。它只报告异常的发生,不提供任何额外的信息
  • stdexcept头文件定义了几种常用的异常类
异常类 问题
exception 最常见的问题
runtime_erro 只有在运行时才能检测出的问题
range_error 运行时错误:生成的结果超出了有意义的值域范围
overflow_error 运行时错误:计算上溢
underflow_error 运行时错误:计算下溢
logic_error 程序逻辑错误
domain_error 逻辑错误:参数对应的结果值不存在
invalid_argument 逻辑错误:无效参数
length_eroor 逻辑错误:试图创建一个超出该类型最大长度的对象
out_of_range 逻辑错误:使用一个超出有效范围的值
  • new头文件定义了bad_alloc异常类型
  • type_info头文件定义了bad_cast异常类型
发布了34 篇原创文章 · 获赞 5 · 访问量 3万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章