C语言KR圣经笔记 3.6 do-while循环 3.7 break和continue 3.8 goto和标号

2023-11-11 08:12

本文主要是介绍C语言KR圣经笔记 3.6 do-while循环 3.7 break和continue 3.8 goto和标号,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

3.6 do-while循环

如第1章所述,while 和 for 在循环顶部检查结束条件。与之相反,C语言的第三个循环,do-while 是每轮循环的主体走完之后,在底部检查结束条件;循环体至少会执行一次。

do 的语法为

do

        语句

while (表达式);

先执行语句,然后对表达式求值。如果为真,则继续执行语句,接着再对表达式求值,就这样循环往复。当表达式变为假时,循环结束。除了检查的含义外,do-while 等价于Pascal的 repeat-until语句【Pascal的 until 判断为真则循环退出,与C语言的 while 表达式判断为假才退出,含义正好相反】

经验显示 do-while 用得比 while 和 for 少得多。然而,有时它也是有价值的,比如下面这个函数 itoa,将一个数转换成字符串( atoi 的反向处理)。这活儿比你一开始可能想的要稍微复杂些,因为用简单方法生成的字符串顺序是错误的。我们选择反向生成字符串,然后将其翻转。【reverse函数见上一节】

/* itoa: 把n转换成字符串,存入s */
void itoa(int n, char s[])
{int i, sign;if ((sign = n) < 0)   /* 记录符号 */n = -n;           /* 使n为正数 */do {                /* 倒序生成字符串 */s[i++] = n % 10 + '0';     /* 获取下一个数位 */} while ((n /= 10) > 0)        /* 删除该数位 */if (sign < 0)s[i++] = '-';s[i] = '\0';reverse(s);
}

这里用 do-while 是必要的,至少是方便的,因为至少要有一个字符被放到数值 s 中,即使 n 是 0。尽管大括号不是必需的,我们还是把构成 do-while 主体的单条语句包在其中,避免草率的读者把 while 部分错看成是一个 while 循环的开始

练习3-4、在数字用2的补码表示的机器上,我们的 itoa 版本无法处理最大的负数,即当 n = -(2的字长 -1 次方)。解释为何如此。修改程序使之打印正确的值,不管它跑在什么机器上。

练习3-5、写函数 itob(n ,s, b) 将整数 n 转换成以 b 为基数的字符串并存入字符串 s 中。特别说明,itob(n, s, 16) 把 n 格式化为 16进制数存入s中。

练习3-6、写个一版接受3个而不是2个参数的 itoa 函数。第三个参数为最小域宽度;有必要的话,在转换后的数字左侧填充空格使其达到足够的宽度。

3.7 break和continue

不通过顶部或底部的条件检查而直接从循环中退出,有时会比较方便。break 语句提供了从 for、while 和 do 中提前退出的方法,还包括前面说过的 switch 。break 会使它所在的最内层循环或 switch 马上退出。

下面的函数 trim 从字符串末尾删除结尾的空格,制表符和换行符,当发现最右边的非空格、非制表符、非换行符时,它使用 break 从循环中退出。

/* trim: 删除末尾的空格、指标和换行符 */
int trim(char s[])
{int n;for (n = strlen(s)-1; n >= 0; n--)if (s[n] != ' ' && s[n] != '\t' && s[n] != '\n')break;s[n+1] = '\0';return n;
}

strlen 返回字符串的长度。for 循环从末尾开始反向扫描,寻找第一个非空格、非制表、非换行符。当找到一个这样的字符,或者 n 变为负数时(此时整个字符串都扫描完了),循环结束。你应该验证,即使在字符串为空或者只包含空白字符的时候,这个处理也是正确的。

continue 语句与 break 相关,但用的少一些;它会使其所在的 for、while 和 do 循环开始下一轮迭代。在 while 和 do 中,这意味着马上执行括号内的检查部分;而对于 for, 控制转移到递增的步骤【即表达式3】。continue 语句只用于循环,不用于 switch。若循环内有 switch 且 switch 内有 continue 时,这个 continue 会使循环进入下个迭代。

例如,下面这个代码段只处理数组 a 中的非负元素;负值都被跳过了

for (i = 0; i < n; i++) {if (a[i] < 0)    /* 跳过负元素 */continue;...   /* 处理正元素 */
}

 continue 语句经常用在这种情况:当循环后面的一部分非常复杂,而把测试条件反转然后再加一层缩进,会让程序嵌套太深【而影响阅读/维护】

3.8 goto 和 标号

C提供了可被无限滥用的 goto 语句,以及跳转的标号。正式地说,goto 并非必要,而且实践中总是很容易写出不用 goto 的代码。本书中我们还没用过 goto。

