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

相关文章

C语言逗号运算符和逗号表达式的使用小结

《C语言逗号运算符和逗号表达式的使用小结》本文详细介绍了C语言中的逗号运算符和逗号表达式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习... 在C语言中逗号“,”也是一种运算符,称为逗号运算符。 其功能是把两个表达式连接其一般形式为:表达

Go语言实现桥接模式

《Go语言实现桥接模式》桥接模式是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立地变化,本文就来介绍一下了Go语言实现桥接模式,感兴趣的可以了解一下... 目录简介核心概念为什么使用桥接模式?应用场景案例分析步骤一:定义实现接口步骤二:创建具体实现类步骤三:定义抽象类步骤四:创建扩展抽象类步

GO语言实现串口简单通讯

《GO语言实现串口简单通讯》本文分享了使用Go语言进行串口通讯的实践过程,详细介绍了串口配置、数据发送与接收的代码实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 目录背景串口通讯代码代码块分解解析完整代码运行结果背景最近再学习 go 语言,在某宝用5块钱买了个

GO语言zap日志库理解和使用方法示例

《GO语言zap日志库理解和使用方法示例》Zap是一个高性能、结构化日志库,专为Go语言设计,它由Uber开源,并且在Go社区中非常受欢迎,:本文主要介绍GO语言zap日志库理解和使用方法的相关资... 目录1. zap日志库介绍2.安装zap库3.配置日志记录器3.1 Logger3.2 Sugared

Go语言中如何进行数据库查询操作

《Go语言中如何进行数据库查询操作》在Go语言中,与数据库交互通常通过使用数据库驱动来实现,Go语言支持多种数据库,如MySQL、PostgreSQL、SQLite等,每种数据库都有其对应的官方或第三... 查询函数QueryRow和Query详细对比特性QueryRowQuery返回值数量1个:*sql

GO语言中gox交叉编译的实现

《GO语言中gox交叉编译的实现》本文主要介绍了GO语言中gox交叉编译的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录一、安装二、使用三、遇到的问题1、开启CGO2、修改环境变量最近在工作中使用GO语言进行编码开发,因

从基础到高级详解Go语言中错误处理的实践指南

《从基础到高级详解Go语言中错误处理的实践指南》Go语言采用了一种独特而明确的错误处理哲学,与其他主流编程语言形成鲜明对比,本文将为大家详细介绍Go语言中错误处理详细方法,希望对大家有所帮助... 目录1 Go 错误处理哲学与核心机制1.1 错误接口设计1.2 错误与异常的区别2 错误创建与检查2.1 基础

Go语言中json操作的实现

《Go语言中json操作的实现》本文主要介绍了Go语言中的json操作的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录 一、jsOChina编程N 与 Go 类型对应关系️ 二、基本操作:编码与解码 三、结构体标签(Struc

MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决

《MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决》MyBatis默认开启一级缓存,同一事务中循环调用查询方法时会重复使用缓存数据,导致获取的序列主键值均为1,... 目录问题原因解决办法如果是存储过程总结问题myBATis有如下代码获取序列作为主键IdMappe

python语言中的常用容器(集合)示例详解

《python语言中的常用容器(集合)示例详解》Python集合是一种无序且不重复的数据容器,它可以存储任意类型的对象,包括数字、字符串、元组等,下面:本文主要介绍python语言中常用容器(集合... 目录1.核心内置容器1. 列表2. 元组3. 集合4. 冻结集合5. 字典2.collections模块