1. while语句
while (expression)
{
statement
}
- statement 可以是分号结尾的简单句,也可以是花括号括起来的复合语句
- expression 部分大多都使用关系表达式
- 如果 expression 为真(非0),执行 statement 部分一次,然后再次判断 expression
- 在 expreesion 为假(0)之前,循环的判断和执行一直重复进行
- 每次循环都被称为一次迭代(iteration)
1.1 终止 while 循环
- 在构建 while 循环时,必须让测试表达式的值有变化,表达式最终要为假
- 否则,循环将不会终止
1.2 何时终止循环
- 只有在对测试条件求值时,才决定是否终止循环
1.3 while:入口条件循环
- while 循环是使用入口条件(entry condition)的有条件循环
- 入口条件:满足条件才能进入循环体
1.4 语法要点
- 只有在测试条件后面的单独语句(简单语句或复合语句)才是循环部分
int i = 0
while (i < 3)
printf("%d", i);
i++;
// 无限循环(infinite loop)
while (i++ < 5);
printf("%d", i);
// 只会输出一次
// 测试条件后面的单独分号是空语句(null statement)
2. 用关系运算符和表达式比较大小
- while 循环经常依赖测试表达式作比较,这样的表达式被称为关系表达式(relation expression),出现在关系表达式中间的运算符叫作关系运算符(relational operator)
运算符 | 含义 |
---|---|
< | 小于 |
> | 大于 |
<= | 小于等于 |
>= | 大于等于 |
== | 等于 |
!= | 不等于 |
- 关系运算符比较字符时,比较的是机器字符码(ANSII)
- 不能用关系运算符比较字符串
2.1 什么是真
- 表达式为真的值是 1
- 表达式为假的值是 0
int i;
int j;
i = (3 > 2);
j = (3 < 2);
printf("true = %d, flase = %d\n", i, j);
// true = 1, flase = 0
2.2 其它真值
- 所有的非零值都视为真
- 只有0被视为假
int i = 5;
while (i)
{
printf("%d\n", i);
i--;
}
2.3 真值的问题
- 不要错用 ==(等于)和 =(赋值)
- 关系运算符用于构成关系表达式
- 关系表达式为真时值为1,为假时值为0
- 通常用关系表达式作为测试条件的语句(while 和 if)可以使用任何表达式作为测试条件,非0为真,0为假
2.4 新的 _Bool 类型
- C99 针对布尔变量(Boolean variable)新增了 _Bool 类型
- _Bool 类型的变量只能存储 1(真)或 0(假)
- 如果把其他非0数值赋值给 _Bool 类型的变量,该变量会被设置为1
- C99 提供了 stdbool.h 头文件,该头文件让 bool 成为 _Bool的别名,把 true 和 false 分别定义为 1 和 0 的符号常量
2.5 优先级和关系运算符
运算符(优先级从高到低) | 结合律 |
---|---|
() | 从左往右 |
-,+,++,–,sizeof | 从右往左 |
*,/,% | 从左往右 |
+,- | 从左往右 |
<,>,<=,>= | 从左往右 |
==,!= | 从左往右 |
= | 从右往左 |
3. 不确定循环和计数循环
- 不确定循环(indefinite loop):在测试表达式为假之前,预先不知道要执行多少次循环
- 计数循环(counting loop):在执行循环之前知道要重复执行多少次
4. for 循环
- for 循环将初始化、测试和更新,3个行为组合在一起
for(初始化; 测试条件; 执行更新)
{
简单句 / 复合句
}
-
初始化:只会在 for 循环开始时执行一次
-
测试条件:在执行循环之前对表达式求值;如果表达式为假,循环结束
-
执行更新:每次循环结束时求值
-
括号中的表达式也叫做控制表达式
4.1 利用 for 的灵活性
- 使用递减运算符来递减计数器
for (int i = 5; i > 0; i--)
{
printf("%d\n", i);
}
- 让计数器递增
for (int i = 2; i < 10; i += 2)
{
printf("%d\n", i);
}
- 用字符代替数字计数
for (char c = 'a'; c < 'z'; c++)
{
printf("c = %c = %d\n", c, c);
}
- 测试其他条件
for (int i = 2; i * i < 10; i++)
{
printf("%d\n", i);
}
- 递增的量成几何增长
for (int i = 2; i < 10; i *= 2)
{
printf("%d\n", i);
}
- 执行更新,使用任意合法的表达式
int j = 0;
for (int i = 2; i < 10; j = (++i) * 2)
{
printf("i = %d, j = %d\n", i, j);
}
- 省略一个或多个表达式(不能省略分号)
for (int i = 2; i < 10;)
{
printf("%d\n", i);
i++;
}
- 初始化,使用printf()
int i = 0;
for (printf("keep enter"); i != 6;)
{
scanf("%d", &i);
}
- 循环体中的行为可以改变循环头中的表达式
int j = 0;
for (int i = 1; i < 10; i = i + j)
{
j = i;
printf("i = %d, j = %d\n", i, j);
}
5. 其他赋值运算符:+=、-=、*=、/=、%=
运算符 | 含义 |
---|---|
+= | i += 1 等同于 i = i + 1 |
-= | i -= 1 等同于 i = i - 1 |
*= | i *= 1 等同于 i = i * 1 |
/= | i /= 1 等同于 i = i / 1 |
%= | i %= 1 等同于 i = i % 1 |
6. 逗号运算符
- 扩展 for 循环的灵活性,以便在循环头中包含更多的表达式
int i = 0;
int j = 0;
for (i = 1, j = 1; i <= 9; i++, j = 1)
{
while (j <= i) {
printf("%d * %d = %2d ", i, j, i * j);
j++;
}
printf("\n");
}
-
逗号运算符并不局限于在 for 循环中使用,但是这是它最常用的地方
-
逗号运算符的两个其他性质
-
保证了被它分隔的表达式从左往右求值(逗号是一个序列点,所以逗号左侧项的所有副作用都在程序执行逗号右侧项之前发生)
-
整个逗号表达式的值是右侧项的值
#include <stdio.h> int main() { int i = 0; int j = 0; i = 200, 500; printf("i = %d\n", i); // i = 200 j = (200, 500); printf("j = %d\n", j); // j = 500 }
-
7. 出口条件循环:do while
- 出口条件循环(exit-condition loop):在循环的每次迭代之后检查测试条件,保证了至少执行循环体中的内容一次
do
statement
while (expression);
- statement 可以是一条简单语句或复合语句
- do while 循环在执行完循环体后才执行测试条件,至少执行循环体一次
8. 如何选择循环
- 确定使用入口条件循环还是出口条件循环
- 入口条件循环使用次数较多
- 一般原则是在执行循环之前测试条件比较好
- 测试放在循环的开头,程序的可读性更高
- 在许多应用中,要求在一开始不满足测试条件时就直接跳过整个循环
- 当循环涉及初始化和更新变量时,用 for 循环比较合适
- 在其他情况下用 while 循环更好
9. 嵌套循环
- 嵌套循环(nested loop)指在一个循环内包含另一个循环
- 嵌套循环常用于按行和列显示数据,一个循环处理一行中的所有列,另一个循环处理所有的行
for (int i = 9; i >= 1; i--) // 外层循环(outer loop)
{
for (int j = 1; j <= i; j++) // 内层循环(inner loop)
{
printf("%d * %d = %2d ", j, i, i * j);
}
printf("\n");
}