然而,还是存在一些也许可以使用 goto 的场景。最常用的是从某些深深嵌套的结构中放弃处理,比如从两层或更多层的循环中马上跳出来。不能直接使用 break 语句是因为它只能退出最内层的循环。像这样:

for (...)for (...) {if (disaster)goto error;}
...error:善后处理

如果错误处理代码很重要,而且错误会发生在多处,则这个代码组织方式是很方便的。

标号的形式与变量名相同,后面跟着冒号。标号可以加到与 goto 所在同一函数的任一语句前面。标号的作用域是整个函数。

另一个例子是判断两个数组 a 和 b 是否有相同的一个元素。一种可能的写法是:

    for (i = 0; i < n; n++)for (j = 0; j < m; j++)if (a[n] == b[m])goto found;/* 没找到相同元素的处理 */...
found:/* 找到 a[i] == b[j] */...

涉及 goto 的代码总是能写成不带 goto的,尽管可能的代价是一些重复的检查或一个额外的变量。例如,上面的例子改写为

found = 0;
for (i = 0; i < n && !found; i++)for (j = 0; j < m && !found; j++)if (a[n] == b[m])found = 1;
if (found)/* 找到 a[i-1] == b[j-1] */...
else/* 没找到相同的元素 */...

除了这里举出的几个例外,依赖于 goto 语句的代码通常总是比没有 goto 的代码更难理解、更难维护。尽管我们不想在这个问题上说的太武断,但确实看起来 goto 应该少用,如果不是说完全不用的话。

(第三章完)

这篇关于C语言KR圣经笔记 3.6 do-while循环 3.7 break和continue 3.8 goto和标号的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/388725

相关文章

Go语言开发实现查询IP信息的MCP服务器

《Go语言开发实现查询IP信息的MCP服务器》随着MCP的快速普及和广泛应用,MCP服务器也层出不穷,本文将详细介绍如何在Go语言中使用go-mcp库来开发一个查询IP信息的MCP... 目录前言mcp-ip-geo 服务器目录结构说明查询 IP 信息功能实现工具实现工具管理查询单个 IP 信息工具的实现服

C 语言中enum枚举的定义和使用小结

《C语言中enum枚举的定义和使用小结》在C语言里,enum(枚举)是一种用户自定义的数据类型,它能够让你创建一组具名的整数常量,下面我会从定义、使用、特性等方面详细介绍enum,感兴趣的朋友一起看... 目录1、引言2、基本定义3、定义枚举变量4、自定义枚举常量的值5、枚举与switch语句结合使用6、枚

C# foreach 循环中获取索引的实现方式

《C#foreach循环中获取索引的实现方式》:本文主要介绍C#foreach循环中获取索引的实现方式,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录一、手动维护索引变量二、LINQ Select + 元组解构三、扩展方法封装索引四、使用 for 循环替代

Spring Boot循环依赖原理、解决方案与最佳实践(全解析)

《SpringBoot循环依赖原理、解决方案与最佳实践(全解析)》循环依赖指两个或多个Bean相互直接或间接引用,形成闭环依赖关系,:本文主要介绍SpringBoot循环依赖原理、解决方案与最... 目录一、循环依赖的本质与危害1.1 什么是循环依赖?1.2 核心危害二、Spring的三级缓存机制2.1 三

Go 语言中的select语句详解及工作原理

《Go语言中的select语句详解及工作原理》在Go语言中,select语句是用于处理多个通道(channel)操作的一种控制结构,它类似于switch语句,本文给大家介绍Go语言中的select语... 目录Go 语言中的 select 是做什么的基本功能语法工作原理示例示例 1:监听多个通道示例 2:带

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

C语言函数递归实际应用举例详解

《C语言函数递归实际应用举例详解》程序调用自身的编程技巧称为递归,递归做为一种算法在程序设计语言中广泛应用,:本文主要介绍C语言函数递归实际应用举例的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录前言一、递归的概念与思想二、递归的限制条件 三、递归的实际应用举例(一)求 n 的阶乘(二)顺序打印

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

C语言中的数据类型强制转换

《C语言中的数据类型强制转换》:本文主要介绍C语言中的数据类型强制转换方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C语言数据类型强制转换自动转换强制转换类型总结C语言数据类型强制转换强制类型转换:是通过类型转换运算来实现的,主要的数据类型转换分为自动转换

利用Go语言开发文件操作工具轻松处理所有文件

《利用Go语言开发文件操作工具轻松处理所有文件》在后端开发中,文件操作是一个非常常见但又容易出错的场景,本文小编要向大家介绍一个强大的Go语言文件操作工具库,它能帮你轻松处理各种文件操作场景... 目录为什么需要这个工具?核心功能详解1. 文件/目录存javascript在性检查2. 批量创建目录3. 文件