简单语句
空语句
; //空语句
在程序的某个地方,语法上需要一条语句但逻辑上不需要,此时应该使用空语句。
使用空语句时应该加上注释,从而令度这段代码的人知道这句语句是有省略的。
复合语句(compound statement)
用花括号括起来的语句和声明序列,复合语句也被称为块(block)。将其转化成一条复合语句
while (val <= 40)
{
sum += val;
++val;
} //while只能容纳一条语句,要执行的语句括起来后转化成一条(复合)语句
语句作用域
可以在if、switch、while和for语句的控制结构内定义变量。定义在控制结构当中的变量只能在相应语句内部可见,一旦语句结束,变量也就超过其作用范围。
while(int i = get_num())
cout << i << endl;
i = 0; //错误
悬垂else(dangling else)
在那些既有if语句又有if else语句的语言中是个普遍的问题。C++的解决方案离他最近尚未匹配的if.
if (grade % 10 >= 3)
if(grade % 10 > 7)
lettergrade += '+';
else
lettergrade += '-';
//代码编辑时
//真实编译时
if (grade % 10 >= 3)
if(grade % 10 > 7)
lettergrade += '+';
else
lettergrade += '-';
switch语句
注:①如果switch语句表达式和所有case都没有匹配上,将直接跳转到switch结构之后的第一条语句。
②case关键字和它对应的值一起被称为case标签(case label)。case标签必须是整型常量表达式
char ch = getVal();
int ival = 42;
switch(ch)
{
case 'a': ; //正确
case 3.14: ; //错误
case ival: ; //错误
}
③如果某个case标签匹配成功,将从标签开始循序执行所有case分支【break语句的原因】
④一定不要省略case分支最后的break语句。如果没有break语句,最好加一段注释说明清楚程序的逻辑。
⑤default标签:即使不准备在default标签下做任何工作,定义一个default标签也是有用的。其目的在于告诉程序的读者,我们已经考虑到了默认的情况,只是目前什么也没做。
⑥在C++中,switch-case中的case实质上只是一个标签(label),就像goto的标签一样。case中的代码并没有构成一个局部作用域,虽然它的缩进给人一种错觉,好像它是一个作用域。也就是说,所有在case里面定义的变量作用域都是switch{...},
switch(selector)
{
cout << selector;
case selector_a:
int i = 1;
case selector_b:
// i在此仍然可见
}
如果一个程序的执行路径从代码中的点A(某个局部变量x还未定义)跳到代码中另一点B(该局部变量x已定义,并且定义的时候有初始化),那么编译器会报错。
⑦ 在case中定义变量时必须在周围加{..}以形成局部作用域,否则编译报错。习惯上总是将case中的代码用{..}括起来,比较省事。是有些公司的coding convention之一。
case true:
{
string file_name = get_file_name();
}
迭代语句
传统for循环语句
注:①如果第一次迭代时条件就为假,for循环体一次也不会执行
for (int i = 0; i <= -1; ++i)
cout << 'a' << endl; //一个也没有
②init_statement只能有一条声明语句。因此,所有变量的基础类型必须相同
for(decltype(v.size()) i = 0, sz = v.size(); i != sz; ++i )
v.push_back(v[i]);
③for语句头能省略掉init-statement、condition和expression中的任意一个(或者全部)
auto beg = v.begin();
for( ; beg != v.end() && *beg >= 0 ; ++beg)
;
auto beg = v.begin();
for( int i = 0 ; ; ++i)
//必须存在负责终值迭代的语句
vector <int> v;
for (int i; cin >> i; )
v.push_back(i);
范围for语句(C++11)
for(declaration : expression)
statement
expression: 表示的必须是一个序列,用花括号括起来的初试值列表,vector或string等类型的对象
declaration: 表示的是一个变量(auto类型说明符)
for语句的定义来源于与之等价的传统for语句;
【如此可以理解】不能通过范围for语句增加vector对象(或者其他容器)的元素了。
在范围for语句中,预存了end()的值。一旦在序列中添加(删除)元素,end函数的值就可以变得无效了;
跳转语句
C++语言提供了4种跳转语句:break,continue,goto和return。
break语句
负责终止距离它最近的while、do while、 for或switch语句【没有if!!!】,并从这些语句之后的第一条语句开始继续执行。
string buf;
while (cin >> buf && !buf.empty())
{
switch (buf[0])
{
case '-' :
{
for (auto it = buf.begin() + 1; it != buf.end(); ++it)
if (*it == ' ')
break; //跳转case结束
}
break; //跳转switch结束
case '+' :
{
;
}
default:
break;
}
break; //跳转while结束
}
continue语句
终止最近的循环中的当前迭代并立即开始下一次迭代。
只能出现在for、while、do while循环的内部,或者镶嵌在此类循环类的语句或块的内部。
string buf;
while (cin >> buf && !buf.empty())
{
if(buf[0] != '_')
{
continue;
}
}
与break比较:相同:仅作用于离它最近的循环;
不同:只有当switch语句嵌套在迭代语句内部时,才能在switch里使用continue。
goto语句
作用:从goto语句无条件跳转到同一函数内部的另一条语句【不要在程序中使用,使得程序难以理解并且难以修改】
goto label;
注:①goto语句和控制权转向的那条带标签的语句必须位于同一个函数之内
②带标签语句(labeled statement)
end:return; //带标签语句,可以作为goto目标
③标签标识符独立于变量或其他标识符的名字
④和switch语句相同,goto语句不能将程序的控制权从变量的作用域之外转移到作用域之内
goto end;
int ix = 10;
//标签绕过了它的声明,错误
end:ix = 42;
begin:
int sz = get_size();
if (sz <= 0)
{
goto begin;
}
//成立 语句将销毁zs,从新定义并初始化
try语句块和异常处理
异常处理机制为程序中异常检测和异常处理这两部分的协作提供支持
throw表达式(throw expression):异常检测部分使用throw表达式来表示它遇到了无法处理的问题。我们说throw引发(raise)了异常
try语句块(try block):异常处理部分使用try语句处理异常。
throw表达式
在这段代码中,会抛出一个异常,该异常的类型runtime_error的对象。抛出异常时终止当前函数,并把控制权移交给可以处理异常的代码。
#include <stdexcept>
using std::runtime_error;
#include <new>
using std::bad_alloc;
throw (表达式:其类型就为异常类型);
throw bad_alloc();
throw runtime_error("error!");;
#include <stdexcept>
using std::runtime_error;
int main()
{
vector<string> buf{"asdf","asdf","asdf"};
if (buf[1] == buf[0])
throw runtime_error("error!");
return 0;
}
try语句块
try
{
program-statements;
}
catch(exception-declaration)
{
handler-statements;
}
给用户的提示信息中输出了err.what()的返回值。err的类型是runtime_error,因此得知what是runtime_error类的一个成员函数。
每个标准库异常类都定义了名为what的成员函数,这些函数没有参数,返回值为“const char*”
【提示】编写异常安全的代码非常困难
我们需要清楚异常何时发生,异常发生后程序如何确保对象有效、资源无泄漏、程序处于合理状态。
标准异常
C++标准库定义了一组类,用于报告标准库函数遇到的问题。这些异常类可以在用户编写的程序中使用。
<exception>定义 异常类 exception(最通用) 仅支持默认初始化方式
<stdexcept>定义 几种 异常类 仅支持string/C风格字符串初始化
<new>定义 异常类bad_alloc 仅支持默认初始化方式
<type_info> 定义 异常类bad_cast 仅支持默认初始化方式
异常类型只定义了一个名为what的成员函数,该函数没有任何参数,返回一个指向C风格的字符串。
术语表:
块(block)/复合语句(compound statement):包围在花括号内的由0条或多条语句组成的序列。块也是一条语句,所以只要是能够使用语句的地方,就可以使用块。
异常类(exception class):标准库定义的一组类,用于表示程序发生的错误。
异常声明(exception declaration):位于catch字句中的声明,指定该catch可以处理的类型
带标签语句(labeled statement):前面带有标签的语句。所谓标签是指一个标识符以及紧跟着的一个冒号。对于同一个标识符来说,用作标签的同时还能用于其他目的,互不干扰。
terminate:标准库函数,当异常没有被捕捉到时调用。terminate终止当前程序的执行。