> 文档中心 > 第六章 选择语句《C语言程序设计现代方法(第2版)》读书笔记

第六章 选择语句《C语言程序设计现代方法(第2版)》读书笔记

目录

第六章 循环 🚀

6.2 do 语句 🚀

6.3 for 语句 🚀

6.3.1 for 语句的惯用法 🚀

6.3.2 在 for 语句中省略表达式 🚀

6.3.3 C99 中的 for 语句 🚀

6.3.4 逗号运算符 🚀

6.4 退出循环 🚀

6.4.1 break 语句 🚀

6.4.2 continue 语句 🚀

6.4.3 goto 语句 🚀

6.5 空语句 🚀

问与答 🚀


从今天开始,各书读书笔记就陆陆续续开展了哈(本书为《C语言程序设计现代方法(第二版)》)(一本书一个专栏,订阅会第一时间推荐更新哈),主要会把作者认为比较重要或者比较新奇的知识点记录下来。但是要想真的了解一本书,自己去看可能才会有更深的体会哈。


C语言入门篇进阶篇深剖篇都整理在这里了哈。然后这里是个人主页,比点头像更好找文章哈。

者新建立的社区:非科班转码社区-CSDN社区云💖💛💙

期待hxd的支持哈🎉 🎉 🎉


最后是打鸡血环节:改变的确很难,但结果值得冒险,拿出点勇气来。路还很长,现在才刚开始而已。过去无可挽回,未来可以改变。🚀 🚀 🚀

章 循环 🚀

循环 loop 是重复执行其他语句(循环体)的一种语句。在 C 语言中,每个循环都有一 控制表达式 controlling expression 。每次执行循环体(循环 重复 一次)时都要对控 制表达式求值。如果表达式为真(即值不为零),那么继续执行循环。C 语言提供了 3 种重复语句,即 while 语句、 do 语句和 for 语句。 break 语句用来跳出循环并把程序控制传递到循环后的下一条语句, continue语句用来跳过本次循环的剩余部分,而goto 语句则可以跳到函数内的任何语句上。

6.2 do 语句 🚀

do 语句和 while 语句关系紧密。事实上, do 语句本质上就是 while 语句,只不过其控制表达 式是在每次执行完循环体 之后 进行判定的。         顺便提一下,无论需要与否,最好给所有的 do 语句都加上花括号,这是因为没有花括号的do语句很容易被误认为是 while 语句:

6.3 for 语句 🚀

for 语句和 while 语句关系紧密。事实上,除了一些极少数的情况以外,for 循环总可 以用等价的 while 循环替换: 就像这个模式显示的那样, 表达式 1 是循环开始执行前的初始化步骤,只执行一次; 表达式 2 用来控制循环的终止(只要 表达式 2 的值 不为零,循环持续执行);而 表达式 3 是每次循环中最后被执行的一个操作。把这种模式用于先前的for 循环示例中,可以得到:

研究等价的 while 语句有助于更好地理解 for 语句。例如,假设把先前的 for 循环示例中的 i-- --i 来替换: 这样做会对循环产生什么样的影响呢?看看等价的 while 循环就会发现,这种做法对循环没有 任何影响:

因为for语句中第一个表达式和第三个表达式都是以语句的方式执行的所以它们的值互不相 关——它们有用仅仅是因为有副作用。 结果是,这两个表达式常常作为赋值表达式或自增 / 自减表达式。

6.3.1 for 语句的惯用法 🚀

6.3.2for 语句中省略表达式 🚀

for 语句远比目前看到的更加灵活。通常 for 语句用三个表达式控制循环,但是有一些 for 循环可能不需要这么多,因此 C语言允许省略任意或全部的表达式。

 

如果省略第一个表达式,那么在执行循环前没有初始化的操作:

