我开发了一个基于 Beancount 的账本托管服务 HostedBeans,欢迎大家来了解纯文本复式记账并试用我的服务。
归档 2012 年 11 月

C++ 讲稿 6.循环语句A

By 精英王子

CC-BY-NC-SA(署名-非商业性使用-以相同方式共享) 3.0

注:解说在图片下方

原始幻灯片(持续更新):https://docs.google.com/presentation/d/1nv8Vc_ychYkVzamL69aanRL33lYgyAydju8i0Ip85Mg/edit

解说写在讲者备注

1

有时我们需要不断执行某个操作一定的次数,或者执行某个操作直到某种情况出现。

这时就用到了循环语句。

2

这是一个简单的for语句,在C++中for语句用来进行循环。
循环即按照某些条件,执行相同的代码,但代码中变量的值可能不同,所以可能每次循环都会呈现出不同的结果。

循环必须有终止条件,否则就成了死循环(当然,死循环在某些情况下是故意设计的),所以在每一次循环的时候都要更新一些变量的值,并判断是否达到了终止的条件。

初始化表达式(语句)会在循环开始前执行一次,通常用来定义与循环有关的变量,并赋初值。

条件表达式即用于判断是否循环,当条件表达式为真时,循环会继续进行,每次循环开始前都会重新对条件表达式进行判断。

更新表达式用于更新循环中的变量,使之可以在一定次数的循环后达到终止条件,更新表达式会在每次循环之后执行。

在这里,我在初始化表达式里面定义了一个变量i,并将它的值设置为0.

条件表达式是i<10,即只有i小于10时才继续循环。

更新表达式是i++. 它的作用是每次循环后把i加一,这个我们稍后介绍。

如此一来,循环中的语句便可以执行十次,十次后将等于10, 不满足条件i<10, 循环将结束。

3

如果用流程图表示前面那个程序,将会是这样。

4

自增、自减运算符。如i++,i&#8211;,是i=i+1,i=i-1的简写形式。

前缀和后缀的区别就是,前缀形式先将变量的值作为整个表达式的值,再对变量进行自增、自减运算。

后缀形式先对变量进行自增、自减运算,再将这个变量的值作为整个表达式的值。

自增、自减运算符只能用于变量,不能用于字面值。比如1++,因为1=1+1这样的表达式是错误的。

5

之前我们不止一次提到表达式和语句的概念,现在我们来讨论一下什么是表达式,什么是语句。

一般来讲,表达式由值和运算符组成,值是一个很宽的概念,可以是表达式、字面值、变量、函数返回值等。

运算符就是上节课我们提到的那些运算符,以及这节课新学到的自增/自减运算符,当然,还有很多运算符我们没有学习。

单个的值(单个的字面值、变量)也是表达式。

说了这么多,表达式的特点就是,所有表达式都具有一个值。

6

语句是特殊的语法结构,比如之前学到过的for、if、return、switch、变量定义语句等等。

所有表达式加上一个分号,就可以成为一个语句,功能是对这个表达式进行求值。求值是计算表达式的值的过程,如果表达式中含有具有副作用的运算符(如自增运算符),就会在求值时体现出副作用。

对于1这样一个字面值,加上一个分号可以成为一个语句,功能是对1进行求值,结果还是1,而且结果没有被储存到任何地方。这个语句对整个程序完全没有任何影响(通常会被编译器优化功能删除掉),我们称这个表达式没有副作用。

反之,a=b+c这个表达式在求值过程中(没错,记住赋值号也是一个普通的运算符),会把b+c的结果赋值给a,求值前后a的值发生了变化,我们称这个表达式有副作用

但反之不成立,语句去掉分号不一定能成为表达式。

if、for等结构被视为一条语句,虽然其中可能包含多条语句。

回到之前的for语句,你是否发现,被标注为“初始化表达式”的地方被写了一个语句——int i=0; 一个变量定义语句。

这是一个例外,C++规定for的初始化表达式可以是变量定义语句,定义的变量仅在这个for结构之内有效。

7

因为现在学习的内容越来越复杂,我会随时穿插习题。

8

再来看一个例子,它的功能是计算1+2+3+4+5+6+7+8+9+10的和。

首先我们定义了一个变量sum,用来储存它们的和。之前我们都在使用单个字母做变量的名字,这是因为那些变量实在没什么意义,起不出什么好名字。

大家应该尽可能使用有意义的英文单词作为变量名以增加代码的可读性,sum是和的意思。

初始化表达式中我将i(index)的初值设置为了1,因为我们要从1开始相加;条件表达式是i<=10,因为我们要计算10和10以下的整数的和,更新表达式依旧是i++.

