5.1简单语句
空语句
C++中大多数语句都以分号结尾,以个表达式末尾加上分号就变成了表达式语句。最简单的语句是空语句,空语句中只有一个分号,一种常见的情况是,如果一条循环语句中,条件就包含了循环所需的全部语句,则会在下方使用空语句,例如:
while(cin>>s&&s!=sought)
;//空语句
切忌分号不可乱加,例如:
while(iter!=svec.end());
++iter;
while的循环体是空语句,下面的递增语句不属于循环体
复合语句
复合语句是指用花括号括起来的语句,被括起来的部分成为块,一个快就是一个作用域,所以块内定义的变量只能在块中及其嵌套的子块中使用
5.2语句作用域
可以用if、while、switch、for,定义在控制结构当中的变量只在相应的语句内可见,一旦语句结束,变量也就超出了作用范围,如果其他代码需要用到此变量,须在结构外定义变量
5.3条件语句
C++提供了两种按条件执行的语句,一种是if,另一种是switch
if语句
if语句的作用是判断一个条件是否为真,根据判断结果决定是否执行另外一条语句,if语句有两种用法,一种是带else另一种不带。具体用法如下:
//不带else
if(a>60)
cout<<"pass"<<endl;
//带else
if(a>90)
cout<<"grate"<<endl;
else
cout<<"pass"<<endl;
上面的语句分别代表,判断a是否小于60,是则输出pass,否则无输出;
第二句判断a是否大于90,是则输出grate,否则输出pass。
嵌套的if语句
if语句可以嵌套,但在嵌套时应该注意else所匹配的if是哪个,C++语言规定,else与距离它最近且未匹配else的if匹配,例如:
if(grafe%10>=3)
if(grade%10>7)
lettergrade+='+';
else
letterrade+='-';
上述代码,即便else的缩进格式与第一个if相符,但编译器还是会把else匹配给内层if,想要else与外层if匹配需要使用花括号:
if(grafe%10>=3)
{
if(grade%10>7)
lettergrade+='+';
}
else
letterrade+='-';
此时,else将会匹配外层if。
switch语句
switch通常用在条件很多,且为同种条件的时候,例如想要判断一个单词中有几个元音字母:
int 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 'o':
++oCnt;
break;
case 'u':
++uCnt;
break;
}
}
以上程序先输入一个字符,然后判断字符是否为‘a’,是则aCnt递增,并退出switch语句,否则继续进行下面的判断。
通常我们会在每个条件下加上break语句,break语句是为了中断switch语句,如果去掉上述程序的所有break,则当一个条件成立后,会执行下面的所有语句,例如输入字符a,则aCnt,eCnt,iCnt,oCnt,uCnt都会递增,如果输入字符i,则iCnt,oCnt,uCnt会递增,但有时我们也会故意不加break语句,例如:我们想统计元音字母出现的总次数:
while(cin>>ch)
{
switch(ch)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
++vowelCnt;
break;
}
}
default标签
default与else类似,可以不加这条语句,default用来表示没有一个标签可以匹配的情况:
int aCnt = 0,eCnt = 0,iCnt = 0,oCnt = 0,uCnt = 0,otherCnt = 0;
char ch;
while(cin>>ch)
{
switch(ch)
{
case 'a':
++aCnt;
break;
case 'e':
++eCnt;
break;
case 'i':
++iCnt;
break;
case 'o':
++oCnt;
break;
case 'u':
++uCnt;
break;
default:
++otherCnt;
break;
}
}
上述程序,如果不是元音字母,则otherCnt递增。
switch的内部变量定义
如前所述,switch的执行流程有可能跨过某些语句,如果被跨过的语句内有变量的定义,则会产生问题。例如下列语句:
case true:
//因为程序的执行流可能会绕过以下语句,所以该switch语句不合法
string s;//错误,控制流绕过一个隐式初始化的变量
int ival = 0;//错误,控制流绕过一个显示初始化的变量
int jval;//正确,jval未初始化
case fause:
jval = 1;//正确,给jval赋初值
if(s.empty())//s在作用域内,但没有被初始化
想要解决以上问题,可以使用花括号,将一系列语句变为块,变量的作用域则会缩小。
5.4迭代语句
迭代语句通常称为循环,常用的有while、for、do while
while语句
当不知道循环的次数时,使用while语句较为合适
for语句
在知道循环次数时,使用for语句较为合适,for语句的第一条表达式可以定义多个对象,但是只能有一条语句,意味着所有的变量类型必须相同,
for(int i = 0,j = 0;i<10;++i)
省略for语句头中的某些部分
如果for语句头中不需要初始化,则可以将第一条语句设为空语句:
for(;i<10;++i)
其他情况也类似:如果省略循环条件,则相当于条件永远为真,此时,循环体内部必须有结束循环的语句;迭代语句也可以省略,则迭代语句需要在循环体内部出现。
范围for语句
前面已经介绍过,这里就不再赘述
do while语句
do while语句与while语句的区别是:do while语句先执行一次循环体的内容,再判断条件是否为真,具体用法如下:
do
cout<<"hello world"<<endl;
while(s.empty());
5.5跳转语句
break语句
break语句用来终止离他最近的while、do while、for、switch语句,所以break语句只能出现在上述语句的内部,并且break语句只会跳出离他最近的一个循环
continue语句
continue语句用来跳过循环体剩下的语句,然后执行下一次循环:
string s;
while(cin>>s&&1s.empty())
if(s[0]!='_')
continue;//接着读取下一个输入
//程序执行到这里,说明当前输入是以_开头的,接着处理s
此程序只能输入以_开头的单词
goto语句
goto语句的作用是无条件的跳转到同一函数的另一条语句。
语法形式是:goto label;
其中label是用于标识一条语句的标识符。带标签语句是一种特殊的语句,在它之前有一个标识符以及一个冒号:
end:return;//带标签语句,可以作为goto目标
建议:不要在程序中使用goto语句,它会使程序变得难以理解和修改
try语句块和异常处理
异常是指存在于运行时的反常行为,这些行为超出了函数正常功能的范围,典型的异常包括失去数据库连接以及意外输入等。
throw表达式
程序的异常检测部分使用throw表达式引发一个异常,使用方法:
//该程序是第一章的改写
if(item1.isbn()!=item2.isbn())//检查两条数据是否为同一书籍的
throw runtime_error("Data must refer to same ISBN");
cout<<item1+item2<<endl;//程序执行到这里则说明两条数据为同一书籍的
该异常是类型runtime_error的对象,这是标准库异常类型的一种,使用时必须进行初始化。
try语句块
具体用法如下:
while(cin>>item1>>item2)
{
try
{
//执行添加两个对象的代码
//如果添加失败,代码抛出一个runtime_error异常
}
catch(runtime_error)
{
//提醒用户两个ISBN必须一致,询问是否重新输入
cout<<err.what()
<<"\nTry again?Enter y or n"<<endl;
char c;
cin>>c;
if(!cin||c=='n')
break;//跳出while循环
}
}
标准异常
小结
本章内容大部分是已学过的东西,最后一小节简单介绍了异常处理,在之后的章节还会进行深入的讲解(课后习题见下一篇博客)