语句
一、简单语句
C++语言中的大多数语句都以分号结束,一个表达式,末尾加上分号就变成了表达式语句。
1.空语句
最简单的语句就是空语句,空语句中只含有一个单独的分号:
; //空语句
如果在程序的某个地方,语法上需要一条语句但是逻辑上不需要,此时应该使用空语句。
while(cin>>s && s!=sought)
; //空语句
2.复合语句
复合语句是只用花括号括起来的(可能为空)语句和声明的序列,复合语句也被称作块。一个块就是一个作用域,在块中引入的名字只能在块内部以及嵌套在块中的子块里访问。
while(cin>>s && s!=sought)
{
sum+=val;
++val;
}
从逻辑上来说要执行两条语句,但是while循环只能容纳一条。此时,把要执行的语句用花括号起来,就将其转换成了一条(复合)语句。
所谓空块,是指内部没有任何语句的一对花括号。空块的作用等价于空语句:
while(cin>>s && s!=sought)
{
} //空块
二、语句作用域
可以在if、switch、while和for语句的控制结构内定义变量。定义在控制结构当中的变量只在相应语句的内部可见,一旦语句结束,变量也就超出其作用范围了:
while(int i =get_num())
cout<<i<<endl;
i=0; //错误:在循环外部无法访问i
如果其他代码也需要访问控制变量,则变量必须定义在语句的外部:
auto beg =v.begin(); //beg定义在外部
while(beg != v.end() && *beg>=0)
++beg;
if(beg == v.end()) //beg定义在外部,其他语句才能访问
三、条件语句
1.if和switch语句区别
if语句:根据条件控制流
switch语句:它计算一个整型表达式的值,然后根据这个值从几条执行路径中选择一条。
2.if语句
if语句的作用:判断一个指定的条件是否为真,根据判断结果决定是否执行另外一条语句。
if语句包括两种形式:一种含有else分支,另外一种没有。简单的if语句的语法形式是
if(condition)
statement
if else语句的形式是
if(condition)
statement
else
statement2
condition必须用圆括号包围起来。condition可以是一个表达式,也可以是一个初始化的变量声明。不管是表达式还是变量,其类型都必须能转换成布尔类型。
如果condition为真,执行statement。当statement执行完成后,程序继续执行if语句后面的其他语句。
如果condition为假,跳过statement。对于简单if语句来说,程序继续执行if语句后面的其他语句;对于if else语句来说,执行statement2。
3.嵌套if语句
if (grada < 60)
lettergrad = scores[0];
else{
lettergrad =scores[(grada -50)/10];
if(grade%10>7)
lettergrad += '+';
else if(grade %10 <3)
lettergrad += '-';
}
4.悬垂else
if(grade%10>7)
if(grade %10 >3)
lettergrad += '+';
else
lettergrad += '-';
上面的代码else实际和内层的if匹配(grade%10>3),要跟外层的if匹配(grade %10 >7),需要使用花括号:
if(grade%10>7)
{ if(grade %10 >3)
lettergrad += '+';}
else
lettergrad += '-';
5.switch语句
switch语句提供了一条便利的途径使得我们能够在若干固定选项中做出选择。
举个例子,假如我们想统计五个元音字母在文本中出现的次数,程序逻辑应该如下所示:
//为每个元音字母初始化其计算值
int aCnt = 0, eCnt =0, iCnt =0, oCnt =0, uCnt =0;
char ch;
while(cin>>ch){
//如果ch是元音字母,将其对应的计数值加1
switch(ch){
case 'a':++aCnt;
break;
case 'e':++eCnt;
break;
case 'i':++iCnt;
break;
case 'o':++oCnt;
break;
case 'u':++uCnt;
break;
}
}
switch语句首先对括号里的表达式求值,该表达式紧跟在关键字swtich的后面,可以是一个初始化的变量声明。表达式的值转换成整数类型,然后与每个case标签的值比较。
如果表达式和某个case标签的值匹配成功,程序从该标签之后的第一条语句开始执行,直到达到了swtich的结尾或者遇到一条break语句为止。
如果swith语句的表达式和所有case都没有匹配上,将直接跳转到switch结构之后的第一条语句。
case关键字和它对应的值一起被称为case标签。case标签必须是整型常量表达式:
char ch =getVal();
int ival =42;
switch(ch)
{
case 3.14: //错误:case标签不是一个整数
case ival: //错误:case标签不是一个常量
任何两个case标签的值不能相同,否则会引发错误。
6.default标签
如果没有任何一个case标签能匹配上switch表达式的值,程序将执行紧跟在default标签后面的语句。
例如,可以增加一个计数值来统计非元音字母的数量,只要在default分支内不断增加名为otherCnt的变量就可以了:
switch(ch)
{
case:'a':case'e':
break;
default:
++otherCnt;
break
}
如果switch结构以一个空的default标签作为结束,则该default标签后面必须跟上一条空语句或一个空块。
7.switch内部的变量定义
如果被略过的代码中含有变量的定义改怎么办?如果在某处一个带有初值的的变量位于作用域之外,在另一处该变量位于作用域之内,则从前一处跳转到后一处的行为是非法行为。
case true:
//因为程序的执行流程可能绕开下面的初始化语句,所以该switch语句不合法
string file_name; //错误:控制流绕过一个隐式初始化的变量
int ival = 0; //错误:控制流绕过一个显式初始化的变量
int jval; //正确:因为jval没有初始化
break;
case false:
//正确:jval虽然在作用域内,但是它没有被初始化
jval = next_num(); //正确:给jval赋一个值
if(file_name.empty()) //file_name在作用域内,但是没有被初始化
如果需要为某个case分支定义并初始化一个变量,我们应该把变量定义在块内,从而确保后面的所有case标签都在变量的作用域之外:
case true:
{
//正确:声明语句位于语句块内部
string file_name =get_file_name();
}
break;
case false:
if(flie_name.empty()) //错误:file_name不在作用域之内
四、迭代语句
1.while语句
只要条件为真,while语句就重复地执行循环体,它的语法形式是:
while(condition)
statement
在while结构中,只要condition的求值结果为真就一直执行statement,condition不能为空,如果condition第一次求值是false,statement一次都不执行。
while的条件部分可以是一个表达式或者一个带初始化的变量声明。通常来说,应该由条件本身或者是循环体设法改变表达式的值,否则循环可能无法终止。
2.使用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;
if(beg==v.end())
//此时我们知道v中的所有元素大于等于0
3.传统的for语句
for语句的语法形式是:
for(init-statemen;condition;expression) //关键字for及括号里面的部分称作for语句头
statement
init-statemen必须是以下三种形式中的一种:声明语句、表达式语句或空语句,因为这语句都以分号作为结束。所以for语句的语法形式也可以看做:
for(initializer;condition;expression)
statement
init-statemen负责初始化一个值,这个值将随着循环的进行而改变。condition作为循环控制的条件,只要condition为真,就执行一次statement。如果condition第一次求值结果就是false,则statement一次也不会执行。expression负责修改init-statemen初始化的变量,修改发生在每次循环迭代之后。
4.省略for语句头的某些部分
for语句能省略掉init-statemen、condition和expression中的任何一个(或者全部)。
如果无须初始化,我们可以使用一条空语句作为init-statemen。例如,对于在vector对象中寻找第一个负数的程序,完全能用for循环改写:
auto beg =v.begin();
for(/*空语句*/;beg!=v.end()&&*beg>=0;++beg)
;
省略condition的效果等价于在条件部分写了一个true。因为条件的值永远是true,所以在循环替换内必须有语句负责退出循环,否则循环就会无休止地执行下去:
for(int i =0;/*空语句*/;++i)
; //对i进行处理,循环内部的代码必须负责终止迭代过程
省略掉for语句头中的expression,这样的循环中就要求条件部分或者循环体必须改变迭代变量的值。
vector<int> v;
for(int i =0;cin>>i;/*空语句*/)
;
因为条件部分能改变i的值 ,所以这个循环无须表达式部分。其中,条件部分不断检查输入流的内容,只要读取完所有的输入或者遇到一个输入错误就终止循环。
5.范围for语句
C++11引入了一种更简单的for语句,这种语句可以遍历容器或其他序列的所有元素。范围for语句的语法形式是:
for(declaration:expression)
statement
expression表示的必须是一个序列,比如花括号括起来的初始值列表、数组或者容器(vector、string)等类型对象,这些类型的共同特点是拥有返回迭代的begin和end成员。
declaration定义一个变量,序列中的每个元素都得能转换该变量的类型。确保类型最简单的方法是使用auto类型说明符,可以令编译器帮主我们制定适合的类型。如果需要对序列中的元素执行操作,循环变量必须声明引用类型。
vector<int> c={1,2,3,4,5};
for(auto &v :c)
cout<<v<<endl;
6.do while语句
do while语句和while语句唯一区别是,do while语句先执行循环体后检查条件。不管条件的值如何,我们都至少执行一次循环。do while语句的语法形式如下:
do
statement
while(condition); //do while语句应在括号包围起来的条件后面用一个分号表示语句结束
在do语句中,求conditiond的值之前首先执行一次statement,condition不能为空。如果condition的值为假,循环终止。否则,重复循环过程。condition使用的变量必须定义在循环体之外。
//使用do while执行加法运算
string res; // 作为循环的条件,不能定义在do的内部
do{
int vall =0, val2=0;
cin>>vall>>val2;
cin>>res;
}while(!res.empty() &&res[0]!='\n');
因为对于do while来说先执行语句或者块,后判断条件,所以不允许在条件部分定义变量:
do{
//...
numble(foo);
}while(int foo =get_foo()); //错误:将变量声明放在了do的条件部分
五、跳转语句
1.break语句
break语句负责终止离它最近的while、do while、for或switch语句,并从这些语句之后的第一条语句开始执行。
break语句只能出现在迭代语句或者switch语句内部:
string buf;
while(cin>>buf && !buf.empty()){
switch(buf[0]){
case '-':
for(auto it =buf.begin();it !=bf.end();++it){
if(*it=='')
break; //离开for循环
}
//break后将控制权转移到这里
break; //离开switch语句
case '+':
}
}
2.continue语句
continue语句终止最近的循环中的当前迭代并立即开始下一次迭代。continue语句只能出现在for、while和do while循环的内部,或者嵌套在此类循环里的语句或块的内部。
和break语句不不同的是,只有当switch语句嵌套在迭代语句内部时,才能在switch里使用continue。
continue语句中断当前的迭代,但是仍然继续执行循环。对于while或者do while语句来说,继续判断条件的值:对于传统的for循环来说,继续执行for语句头的expression;而对于范围for语句来说,则是用序列中的下一个元素初始化控制变量。
//每次从标准输入中读取一个单词。循环只对那些以下划线开头的单词感兴趣,其他情况,我们直接终止当前循环并获取下一个单词
string buf;
while(cin>>buf && !buf.empty()){
if(buf[0]!='_')
continue; //接着读取下一个输入
}
总结