在这个例子中,变量 i 由一条单独的赋值语句实现了初始化,所以在 for 语句中省略了第一个表 达式。(注意,保留第一个表达式和第二个表达式之间的分号。即使省略掉某些表达式,控制表达式也必须始终有两个分号。如果省略了for语句中的第三个 表达式,循环体需要确保第二个表达式的值最终会变为假。 我们的 for语句示例可以这样写: 为了补偿省略第三个表达式产生的后果,我们使变量 i在循环体中进行自减。         当for 语句同时省略掉第一个第三个 表达式时,它和while语句没有任何分别。例如,循环 这里 while 语句的形式更清楚,也因此更可取。 如果省略第二个表达式,那么它默认为真值,因此for语句不会终止(除非以某种其他形 式停止)。 例如,某些程序员用下列的for 语句建立无限循环:

6.3.3 C99 中的 for 语句 🚀

        在C99 中,for 语句的第一个表达式可以替换为一个声明,这一特性使得程序员可以声明一个用于循环的变量:

变量i不需要在该语句前进行声明。事实上,如果变量i在之前已经进行了声明,这个语句将创 建一个新的i且该值仅用于循环内。         for语句声明的变量不可以在循环外访问(在循环外不 可见):

        让for 语句声明自己的循环控制变量通常是一个好办法:这样很方便且程序的可读性更强,但是如果在for 循环退出之后还要使用该变量,则只能使用以前的 for 语句格式。 顺便提一下,for语句可以声明多个变量,只要它们的类型相同:

6.3.4 逗号运算符 🚀

有些时候,我们可能喜欢编写有两个(或更多个)初始表达式的 for 语句,或者希望在每 次循环时一次对几个变量进行自增操作。使用 逗号表达式 comma expression )作为 for 语句中第一个或第三个表达式可以实现这些想法。 这里的 表达式 1 表达式 2 是两个任意的表达式。逗号表达式的计算要通过两步来实现: 一步计算 表达式1并且扔掉计算出的值。第二步,计算表达式2,把这个值作为整个表达式的值。对表达式1的计算应该始终会有副作用;如果没有,那么表达式1就没有了存在的意义。 例如,假设变量 i 和变量 j 的值分别为 1 5 ,当计算逗号表达式 ++i , i+j 时,变量 i 先进行自增,然后计算i+j ,所以表达式的值为 7 。(而且,显然现在变量 i 的值为 2 。)顺便说一句,逗号运算符的优先级低于所有其他运算符,所以不需要在++i i+j外面加圆括号。         有时需要把一串逗号表达式串联在一起,就如同某些时候把赋值表达式串联在一起一样。逗号运算符是左结合的,所以编译器把表达式 因为逗号表达式的左操作数在右操作数之前求值,所以赋值运算 i = 1 j = 2 k = i + j是从左向右进行的。         提供逗号运算符是为了在C 语言要求只能有一个表达式的情况下可以使用两个或多个表达式。换句话说,逗号运算符允许将两个表达式“粘贴”在一起构成一个表达式。(注意与复合语句的相似之处,后者允许我们把一组语句当作一条语句来使用。)         需要把多个表达式粘在一起的情况不是很多。正如后面的某一章将介绍的那样,某些宏定义( 14.3 节)可以从逗号运算符中受益。除此之外, for 语句是唯一可以发现逗号运算符的地方。例如,假设在进入for 语句时希望初始化两个变量。可以把原来的程序           表达式sum = 0, i = 1 首先把 0 赋值给 sum ,然后把 1 赋值给 i 利用附加的逗号运算符, for语句可以初始化更多的变量。

6.4 退出循环 🚀

6.4.1 break 语句 🚀

当这些语句出现嵌套时, break 语句只能跳出一层嵌套。 break 语句可以把程序控制从 switch 语句中转移出来,但是却不能跳出 while 循环。后面会继 续讨论这一点。

6.4.2 continue 语句 🚀

用break语句会使程序控制跳出循环,而continue语句会把程序控制留在循环内。break语句和continue语句的另外一个区别是:break语句可以用于switch语句和循环(while、do和for),而continue语句只能用于循环。

6.4.3 goto 语句 🚀

break 语句和 continue 语句都是跳转语句:它们把控制从程序中的一个位置转移到另一个 位置。这两者都是受限制的: break 语句的目标是包含该语句的循环结束 之后 的那一点,而 continue 语句的目标是循环结束 之前 的那一点。 goto 语句则可以跳转到函数中 任何 标号的语句处。(C99增加了一条限制:goto语句不可以用于绕过变长数组( 8.3节)的声明。)

 

执行语句goto L;,控制会转移到标号L后面的语句上,而且该语句必须和goto语句在同一个函数中。

如果C语言没有break语句,可以用下面的goto语句提前退出循环:

 

goto 语句在早期编程语言中很常见,但在日常 C 语言编程中却很少用到它了。 break 、continue、 return 语句(本质上都是受限制的 goto 语句)和 exit 函数( 9.5 节)足以应付在 其他编程语言中需要 goto 语句的大多数情况。虽然如此, goto 语句偶尔还是很有用的。考虑从包含 switch 语句的循环中退出的问题。正 如前面看到的那样, break 语句不会产生期望的效果:它可以跳出 switch 语句,但是无法跳出 循环。 goto 语句解决了这个问题: goto 语句对于嵌套循环的退出也是很有用的。 

注意, return 语句后面没有 break 语句。紧跟在 return 语句后的 break 语句永远不会执行, 许多编译器还将显示警告消息。