sum+=i;的意思是sum=sum+i;即把sum和i相加,赋值给sum. 这句话会循环执行十次,每次i的值都是不同的,分别是1、2、3、4&#8230;&#8230;10.

这样每次循环都将i加到sum上,循环结束时,sum中的数就是我们要的结果了。

最后输出sum.

9

这个就很好理解了,不再详细讲解。

组合赋值运算符除了列出的五个还有一些。它们的优先级和赋值运算符相同,结合性也相同(向右结合)

10

逗号运算符连接两个表达式,(从左到右)逐个计算表达式的值,并将最后一个表达式的值作为整个表达式的值。

利用逗号运算符我们可以在一个语句(表达式)中完成多个表达式的求值。

比如for的条件表达式,只能提供一个表达式,但我们可以通过逗号运算符,将两个表达式连接成为一个表达式,作为for的条件表达式。

看下面的例子,将逐个计算a=1、b=2,c=3,并将c=3(即3)作为整个表达式的值,所以d=3.

值得注意的是逗号表达式的优先级非常低,几乎是优先级最低的运算符,在很多情况下,我们都需要加括号。

并非C++代码中所有的逗号都是逗号运算符,比如变量定义语句中的逗号,是变量定义语句中固有的结构,不是逗号运算符。

之前我也强调过,在C++中同一个符号,在不同的上下文,具有不同的含义。

11

while是C++中另一种循环语句,以while关键字开始,后面括号里直接就是条件表达式,满足这个条件,就会继续循环。

如果用while语句改写上面的程序,将会是这样。

将初始化语句移至循环开始之前,将更新表达式放入循环体。

12

通过之前的例子,我们可以得出这样一种大致的等价关系。

它们都可以用来进行循环,功能上没有区别,只是表达形式上有区别。

通常for用来进行已知循环次数的循环,而while用来进行需要达到某种条件的循环。

13

14

循环还没讲完,下节课接着讲。

C++ 讲稿 5.条件语句

By 精英王子

CC-BY-NC-SA(署名-非商业性使用-以相同方式共享) 3.0

注:解说在图片下方

原始幻灯片(持续更新):https://docs.google.com/presentation/d/1yA9HuxRrAQJNyucXv2EvosYreR5YxfXmeY3MxqhTQbo/edit

解说写在讲者备注

1

在此之前,我们编写的程序都像是一条直线,一句一句从头执行到位。

这节课我们会介绍条件语句,它可以令你的程序根据不同的输入,选择不同的分支来执行。进而获得不同的结果。

2

关系运算就是比较两个值的大小,或者两个值是否相等。

值得注意的是等于用两个等号表示,因为一个等号是赋值号,这点很容易被忘记。

关系运算的结果是bool类型,即是(true)/否(false).

需要明确这个概念:关系运算是一种普通的运算,和加减法无异,只不过这种运算通过比较来实现。

看右面最后一句,关系运算符的左右,可以是(字面值) ,也可以是表达式,或者变量,甚至函数的返回值。

3

逻辑运算是对bool类型的运算,即对是/否的运算,原理与数学中的逻辑联结词、物理中的逻辑电路相通。

通常逻辑运算用来对关系运算的结果进行加工,对关系运算的结果进行取反(最后一句),或者连接(第四句、第五句)。

C++中的逻辑运算符存在一种“短路效应”.

如右面被标红的那句,||的左面已经为true, 无论右面是何值,结果都将是ture, 所以C++在能够确定整个式子的结果的时候,会跳过右半部分的计算。

在&&运算时也存在类似情况,若左面的值为false,那么无论右面为何值,整个式子都是false, C++会跳过右半部分的计算。

这种短路效应在这个例子中无关紧要,当右半部分是一个(有副作用的表达式,如)函数时,短路效应将导致右半部分不会被计算(函数不会被调用).

4

不做过多解释,参见数学、物理书

5

这是一个简单的if语句的例子。
if语句的功能是根据一定的条件,决定是否要执行一段代码。

if后面跟着一个括号,括号中是一个bool类型的表达式,这个表达式的值决定了if是否执行接下来的代码。

我们之前介绍过,在C++中,花括号表示一个整体。在这里,这对花括号中的语句,就是当括号中的表达式为真时,if要执行的代码。

花括号中可以有任意行代码、一行、多行、没有,都可以。

当花括号中只有一行代码的时候,花括号可以省略。

按照通常的习惯,为了阅读方便,每个花括号中的代码都会向右缩进(比如4个空格), 在编辑器中按Tab可以缩进。

如果我输入了一个负数5, 表达式a<=0的值将会是true, 将会执行if中的代码,输出一行文字。

