1、复合语句(块):
用花括号括起来的(可能为空的)语句和声明的序列。
在块中引入的名字只能在块内部以及嵌套在块中的子块里访问。
2、if else语句
可以将if else语句当成一条语句来理解
例:
if(grade >= 60)
if(grade >= 90)
cout << "great";
else
cout << "fail";
通过缩进格式可以看出程序初衷是希望else与外层的if匹配,即grade < 60时输出"fail",然而这里的else分支实际上是内层if语句的一部分,即60 <= grade < 90时输出"fail"。可以通过块来使else和外层的if匹配:
if(grade >= 60){
if(grade >= 90)
cout << "great";
}else //花括号强迫else和外层if匹配
cout << "fail";
3、switch语句
case关键字和对应的值合称case标签。case标签必须是整型常量表达式。
switch(ch){
case 3.14: //错误:3.14不是整型
case ival: //错误:ival不是常量
}
一种常见的错觉就是把case当成if else语句那样只执行匹配成功的那个case分支的语句,然而实际上如果某个case标签匹配成功,将从该标签开始往后顺序执行所有case分支,所以通常在下一个case标签之前应该有一条break语句用于避免执行后续case分支的代码。
switch(ch){
case 'a':
++acnt;
//break; //此处应有break语句,下面同理
case 'e':
++ecnt;
case 'i':
++icnt;
case 'o':
++ocnt;
case 'u':
++ucnt;
default:
++othercnt;
}
若是ch的值是'e',那么执行完++ecnt;将会跨越case标签的边界继续执行++ocnt;++ucnt;++othercnt;
然而有时默认的switch行为才是程序需要的,每个标签只能对应一个值,有时我们希望两个或更多值共享同一组操作,此时故意省略break语句使程序能够连续执行若干case标签。
switch(ch){
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
++vowelCnt; //只要ch满足任一条件都会执行此语句
break;
}
switch内部变量的定义
C++语言规定,不允许跨过变量的初始化语句直接跳转到该变量作用域内的另一个位置。如果需要为某个case分支定义并初始化一个变量,应该把变量定义在块内,从而确保后面所有的case标签都在变量的作用域之外。
我的理解是被跳过的定义而未初始化的变量是可以在后面使用的,而定义时初始化的变量就不能使用。
case true:
{
int ival = 0;//正确,ival的作用域只在这个块内
}
int jval; //正确:因为jval没有被初始化
int kval; //错误:控制流绕过一个显式初始化的变量的初始化
string s; //错误:控制流绕过一个隐式初始化的变量的初始化
break;
case false:
ival = 1; //错误:ival不在作用域之内
jval = 1; //正确:给jval赋值1
kval = 1; //错误:kval在作用域内但未被初始化。
4、传统for语句
for (init-statement;condition;expression)
statement
init-statement可以定义多个对象,但只能有一条声明语句,故所有变量的基础类型必须相同。
condition部分建议用!=代替<、>。
//记录下v的大小,当到最后一个元素后结束循环
for (decltype(v.size()) i = 0, sz = v.size(); i != sz; ++i)
v.push_back(v[i]);
5、范围for语句
vector<int> v{0,1,2,3,4,5,6,7,8,9};
for(auto &r : v) //范围变量是引用类型才能对v的元素执行写操作
r *= 2;
范围for语句的定义来源于与之等价的传统for语句:
for (auto beg = v.begin(), end = v.end(); beg != end; ++beg){
auto &r = *beg;
r *= 2;
}
6、break和continue语句
break负责终止离它最近的while、for、do while、switch语句
continue负责终止最近的while、for、do while循环中的当前迭代并立即开始下一次迭代。只有当switch语句嵌套在迭代语句内部时,才能在switch里使用continue。
7、goto语句
尽可能不使用。
与switch相似,goto不能将程序的控制权从变量的作用域之外转移到作用域之内。
goto end;
int i = 0; //错误goto语句绕过了一个带初始化的变量定义
end: //错误,此处的代码要用到i,而goto语句绕过了它的声明
i = 1;
8、try语句块和异常处理(未完)
throw表达式:表示异常检测部分遇到了无法处理的问题
try语句块:用于处理异常。以关键字try开始,并以一个或多个catch子句结束。try语句块中代码抛出的异常通常会被某个catch子句处理,catch子句的代码亦被称为异常处理代码。
异常类:用于在throw表达式和相关的catch子句之间传递异常的具体信息。
throw表达式包含关键字throw和紧随其后的一个表达式,表达式的类型就是抛出的异常类型。
string s1, s2;
cin >> s1 >> s2;
if(s1 == s2){
cout << "same" << endl;
return 0;
} else {
cerr << "wrong" << endl;
return -1;
}
假如需要输入两个相同的字符串(如确认密码),那么应该把输出的代码和用户交互的代码分离开。此例中,改写程序使得首先检查s1和s2是否相同,且不再直接输出一条信息,而是抛出一个异常。
if(s1 != s2)
throw runtime_error("Data must refer to same string");
//如果程序执行到这里,表示s1和s2是相同的
cout << "same" << endl;
这段代码中如果s1和s2不相同就抛出一个异常,类型是runtime_error的对象。抛出异常将终止当前函数并把控制权转移给能处理该异常的代码。
try语句和标准异常暂时未看