C++学习笔记(7)——C++语句

C++程序是一组函数,而每个函数又是一组语句。C++有好多种语句类型,上篇笔记总结的表达式可以转化为语句,通常被称作表达式语句。除此之外,还有空语句(;),返回语句(return 0;),复合语句({}程序块)等。以上又被统称为简单语句。相对于简单语句,C++还有类似于C语言的特殊语句,条件语句、循环语句以及转移语句。本篇笔记总结这些特殊语句的用法。

一、条件语句

1.if语句

if(boolean_expression)

{

   // 如果布尔表达式为真将执行的语句

}

如果布尔表达式为true,则if语句内的代码块将被执行。如果布尔表达式为 false,则if语句结束后的第一组代码(闭括号后)将被执行。整个if语句被视为一条语句。

if的测试条件会被强制转化为bool类型,这意味着0被转换为false,一切非零值(包括负数)被转化为正值。常见的编写带有返回值的函数时,用返回0判断程序执行正常,返回负值代表错误代码,在调用该函数时只要用if(function())即可判断。

如果决策结果只有两种,也即“非黑即白”,那么可以引入if else语句。

if(boolean_expression)

{

   // 如果布尔表达式为真将执行的语句

}

else

{

   // 如果布尔表达式为假将执行的语句

}

如果布尔表达式为true,则执行 if 块内的代码。如果布尔表达式为false,则执行else块内的代码。

如果决策有两个以上的选择,那么将引入if elseif else结构语句。

if(boolean_expression 1)

{

   // 当布尔表达式 1 为真时执行

}

else if( boolean_expression 2)

{

   // 当布尔表达式 2 为真时执行

}

else if( boolean_expression 3)

{

   // 当布尔表达式 3 为真时执行

}

else

{

   // 当上面条件都不为真时执行

}

需要注意一个if后可跟零个或一个else,else必须在所有else if之后。一个if后可跟零个或多个else if,else if必须在else之前。一旦某个else if匹配成功,其他的else if或else将不会被测试。另外在书写if的条件表达式时,判别等于的情况最好写作if(value==variable),这可以避免与赋值语句的混淆。另外,浮点数由于截断误差的存在,不要用于比较相等或不等,而要写作相差是否在截断误差内的方式,如if(fabs(a-b)<1e-6);

2.switch语句

如果某种决策有五种以上选择,当然可以用if else if else来实现五个分支。但C++提供了更好的大型分支计算语句switch。

switch语句的基本格式如下:

switch (表达式)

{

case 常量表达式1:《语句序列1》《break;》//《》中的内容可省

……

case 常量表达式n:《语句序列n》《break;》//同上,下同

《default:语句序列》

}

其中:

表达式——条件表达式,用作判断条件,取值为整型、字符型、布尔型或枚举型。

常量表达式——由常量构成,取值类型与条件表达式相同。

语句序列——可以是一个语句也可以是一组语句。

switch语句的执行流程如下:

(1) 求条件表达式的值,并在常量表达式中找到与之相等的分支作为执行入口;

(2) 顺序执行该分支的语句序列,直到遇到break语句或开关语句的关括号“}”为止;这意味着程序进入某一分支后,将依次执行之后的所有语句,程序不会在执行到下一个case处自动停止,除非遇见了break;。但不意味着每个case后都要有break,因为顺序执行的情况也是有的。比如书中这段适应大小写字符输入的情况:

(3) 当条件表达式的值与所有常量表达式的值均不相等时,若有default分支,则执行其语句序列,否则跳出switch语句,执行后续语句。

将两种条件语句作比较,可以发现if语句可以对浮点数和范围进行条件判断,而switch只能对常量(整型),所以if 的应用比较广泛。但如果同样可以使用if语句和switch语句,如果分支大于3,通常要用switch语句。

二、循环语句

1. for循环

for循环允许您编写一个执行特定次数的循环的重复控制结构。

for ( init; condition; increment )

{

   statement(s);

}

for循环的执行流程为:

init 会首先被执行,且只会执行一次。这一步允许您声明并初始化任何循环控制变量。您也可以不在这里写任何语句,只要有一个分号出现即可。

接下来,会判断condition。如果为真,则执行循环主体。如果为假,则不执行循环主体,且控制流会跳转到紧接着for循环的下一条语句(for循环整体是一条语句)。

在执行完for循环主体后,控制流会跳回上面的increment语句。该语句允许您更新循环控制变量。该语句可以留空,只要在条件后有一个分号出现即可。

条件再次被判断。如果为真,则执行循环,这个过程会不断重复(循环主体,然后增加步值,再然后重新判断条件)。在条件变为假时,for循环终止。

2.while循环

while循环是没有初始化和更新部分的for 循环,它只有测试条件和循环体。只要给定的条件为真,while循环语句会重复执行一个目标语句。