6.5 空语句 🚀

语句可以为 ,也就是除了末尾处的分号以外什么符号也没有。 空语句主要有一个好处:编写空循环体的循环。 每次执行循环时,先判定条件 d < n 。如果结果为假,循环终止;否则,判定条件 n % d ! = 0 ,如果结果为假则终止循环。(在后一种情况下,n % d == 0 一定为真;换句话说,找到了 n 的一个约数。)

注意上面是如何把空语句单独放置在一行的,不要写成

C程序员习惯性地把空语句单独放置在一行。否则,一些人阅读程序时可能会混淆for语句 后边的语句是否是其循环体:         把普通循环转化成带空循环体的循环不会带来很大的好处:新循环往往更简洁,但通常不会提高效率。但是在一些情况下,带空循环体的循环比其他循环更高效。例如,这些带空循环体的循环更便于读取字符( 7.3 节)数据。

如果不小心在 if while for 语句的圆括号后放置分号会创建空语句,从而造成 if while for 语句提前结束。1. if 语句中,如果在圆括号后边放置分号,无论控制表达式的值是什么, if 语句执行的动作显然都是一样的

因为 printf 函数调用不在 if 语句内,所以无论 d 的值是否等于 0 ,都会执行此 函数调用。

2. while语句中,如果在圆括号后边放置分号,会产生无限循环

另一种可能是循环终止,但是在循环终止后只执行一次循环体语句。

这个例子显示如下消息:

3.  for语句中,在圆括号后边放置分号会导致只执行一次循环体语句:

 这个例子也显示出如下消息:

问与答 🚀

问: 6.1 节有如下循环:

这种写法的循环会在i达到0值时停止,所以它应该和原始版本一样好。p.70 

答:新写法确实更加简洁,许多 C 程序员也都这样写循环。但是,它也有缺点。 首先,新循环不像原始版本那样容易阅读。新循环可以清楚地显示出在 i 达到 0 值时循环终止,但是不能清楚地表示是向上计数还是向下计数。而在原始的循环中,根据控制表达式i > 0 可以推断出这一信息。 其次,如果循环开始执行时i 碰巧为负值,那么新循环的行为会不同于原始版本。原始循环会立刻终止,而新循环则不会。

问: 6.3 节提到,大多数 for 循环可以利用标准模式转换成 while 循环。能给出一个反例吗? p.74 答:当 for 循环体中含有 continue 语句时, 6.3 节给出的 while 模式将不再有效。思考下面这个来自 6.4节的示例: 但是,这个循环并不等价于原始循环。当 i 等于 0 时,原始循环并没有对 n 进行自增操作,但是新循环却做了。

问:哪个无限循环格式更可取,while(1)还是for(;;)p.75

答: C 程序员传统上喜欢 for(;;) 的高效性;因为早期的编译器经常强制程序在每次执行 while 循环体时测试条件1 。但是,对于现代编译器来说,在性能上两种无限循环应该没有差别。

问:听说程序员应该永不使用continue语句。这种说法对吗?

答:continue语句的确很少使用。尽管如此,continue语句有时还是非常方便的。假设我们编写的循 环要读入一些输入数据并测试其有效性,如果有效则以某种方法进行处理。如果有许多有效性测试,或者如果它们都很复杂,那么continue语句就非常有用了。循环将类似于下面这样:

问:goto语句有什么不好?p.79

答: goto 语句不是天生的魔鬼,只是通常它有更好的替代方式。使用过多 goto 语句的程序会迅速退化成“垃圾代码”,因为控制可以随意地跳来跳去。垃圾代码是非常难于理解和修改的。 由于goto语句既可以往前跳又可以往后跳,所以使得程序难于阅读。(break语句和 continue语句只是往前跳。)含有goto 语句的程序经常要求阅读者来回跳转以理解代码的控制流。goto语句使程序难于修改,因为它可能会使某段代码用于多种不同的目的。例如,对于前面有标号的语句,既可以在执行完其前一条语句后到达,也可以通过多条goto 语句中的一条到达。

问:除了说明循环体为空外,空语句还有其他用途吗?p.82

答:非常少。空语句可以放在任何允许放语句的地方,所以有许多 潜在 的用途。但在实际中,空语句只有一种别的用途,而且极少使用。 假设需要在复合语句的末尾放置标号。标号不能独立存在,它后面必须有语句。在标号后放置空语句就可以解决这个问题:

问:除了把空语句单独放置在一行以外,是否还有其他方法可以凸显出空循环体?p.82

最后的最后,创作不易,希望读者三连支持💖

赠人玫瑰,手有余香💖