而如果我输入了一个正数3, 表达式a<=0的值将会是false, 会跳过if中的代码,不会有文字输出。

if是C++的关键字。

6

if else语句是对if语句的扩展,在if的语句块后面可以加上一个else, 并再附加一个语句块,这个语句块会在if语句的条件不成立的时候被执行。

同样,如果语句块(花括号)中只有一行,那么花括号是可以省略的,就像幻灯片上面那样。

if else语句中,无论括号中的表达式是真是假,都会有一个语句块被执行。当表达式为真时,if后的语句块被执行,为假时,else后的语句块被执行。

else也是C++中的关键字。

7

有些人在面对复杂的逻辑流程的时候,喜欢画流程图来帮助理解。

其实流程图可以看作是草稿一样,以比代码更清晰的方式来展现整个程序的逻辑。

而有的人并不喜欢流程图,他们觉得代码比流程图更容易理解。

8

else if 这看起来是一种新的语法,但其实不是,只不过将多个if else组合到了一起,并省略了花括号。

if会与离自己最近的else结合,形成一个if else语句。同时,整个if else语句,被认为是一个语句,单独包含在花括号中时可以省略花括号。

9

?:运算符可以认为是if else语句的简写形式,可以在一行内写完。

不要奇怪,它也是一个运算符,和加号减号一样,只不过它需要三个操作数。

10

但凡你学过一点数学,你应该知道4 + 3 * 2在数学中结果是10, 很高兴地告诉你,在C++里面也一样。

但是为什么是5呢?换成其他运算符又会怎样呢?

决定计算顺序的指标有两个:运算符的优先级,和运算符的结合性。

同时你可以任意添加括号,来改变计算顺序。

11

C++的运算符分为一元、二元、三元运算符,前面的数字代表运算符有几个操作数。

例如负号,它只需要一个操作数,所以叫一元运算符。

而加号需要两个操作数,所以叫二元运算符。

这个表中仅列出了我们学过的运算符,还有很多运算符我们没学过。

记不住优先级怎么办?加括号!

12

因为空间有限,我在一行中写了多个语句,这在C++中是允许的。

switch同样提供了分支的功能,它针对一个表达式可能是多个值之一的情况。

如在这里,月份只可能是1-12中的一个数。

switch后是一个括号,里面是要判断的表达式。再之后是一个大括号。

大括号中有若干个case关键字,后面跟着一个值和一个冒号。

当a的值和任意一个case后的值相等时,程序就会跳到此处执行。

(值得注意)默认情况下,程序会一直执行下去,会跨越多个case, 除非你手动用break语句退出switch.

如果要判断的表达式不和任何一个case匹配,就会执行default后的代码。

switch, case ,break, default都是C++的关键字。

13

14

如果要在屏幕上打印十次同一个字符串,除了把输出语句复制十次还有其他方法么?

近期计划 2012.11

RootPanel应该说是目前最重要的项目,我目测这周,或者最迟下周,RootPanel的基本功能可以搞定。前端包括在Web面板上创建和编辑网站、修改SSH/MySQL密码等等,后端包括生成Nginx/Apache2的配置文件、管理员后台。

搞定之后就可以开始内部测试了(欲参加请联系我,免费且有礼品),由于承诺过12月1日正式上线,好像测试有点仓促。测试过程中,简单重构一下代码,再添加其他功能,比如资源和流量监控、PPTP/Mongo支持等。

这次写RootPanel,也发现了LightPHP非常多的问题,最近还看了一些PHP方面的书,有些新想法,LightPHP将会有很大的变化。LightPHP重构完成后,可能着手完善JyBBS,思来想去,还是自己写个比较靠谱。

还打算对jybox.net进行改版,不光是把phpwind换成JyBBS,重心也会改,以提供一些公益性质的服务为主,以前whtsky和我这么说过。


还有零毫秒,目前一方面在等Qt5——其实这不是理由,Qt5 Beta早就出了。

另一方面在补充有关数字证书/密码学、ipv6/p2p网络方面的知识。

在完成RootPanel后,网站方面的改造工作,和零毫秒并行,零毫秒才是真正令人(只有我?)兴奋的。


我还打算入门一下一些常见的技术,包括我以前不看好的,多了解一点,反正我有时间。

参见

精子生于 1995 年,英文 ID jysperm.

订阅推送

通过 Telegram Channel 订阅我的博客日志、产品和项目的动态:

王子亭的博客 @ Telegram


通过邮件订阅订阅我的博客日志、产品和项目的动态(历史邮件):

该博客使用基于  Hexo  的  simpleblock  主题。博客内容使用  CC BY-NC-ND  授权发布。最后生成于 2024-04-08.