当前课程知识点:基于Linux的C++ > 第二讲 程序控制结构 > 2.6 循环结构 > LinuxCPP0206
接下来我们研究循环结构
我们首先看while循环
while循环的基本格式
就是while后面括号里面跟着一个表达式
后面跟着循环体
它的执行流程就是从一个单入口进来
做条件表达式
看条件表达式值为真或者假
如果是真 就去做循环体
做完这个循环体以后
接着去判断条件表达式
如果为假 就退出
如果为真的话 继续循环
所以对于while来讲
条件表达式首先是需要去做的
当条件为假的时候
循环体有可能一次都不做
这是非常重要的特征
我们看这样一个例子
写一个程序
然后接受用户输入的多个整数来求和
输入0的时候 整个程序就结束
看我们的程序代码
前面输出程序的功能信息
然后让用户输入一个整数
得到这个整数
判定这个整数是不是0
如果是0 我们就结束
如果非0 我们就累加
然后得下一个整数
然后再累加 然后判断
这是一个非常常见的程序结构
我们要将第一个整数先抽取出来
放到循环体的前边
对于while循环
如果它的循环体里边
没有改变循环条件的指令或者代码
那么循环条件不就永远没有办法变吗
就用刚才那个例子 while ( n != 0 )
如果你拿到的数据永远不为零
那这个while循环不就永远地不停做下去吗
如果循环体内部
没有改变循环变量的语句
或者即使改变了这个循环变量的值
也不能够否定这个循环条件
同时循环体内还没有强制终止
这个循环执行的代码或者指令
那么这样的一个循环就会陷入无限循环
没完没了的
这就是无限循环的后果
整个程序永远不会结束
(无限循环)大部分时候是有害的
但是偶尔也需要用它去做一些特别的处理
那么我们怎么样充分利用无限循环
来做程序编码呢
有些程序 除非用户产生了一个
特别的明确的要求 我要结束
否则的话循环就应该不断地做下去
那么这种循环架构
其实使用无限循环更合适
而当用户给出这个结束条件的时候
再退出
这种东西我们称为哨兵
我们可以设计一个无限循环
在循环体内部放一个哨兵
判断用户是不是要求退出
如果是 那么就退出无限循环
否则这个循环就永远地做下去
如果我们使用无限循环这个架构
那么就可以把前面的代码
做一些简单的修改
你比如讲在这里
cout 输出整个程序的功能信息
之后 while循环
里边的条件表达式永远为真
然后我们要求用户输入一个整数
得到这个整数n
然后判断 if ( n == 0 )
我们使用前面讲过的那个break关键字
放一个break语句在这里 终止循环
break 放在这里
它的目的就是停止这个循环的执行
n == 0 这个就叫哨兵
n值为0了 我们就结束
如果n不为0 我们就sum += n 累加
然后继续while循环 拿到下一个数
你注意看现在的实现
和刚才的实现有什么差别
刚才那个例子
我是把第一个数的读取操作
放到while循环体前面的
循环体内部是先累加
读取下一个
然后循环体执行下一次迭代
而现在使用了哨兵
那就不需要把数据的读取操作放在前边
第二种循环结构就是for循环
从某种程度上来讲
for循环结构的头部
实际上比while循环的头部要复杂
但是使用的时候
其实是比while循环更方便
为什么呢 因为把复杂的
控制循环逻辑的语句全放在头部了
在这里我们需要使用到的
非常重要的表达式
我们称它为递增递减表达式
这个表达式记号就是“++”或者“--”
它重要到什么程度呢
重要到C语言的后继者
就直接命名成了C++
为什么叫C++
就是因为“++”操作符在C编程里边
非常非常常见
几乎每个程序都要用到它
因为它是如此得常见
又是如此得方便
所以新的面向对象语言
干脆就叫C++算了
也不叫D语言了
“++”操作符和“--”操作符
都是一元操作符
可以放在变量的前边
也可以放在变量的后边
两者的语义是不一样的
放在前边就叫前缀递增递减
放在后边就叫后缀递增递减
你得记住计算要诀
前缀递增递减那就是先递增递减
后参与运算
比如讲如果a一开始为1 我++a
它本身等价于把a赋值为a+1
a就变成2了 这个没问题
但是你要注意到
它和其他表达式合在一起运算的时候
a为1
b = ++a * 3
那么这个前缀递增表达式
它先递增递减后参与运算
a开始为1
所以++a之后 a就会变成2
然后2乘3
结果6赋值给b
所以这就是结果
它等价于a = a + 1
然后b = a * 3
后来的a是使用递增以后的a
去参与运算的
这是前缀递增的逻辑
这个也一样 b = --a * 3
a要先递减然后才能参与运算
相反地
如果你把“++”、“--”放在后边
它就是后缀递增递减
后缀的话就是先参与运算
然后再递增递减
递增递减操作符放在前边就先算
放在后边就后算
a++它的本意仍然是a = a + 1
但是b = a++ * 3
在这种情况下
它就会把1 * 3得的结果为3
然后把3给b
然后a才能递增变成2
跟刚才不一样了吧
刚才a是递增成2以后再乘3给b的
b的结果是6 现在b的结果是3
这个就是后递增递减的意义
它和前缀递增递减肯定是不一样的嘛
“++”操作符和“--”操作符
不管是前缀还是后缀
本身的优先级都是非常高的
但是当它和其他表达式
合在一起用的时候
同学们就要特别注意
它参与运算的结果
我们特别强调
不要在复杂的表达式里边
使用递增递减操作符
因为它有可能给我们带来错误的结果
基本的架构就是for小括号对
里边由分号分割开的三个表达式
俩分号 三个表达式
第一个初始化表达式
第二个条件表达式
第三个步进表达式
这就是for循环的头部
紧跟在后边的就是它的循环体
我们这个程序怎么做呢
它就从一个单入口进来
然后去做它的初始化表达式
做完这个初始化表达式以后
它就做条件表达式
看这个条件表达式是真还是假
如果是假 那就从单出口退出了
如果是真 我们就做循环体
做完这个循环体
就去做步进表达式
做完步进表达式
继续做条件表达式
如果为假 仍然是退出
如果是为真 那我们就还继续做循环体
然后做步进表达式、条件表达式、
循环体、步进表达式
按照这个方式去循环
初始化表达式只做一次
其他是要循环的
和while循环一样
它的循环体有可能一次都不做
只要条件表达式上来就是假
就是for循环的基本架构
我们可以看这样一个例子
同学们写一个程序
接受用户输入一个整数
求1到N之间的平方和
我们写这个程序
前面的代码都跟刚才一样
输出程序的功能 得到这个数
然后写一个for循环
sum是我们得到的最后的和
n是用户输入的那个整数
i就充当循环变量
for循环初始化的时候
i应该初始化为1
从1开始平方累加
循环条件i应该小于等于n
到n就停了
n的平方本身要加进去 所以i <= n
然后我累加 i从1变成2
然后变成3 一直到n
就按照这个方式变
你看这三个表达式——
初始化表达式、条件表达式、步进表达式
很清晰地写在for循环的头部
那么循环体做什么呢
那就把i的的平方累加到sum上
因为要累加到sum上
在for循环之前sum要赋值为0
for循环和while循环本身其实是等价的
两个循环完全可以互换
这个没有问题
while循环主要用于很少需要初始化的场合
for循环的整个循环架构
非常规整
整个控制结构
全部都写在for循环的头部了
循环结构本身是很清晰的
特别说明
我们可以通过省略这个循环头部中的
一个或者多个表达式
可以把for循环搞得非常复杂
这个是可以的 你可以省略
初始化表达式可以省略 没问题
这样的话 就意味着
如果for循环真地需要初始化表达式
那么这个初始化表达式
一定要写在这个for循环的前边
步进表达式可以不要
不写就意味着如果真地需要步进
那么你必须在循环体的最后
要添上步进表达式
它在循环体之后做嘛
在条件表达式之前做嘛
条件表达式也可以不写
如果不写条件表达式
它就相当于一个无限循环
那么你的循环体内部
一定要有一个哨兵能够退出
写一个程序代码
来输出9×9的乘法表
我们打印上三角就OK
下三角不用管
上三角复杂一点 下三角更简单
我们就要想 这道题怎么做
9×9的乘法表
打印的时候就要找它的重复的模式
一个重复模式对应一个循环
我们要怎么去实现它
一行要打印9栏(除了首列的标题信息)
从1打到9
这显然是一个重复模式
打第一行、第二行、第三行、……、第九行
它也是一个重复模式
实现代码的时候
我们要做的事情第一个
我们要打印表头
“Nine by Nine Multipilication Table”
然后打印表格线
打印前边的首列 空白的地方
然后是打印它的标题行
横排的1到9的标志
用for循环
还是从1开始 i小于等于9
++i
设定它的宽度是4
我们打印它
打印完我们就换行
重新再打印一行标题线
这就完成了整个表头
再然后呢
我们就要打印表格内部
我们要一行一行地打印
打印9行
i就是行号
i从1开始i<=9;++i
对于每一行呢
要打印标题列(对应的行号)
cout << setw(2) << i
把行号打出来
接下来我写一个for循环
打印i行和对应的j列的乘积
打印在对应的j列下
我用一个for循环
打印九列
j就为列号
我们只打印它的上三角
怎么决定上三角呢
i < j 上三角
i == j 对角线
j < i 下三角区域
所以我们打印的时候
if(j < i)
我们打印四个空格
把它的空间跳过去
如果不是
我们就从对角线开始
打印上三角区
把i和j的乘积
打印到对应的位置就OK了
打印完了这一行
我要换行
这个for循环这次迭代就做完了
for循环就会去启动下一次迭代
去执行它的下一行打印
你可以看到一层for循环
里边套着一层for循环
第一层for循环打印的是每行
一行一行地去循环
第二层for循环打印的是每列
一列一列地去循环
这就是一个典型的两重循环
完成我们的9×9的乘法表的打印
为什么
你注意观察我们的数据就知道
它是一个二维表格
所以往往需要使用二维的
两重循环来处理它
简单的数据处理要两重循环
一重循环很难完全处理它
不是不可以 但会比较难
有的时候因为需要反复比较数据
或者移动或者修改数据
二维表格的数据
甚至有可能需要用三重循环去处理
所以你看到这个数据心里就会有谱
给我一个一维的数据
那么往往处理这个数据的
那个循环架构是一重循环或两重循环
如果给我一个二维的数据表(平面数据)
那么处理它的循环
往往是二重循环或者三重循环
如果是一个立体表
往往需要三重循环或者四重循环
也就是循环要么是跟维度是相等的
要么比这个维度 多一个
这是最常见的一种情况
其他的情况也有
但不太常见
-1.1 提纲
-1.2 程序设计的基本概念
-1.3 简单C/C++程序介绍
-1.4 程序设计的基本流程
-1.5 基本语法元素
-1.6 程序设计风格
-1.7 编程实践
-第一讲 C/C++基本语法元素--编程实践提交入口
-2.1 提纲
-2.2 结构化程序设计基础
-2.3 布尔数据
-2.4 分支结构
-2.5 break语句
-2.6 循环结构
-2.7 编程实践
-第二讲 程序控制结构--编程实践提交入口
-3.1 提纲
-3.2 函数声明、调用与定义
-3.3 函数调用栈框架
-3.4 编程实践
-第三讲 函数--编程实践提交入口
-4.1 提纲
-4.2 算法概念与特征
-4.3 算法描述
-4.4 算法设计与实现
-4.5 递归算法(一)
-4.6 递归算法(二)
-4.7 容错与计算复杂度
-4.8 编程实践
-第四讲 算法--编程实践提交入口
-5.1 提纲
-5.2 库与接口
-5.3 随机数库(一)
-5.4 随机数库(二)
-5.5 作用域与生存期
-5.6 典型软件开发流程(一)
-5.7 典型软件开发流程(二)
-5.8 编程实践
-第五讲 程序组织与开发方法--编程实践提交入口
-6.1 提纲
-6.2 字符
-6.3 数组(一)
-6.4 数组(二)
-6.5 结构体
-6.6 编程实践
-第六讲 复合数据类型--编程实践提交入口
-7.1 提纲
-7.2 指针基本概念
-7.3 指针与函数
-7.4 指针与复合数据类型(一)
-7.5 指针与复合数据类型(二)
-7.6 字符串
-7.7 动态存储管理(一)
-7.8 动态存储管理(二)
-7.9 引用
-7.10 编程实践
-第七讲 指针与引用--编程实践提交入口
-8.1 提纲
-8.2 数据抽象(一)
-8.3 数据抽象(二)
-8.4 链表(一)
-8.5 链表(二)
-8.6 链表(三)
-8.7 链表(四)
-8.8 函数指针(一)
-8.9 函数指针(二)
-8.10 抽象链表(一)
-8.11 抽象链表(二)
-8.12 编程实践
-第八讲 链表与程序抽象--编程实践提交入口
-9.1 提纲
-9.2 程序抽象与面向对象
-9.3 类类型
-9.4 对象(一)
-9.5 对象(二)
-9.6 类与对象的成员(一)
-9.7 类与对象的成员(二)
-9.8 类与对象的成员(三)
-9.9 继承(一)
-9.10 继承(二)
-9.11 继承(三)
-9.12 多态(一)
-9.13 多态(二)
-9.14 编程实践
-第九讲 类与对象--编程实践提交入口
-10.1 提纲
-10.2 四则运算符重载(一)
-10.3 四则运算符重载(二)
-10.4 关系与下标操作符重载
-10.5 赋值操作符重载(一)
-10.6 赋值操作符重载(二)
-10.7 赋值操作符重载(三)
-10.8 赋值操作符重载(四)
-10.9 赋值操作符重载(五)
-10.10 流操作符重载(一)
-10.11 流操作符重载(二)
-10.12 流操作符重载(三)
-10.13 操作符重载总结
-10.14 编程实践
-第十讲 操作符重载--编程实践提交入口
-11.1 提纲
-11.2 泛型编程概览
-11.3 异常处理机制(一)
-11.4 异常处理机制(二)
-11.5 运行期型式信息(一)
-11.6 运行期型式信息(二)
-11.7 模板与型式参数化
-11.8 题外话:术语翻译
-11.9 泛型编程实践(一)
-11.10 泛型编程实践(二)
-11.11 泛型编程实践(三)
-11.12 泛型编程实践(四)
-11.13 泛型编程实践(五)
-11.14 泛型编程实践(六)
-11.15 泛型编程实践(七)
-11.16 泛型编程实践(八)
-11.17 泛型编程实践(九)
-11.18 泛型编程实践(十)
-11.19 编程实践
-第十一讲 泛型编程--编程实践提交入口
-12.1 提纲
-12.2 程序执行环境(一)
-12.3 程序执行环境(二)
-12.4 程序执行环境(三)
-12.5 程序执行环境(四)
-12.6 输入输出(一)
-12.7 输入输出(二)
-12.8 文件系统
-12.9 设备
-12.10 库(一)
-12.11 库(二)
-12.12 makefile文件(一)
-12.13 makefile文件(二)
-12.14 makefile文件(三)
-12.15 编程实践
-第十二讲 Linux系统编程基础--编程实践提交入口
-13.01 提纲
-13.02 进程基本概念
-13.03 信号
-13.04 进程管理(一)
-13.05 进程管理(二)
-13.06 进程管理(三)
-13.07 进程间通信(一)
-13.08 进程间通信(二)
-13.09 进程间通信(三)
-13.10 进程间通信(四)
-13.11 进程池
-13.12 编程实践
-第十三讲 进程编程--编程实践提交入口
-14.1 提纲
-14.2 线程基本概念
-14.3 线程管理(一)
-14.4 线程管理(二)
-14.5 线程管理(三)
-14.6 线程管理(四)
-14.7 线程同步机制(一)
-14.8 线程同步机制(二)
-14.9 C++11线程库(一)
-14.10 C++11线程库(二)
-14.11 C++11线程库(三)
-14.12 C++11线程库(四)
-14.13 C++11线程库(五)
-14.14 编程实践
-第十四讲 线程编程--编程实践提交入口
-15.1 提纲
-15.2 Internet网络协议
-15.3 套接字(一)
-15.4 套接字(二)
-15.5 编程实践
-第十五讲 网络编程--编程实践提交入口