while(condition)

{

   statement(s);

}

首先程序计算括号内的测试条件,如果为true则实执行循环体中的语句。知道测试条件为false为止。

通常,while的应用也要在while语句之前初始化一个值,判断条件也即判断该值,在while循环体内对这个值进行更新。这样的结果其实就是for循环的表达形式。所以,while循环被用在读入文件或输入,以及死循环(while(1))的情况。

3.do…while循环

不像for和while循环,它们是在循环头部测试循环条件。do...while循环是在循环的尾部检查它的条件。因此for循环和while循环被称作入口条件循环,而do…while是出口条件循环。

do...while循环与while循环类似,但do...while循环会确保至少执行一次循环。

do

{

   statement(s);

 

}while( condition );

条件表达式出现在循环的尾部,所以循环中的statement(s)会在条件被测试之前至少执行一次。

如果条件为真,控制流会跳转回上面的do,然后重新执行循环中的statement(s)。这个过程会不断重复,直到给定条件变为假为止。

三. 转移语句

这里的转移语句是指break,continue以及goto语句。

1.break和continue语句

break和continue语句都可以使程序能够跳过部分代码。可以在switch语句和任何循环中应用break语句,可以使程序跳到switch或循环后面的语句执行。continue语句只用于循环中,让程序跳过循环体中剩余的代码,并执行下一次循环。

注意:

  • break如果用于循环是用来终止循环,break只能终止距离它最近的循环

  • break如果用于switch,则是用于终止switch

  • break不能直接用于if中,除非if属于循环的一个句子,但此时它的作用是循环而不是if。

同样:

  • continue只作用于距离它最近的循环:for 、while 、do ...while

  • continue也不能直接用于if中,除非if属于循环的一个句子,同break,此时它的作用是循环而不是if

  • continue的优点之一是当需要有if作为判断条件来判断是否执行某些代码时,continue可以使得不必将所有的代码都放进if语句块中。

2.goto语句

C++和C语言一样也有goto语句。goto语句也成为无条件转移语句,其基本形式如下 :

goto 语句标号

语句标号由一个有效地标识符和符号";"组成,其中,标识符的命名规则与变量名称相同,即由字母、数字和下划线组成,且第一个字符必须是字母或下划线。执行goto语句后,程序就会跳转到语句标号处,并执行其后的语句。

通常goto语句与if条件语句连用,但是goto语句在给程序带来灵活性的同时,也会使得使程序结构层次不清,而且不易读,所以要合理运用该语句。在C++PrimerPlus中作者写明在大多数情况下(或者有的人认为在任何情况下)都不应该用goto语句,而应该用结构化控制语句实现其功能。因为goto使得程序的控制流难以跟踪,使程序难以理解和难以修改。任何使用 goto 语句的程序可以改写成不需要使用 goto 语句的写法。

但我个人觉得有一些场景可以尝试使用goto语句,比如多层嵌套循环的推出:

for(...) {
   for(...) {
      while(...) {
         if(...) goto stop;
         .
         .
         .
      }
   }
}
stop:
cout << "Error in program.\n";

消除goto会导致一些额外的测试被执行。一个简单的break语句在这里不会起到作用,因为它只会使程序退出最内层循环。

另外,在一些复杂流程的函数退出,尤其是要清理内存的情况也可以用goto。

比如以下是网上一个老外写的例子:

int MapiInit()
{
    int        Result              = DT_ERROR;
    HRESULT    hResult             = S_FALSE;
    HANDLE     hLock               = NULL;
    BOOL       bLocked             = FALSE;
    DWORD      rc                  = WAIT_TIMEOUT;
    static LPCTSTR szLockName      = _T("MAPIInit");

    hLock = CreateMutex(NULL,FALSE,szLockName);
    if(!hLock)
    {
        goto error;
    }
    rc = WaitForSingleObject(hLock,0);
    if(rc == WAIT_OBJECT_0)
    {
        bLocked = TRUE;
    }
    if(!m_CoInitd)
    {
        hResult = CoInitialize(NULL);
        if(hResult != S_OK)
        {
            goto error;
        }
        m_CoInitd = TRUE;
    }
    if(!m_MapiInitd)
    {
        hResult = MAPIInitialize(NULL);
        if(hResult != S_OK)
        {
            goto error;
        }
        m_MapiInitd = TRUE;
    }

    Result = DT_OK;
done:
    if (hLock) {
        if (bLocked) 
        {
            ReleaseMutex(hLock);
        }
        CloseHandle(hLock);
    }
    return Result;
error:
    Result = DT_ERROR;
    goto done;
}

如果在函数入口处动态开辟了一些内存空间(动态数组),可以在error处进行统一释放。这就省去了每一个判断失败的地方都释放一遍的重复代码。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bjtuwayne

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值