第 4章 选择和循环结构程序设计第 4章 选择和循环结构程序设计
4.1 语句概述
4.2 关系运算符和关系表达式
4.3 逻辑运算符和逻辑表达式
4.4 选择结构的程序设计
4.5 循环结构的程序设计
4.6 程序设计第 4章 选择和循环结构程序设计
4.1 语句概述语句是程序的重要组成部分,它代表程序执行的步骤,实现着程序的意图 。 C语言属于过程式语言,在这种语言中,围绕一个程序目标所要采取的每一步行动都必须由语句一一体现出来 。 简单地说,一个程序中包含了两部分信息,一部分是数据,另一部分是对数据的操作,这些操作是由语句来实现的 。
C语言中,语句的含义也非常广泛 。 任何数据成份,只要以分号结尾,就称为语句,甚至只有一个分号也称为语句 ( 空语句 ) 。 分号是 C语言中的标志 。 一第 4章 选择和循环结构程序设计个语句可分写成多行,只要未遇到分号就认为还在同一个语句中;反之,在一行中也可以写多个语句 。 也就是说 C程序的书写是相当自由的 。 不过为了醒目起见,最好一行只写一条语句,并且根据不同的语法成份,错落有致地加以排列会更好地增加程序的可读性 。 本章我们将主要讲述选择和循环语句,这是 C语言语句中的重点 。 在学习一种语句时,要对其使用的语法规则,语义含义等深刻理解,灵活运用 。
表 4.1中先给出 C语句的全貌 。
第 4章 选择和循环结构程序设计第 4章 选择和循环结构程序设计
4.2 关系运算符和关系表达式关系运算是逻辑运算中比较简单的一种 。 所谓,关系运算,实际上是,比较运算,。 将两个值进行比较,判断其他的结果是否符合给定的条件 。 例如,a>3是一个关系表达式,大于号 ( >)
是一个关系运算符,如果 a的值为 5,则满足给定的,a>3”条件,
因此关系表达式的值为,真,( 即,条件满足,) ;如果 a的值为 2,不满足,a>3”条件,则称关系表达式的值为,假,。
4.2.1 关系运算符及其优先次序
C语言提供 6种关系运算符:
① < ( 小于 )
② <= ( 小于或等于 )
③ > ( 大于 )
④ >= ( 大于或等于 )
⑤ = = ( 等于 )
⑥! = (不等于)
第 4章 选择和循环结构程序设计关于优先次序:
( 1) 前 4种关系运算符 ( <,<=,>,>=) 的优先级别相同,后两种也相同 。 前 4种高于后 2种 。 例如,<=优先于,! =”。 而,>”与,<=”优先级相同 。
( 2) 关系运算符的优先级低于算术运算符 。
( 3) 关系运算符的优先级高于赋值运算符 。
例如:
c>a+b 等效于 c>(a+b)
a>b==c 等效于 (a>b)==c
a==b<c 等效于 a==(b<c)
a=b>c 等效于 a=(b>c)
第 4章 选择和循环结构程序设计
4.2.2 关系表达式用关系运算符将两个表达式 ( 可以是算术表达式或关系表达式,逻辑表达式,赋值表达式,字符表达式 ) 连接起来的式子,称关系表达式 。 例如,下面都是合法的关系表达式:
a>b,a+b>b+c,(a=3)>(b=5),' a' <' b',(a>b)>(b<c)
关系表达式的值是一个逻辑值,即,真,或,假,。 例如,关系表达式,5==3”的值为,假,,,5>=0”的值为,真,。 C语言以 1代表,真,,以,0”代表,假,。
例如,a=3,b=2,c=1,则:
关系表达式,a>b”的值为,真,,表达式的值为 1。
关系表达式,( a>b ) ==c”的值为,真 ( 因为 a>b的值为第 4章 选择和循环结构程序设计
1,等于 c的值),表达式的值为 1。关系表达式,b+c<a”的值为,假,,表达式的值为 0。
如果有以下赋值表达式:
d=a>b d的值为 1。
f=a>b>c f的值为 0(因为,>”运算符是自左至右的结合方向,先执行,a>b”得值为 1,再执行关系运算,1>c”,得值 0,赋给 f)。
第 4章 选择和循环结构程序设计
4.3 逻辑运算符和逻辑表达式用 逻辑运算符将关系表达式或逻辑量连接起来的式子就是逻辑表达式 。
如果 a>b且 x>y,则上述逻辑表达式的值为,真,。 下面介绍 C语言中的逻辑运算符和逻辑运算 。
4.3.1 逻辑运算符及其优先次序
C语言提供三种逻辑运算符:
( 1) && 逻辑与
( 2) || 逻辑或
( 3) ! 逻辑非第 4章 选择和循环结构程序设计
“&&”和,||”是,双目(即有两个运算对象)运算符,,如
( a>b) &&(x>y),(a<b)||(x<y)。
,!,是,一目(即运算对象只有一个)运算符,,
如 !(a>b)。
逻辑运算举例如下:
a&&b 若 a,b为真,则 a&&b为真 ( 即 a,b之一为假,则
a&&b为假 ) 。
a||b 若 a,b之一为真,则 a||b为真 ( 即 a,b都为假,
a||b为假 ) 。
!a 若 a为真,则 !a为假 ( 即 a 为假,!a为真 ) 。
在 一 个 逻辑 表达 式 中如 果 包含 多个 逻 辑运 算 符,
如 !a&&b||x>y&&c
按以下的优先次序:
第 4章 选择和循环结构程序设计
( 1) !(非) —>&&(与) —>||(或),即,!,为三者中最高的。
( 2)逻辑运算符中的,&&”和,||”低于关系运算符,,!,
高于算术运算符。
4.3.2 逻辑表达式如前所述?逻辑表达式的值应该是一个逻辑量,真,或,假,。
C语言编译系统在给出逻辑运算结果时,以数值 1代表,真,,
以 0代表,假,,但在判断一个量是否为,真,时,以 0代表
,假,,以非 0代表,真,。 即将一个非零的数值认作为
,真,。 例如:
(1)若 a=-3,则 !a的值为 0。因为 a的值为非 0,被认作,真,,
对它进行,非,运算得,假,,,假,以 0代表。
第 4章 选择和循环结构程序设计
(2)若 a=-5,b=-6,则 a&&b的值为 1。 因为 a和 b均为非 0,被认为是,真,,因此 a&&b的值民为,真,,值为 1。
(3) a,b值同前,a||b的值为 1。
(4) a,b值同前,!a||b的值为 1。
(5) -10&&0||2的值为 1。
通过这几个例子可以看出,由系统给出的逻辑运算结果不是
0就是 1,不可能是其他数值 。 而在逻辑表达式中作为参加逻辑运算的运算对象 ( 操作数 ) 可以是 0(,假,) 或任何非 0
的数值 ( 按,真,对待 ) 。 如果在一个表达式中不同位置上出现数值,应区分哪能些是作为数值或关系运算的对象,哪些作为逻辑运算的对象 。 例如:
9>3&&2||8<4-!0
表达式自左至右扫描求解 。 首先处理,5>3”( 因为关系运算符优先于 &&) 。 在关系运算符两侧的 5和 3作为数值参加关系第 4章 选择和循环结构程序设计运算,,5>3”的值为 1。再进行,1&&8<4-!0”的运算,8的左侧为,&&”,右侧为,<”运算符,根据优先规则,应先进行
,<”的运算,即先进行,8<4-!0”的运算。现在 4的左侧为
,<”,右侧为,-”运算符,而,-”优先于,<”,因此应先进行,4-!0”的运算,由于,!,的级别最高,因此先进行,!0”
的运算,得到结果 1。然后进行,4-1”的运算,得到结果 3,
再进行,8<3”的运算,得 0,最后进行,1&&0”的运算,得 0。
实际上,逻辑运算符两侧的运算对象不但可以是 0和 1,或者是 0和非 0的整数,也可以是任何类型的数据 。 可以是字符型,
实型或指针型等 。 系统最终以 0和非 0来判定它们属于,真,
或,假,。 例如:
'c'&&'d'
的值为 1( 因为 ‘ c’和 ‘ d’的 ASCII值都不为 0,按,真,处理 ) 。
逻辑运算符的结合性,除 !是右结合外?&&和 ||均为左结合?
如,!!x等于 !(!x)? a||b||c等于 (a||b)||c
第 4章 选择和循环结构程序设计程序中使用关系运算时要注意返回结果是用 0,1来表示真假值?不要用常规的数学知识去思考和理解。
【 例 4.1】
#include<stdio.h>
main()
{int i=7?m?n;
m=!!i;
n=(3<i<6);
printf(″ i=%d?m=%d?n=%d\n″?i?m?n);
return 0; }
程序运行结果为,i=7?m=1?n=1
虽然经过 !!i运算?但 i本身的值并没有改变?它返回给 m的只是个中间结果,!!i=!(!7)=!0=1?所以 m值是 1; 3<i<6即 3<7<6?从数学上看这个不等式的结果应是假的?但在 C语言中却是这样处理的:
第 4章 选择和循环结构程序设计
(3<i<6)=((3<i)<6)=(1<6)=1
事实上?在这里不论 i为何值?3<i的结果一定是 0或 1?它们都小于 6?因此最后的结果为 1?这就是 n的值 。
根据逻辑运算符 && 和 ||的功能及结合性?对逻辑表达式进行求值的时候?常用所谓,懒惰求值法,?即只要能判断出逻辑表达式的真假即停止向后进行运算,,懒惰求值法,主要指:
(1)a&&b&&c:当求得 a值为假时即停止对 b,c的求值?因为此时已可断定整个表达式为假了 ;只有当 a为真时才去求 b?只有当 a
,b全为真时才去求 c。
(2)a||b||c:当求得 a值为假时即停止对 b,c的求值?因为此时已可断定整个表达式为真了 ;只有当 a为假时才去求 b?只有当 a
,b皆假时才去求 c。
第 4章 选择和循环结构程序设计
【 例 4.2】
#include<stdio.h>
main()
{
int a?b?c;
a=b=c=1;
++a||++b&&++c;
printf(″ (1)a=%d?b=%d?c=%d\n″?a?b?c);
a=b=c=1;
++a&&++b||++c;
printf(″ (2)a=%d?b=%d?c=%d\n″?a?b?c);
a=b=c=1;
++a&&++b&&++c;
printf(″ (3)a=%d?b=%d?c=%d\n″?a?b?c);
第 4章 选择和循环结构程序设计
a=b=c=-1;
++a&&++b||++c;
printf(″( 4)a=%d?b=%d?c=%d\n″?a?b?c);
a=b=c=-1;
++a||++b&&++c;
printf(″( 5)a=%d?b=%d?c=%d\n″?a?b?c);
a=b=c=-1;
++a&&++b&&++c;
printf(″( 6)a=%d?b=%d?c=%d\n″?a?b?c);
return 0;
}
第 4章 选择和循环结构程序设计注意,输出 (4)是求 ++a&&++b||++c?++a等于 0仅说明不需要求
b就可知 ++a&&++b为假?但还不能说整个表达式为假?还必须对 ||
后面的 ++c进行运算 。
因为 ||和 &&都是严格地按从左到右的顺序进行运算的?即使它们出现在同一个表达式中也是如此?当 ||出现在 &&之前时?也不会因为 &&的优先级高而先对 &&的运算对象进行运算?因此
++a||++b&&++c等同于 ++a||(++b&&++c)?所以有 (1)和 (5)的输出结果 。
由关系运算符和逻辑运算符可以表示复杂的逻辑条件?这在程序设计中是经常用到的,比如要表示某一年份 year是否为闰年?根据天文学知识?只要符合下列条件之一即为闰年:
(1)年份 year能被 4整除?但不能被 100整除;
(2)年份 year能被 400整除 。
第 4章 选择和循环结构程序设计据此可以写出逻辑表达式,
(year%4==0&&year%100!=0)||year%400==0
根据运算符的优先级?式中的括号是可以不要的?加上是为了清晰 。 当 year为某一整数值时,如果上述表达式值为真 (1),则
year为闰年;否则 year为非闰年。
可以加一个,!,用来判别非闰年:
!((year%4==0&&year%100!=0)||year%400==0)
若表达式值为真 (1),year为非闰年 。 也可以用下面逻辑表达式判别非闰年:
(year%4!=0)||(year%100==0&&year%400!=0)
若表达式值为真?year为非闰年 。 请注意表达式中右面的括弧内的不同运算符 (%?!=?&&?==)的运算优先次序 。
第 4章 选择和循环结构程序设计
4.4 选择结构的程序设计
C语言中用条件语句来设计选择结构的程序。条件语句有两个:
双分支的 if语句和多分支的 switch语句。根据不同情况,恰当地使用它们,可以提高编程效率
4.4.1 if语句
if语句是用来判定所给定的条件是否满足,根据判定的结果
( 真或假 ) 决定执行给出的两种操作之一 。 C语言提供了三种形式的 if语句:
1,if(表达式 ) 语句例如:
if(a<b) printf(″% d″?a);
这种 if语句的执行过程是:若表达式的值为真 (非 0),则执行语句 ;若表达式为假 (0),则不执行语句,继续后面语句的执行 。
第 4章 选择和循环结构程序设计
2,if(表达式 ) 语句 1 else 语句 2
例如:
if(a<b) printf(″% d″?a);
else printf(″% d″?b);
这种 if语句的执行是:若表达式的值为真 (非 0),则执行语句
1;否则 (即表达式值为 0)执行语句 2。
3,if(表达式 1) 语句 1
else if(表达式 2) 语句 2
else if(表达式 3) 语句 3
else if(表达式 m) 语句 m
else 语句 n
该 if语句的执行过程是:若表达式 1的值为真 (非 0)?则执行语句 1;否则,若表达式 2的值为真 (非 0),则执行语句 2 ;否则第 4章 选择和循环结构程序设计
,若表达式 3的值为真 (非 0),则执行语句 3; …… ;否则,若表达式 m值为真 (非 0),则执行语句 m;否则,执行语句 n。
例如,if (number>500) cost=0.15;
else if(number>300) cost=0.10;
else if(number>100) cost=0.075;
else if(number>50) cost=0.5;
else cost=0;
说明:
(1)三种形式的 if语句中在 if后面都有,表达式,,一般为逻辑表达式或关系表达式 。 例如,if(a==b&&x==y)
printf(″ a=b?x=y″ ) ;在执行 if语句时先对表达式求解,若表达式值为 0,按,假,处理,若表达式的值非 0,按,真,处理,
执行指定的语句 。
第 4章 选择和循环结构程序设计假如有以下 if语句:
if(10) printf(″Just good″) ;
是合法的,执行结果输出,Just good”,因为表达式的值为 10,
按,真,处理 。 由此可见,表达式的类型不限于逻辑表达式,可以是任意的数据类型 ( 包括整型,实型,字符型,指针型数据 )
。 例如,下面的 if语句也是合法的:
if('a') printf(″% d″?'a') ;
执行结果:输出 'a'的 ASCII码 97。
(2)第二,第三种形式的 if语句中,在每个 else前面有一分号,
整个语句结束处有一分号 。 例如:
if(x==0)
第 4章 选择和循环结构程序设计
printf(″ The result is wrong″ );
else printf(″ The result is right″ );
这是由于分号是 C语句中不可缺少的部分,这个分号是 if语句中的内嵌语句所要求的 。 如果无此分号,则出现语法错误 。 但应该注意,不要误认为上面是两个语句 (if语句和 else语句 )。 它们都属于同一个 if语句 。 else子句不能作为语句单独使用,它必须是 if语句的一部分,与 if配对使用 。
(3)在 if和 else后面可以只含一个内嵌的操作语句 (如上例 ),
也可以有多个操作语句,此时用花括号,{}”将几个语句括起来成为一个复合语句 。 如:
if(a+b>c&&b+c>a&&c+a>b)
{s=0.5*(a+b+c); area=sqrt(s*(s-a)*(s-b)*(s-c));
printf(″ area=%6.2f\n″?area); }
else printf(″ it is not a trilateral\n″ );
注意在第 3行的花括号,}”外面不需要再加分号 。 因为 {}内是一个完整的复合语句,不需另附加分号 。
第 4章 选择和循环结构程序设计
【 例 4.3】 输入两个实数,按代数值由大到小的次序输出这两个数 。
这个问题很简单,只需要作一次比较即可 。
程序如下:
#include<stdio.h>
main()
{
float a?b?t;
scanf(″% f?%f″?&a?&b);
if(a<b)
{t=a; a=b; b=t; }
printf(″% 5.2f?%5.2\n″?a?b);
return 0; }
程序运行情况如下:
5.6?-7.8↙
-7.80,5.60
第 4章 选择和循环结构程序设计
【 例 4.4】 输入 3个数 a?b?c,要求按由小到大的顺序输出 。
解此题比上一题复杂一些 。 方法上还是类似,只需认准排序之后,a是三者中最小的,c是最大的,即可 。 具体步骤如下:
如果 a>b 则将 a和 b对换 (a是 a?b中的小者 )
如果 a>c 则将 a和 c对换 (a是 a?c中的小者,因此 a是三者中最小者 )
如果 b>c 则将 b和 c对换 (b是 b?c中的小者,也是三者中的次小者 )
然后顺序输出 a?b?c即可 。
因此程序如下:
#include<stdio.h>
main()
{float a?b?c?t;
scanf(″% f?%f?%f″?&a?&b?&c);
if(a>b)
{t=a; a=b; b=t; }/*实现 a和 b的互换 */
第 4章 选择和循环结构程序设计
if(a>c)
{t=a; a=c; c=t; } /*实现 a和 c的互换 */
if(b>c)
{t=b; b=c; c=t; } /*实现 b和 c的互换 */
printf(″% 5.2f?%5.2f?%5.2f\n″?a?b?c);
return 0;
}
程序运行情况如下:
9?8?7↙
7.00?8.00?9.00
4,if语句的嵌套在 if语句中又包含一个或多个 if语句称为 if语句的嵌套 。 一般形式如下:
if(表达式 1)
if(表达式 2) 语句 1
else 语句 2
第 4章 选择和循环结构程序设计
else if(表达式 3) 语句 3
else 语句 4
应当注意 if与 else的配对关系。 else总是与它前面最近的可见的未配对的 if进行配对使用。假如写成:
if(表达式 1)
if(表达式 2) 语句 1
else if(表达式 3) 语句 2
else 语句 3
编写者把 else写在与第一个 if(外层 if)同一列上,希望 else与第一个 if对应,但实际上 else是与第二个 if配对,因为它们相距最近 。 因此最好使内嵌 if语句也包含 else部分 (如嵌套的前一种形式 ),这样 if的数目和 else的数目相同,从内层到外层一一对应
,不致出错 。
第 4章 选择和循环结构程序设计如果 if与 else的数目不一样,为实现程序设计的企图,可以加花括弧来确定配对关系,使它们不可见 。 例如:
if(表达式 1)
{if(表达式 2) 语句 1} (内嵌 if,相对于下面的 else不可见 )
else 语句 2
这时 {}限定了内嵌 if语句的范围,因此 else与第一个 if配对

【 例 4.5】 有一函数:
2x-1 (x<0)
y= 0 (x=0)
2x+1 (x>0)
编写一程序,输入一个 x值,输出 y值 。
分析如下:
输入 x
第 4章 选择和循环结构程序设计若 x<0 y=2x-1
若 x=0 y=0
若 x>0 y=2x+1
输出 y
或:
输入 x
若 x<0 y=2x-1
否则:
若 x=0 y=0
若 x>0 y=2x+1
输出 y
有以下几个程序,请读者判断哪个是正确的?
程序 1:
main()
{
int x?y;
第 4章 选择和循环结构程序设计
scanf(″% d″?&x);
if(x<0) y=2*x-1;
else if(x==0) y=0;
else y=2*x+1;
printf(″ x=%d?y=%d\n″?x?y);
return 0; }
程序 2:将上面程序的 if语句 ( 第 4~6行 )改为:
if(x>=0)
if(x>0) y=2*x+1;
else y=0;
else y=2*x-1;
程序 3:将上述 if语句改为:
y=-1;
if(x!=0)
if(x>0) y=2*x+1;
else y=0;
第 4章 选择和循环结构程序设计程序 4:
y=0;
if(x>=0)
if(x>0) y=2*x+1;
else y=2*x-1;
只有程序 1和程序 2是正确的 。 程序 3和程序 4不能实现题目的要求 。 请注意程序中的 else与 if的配对关系 。 程序 3中的 else子句是和它上一行的内嵌的 if语句配对,而不与第 2行的 if语句配对
。 程序 3是当 x不等于 0且 x小于 0时,y等于 0,这显然不符题目要求 。 要纠正只需在第个 if语句上加一个花括号即可 。
为了使逻辑关系清晰,避免出错,一般把内嵌的 if语句放在外层的 else子句中 (如程序 1那样 ),这样由于有外层的 else相隔,
内嵌的 else不会被误认为和外层的 if配对,而只能与内嵌的 if配对,这样就不会搞混,如像程序 3和程序 4那样写就很容易出错。
第 4章 选择和循环结构程序设计
【 例 4.6】 写程序,判断某一年是否闰年 。
在上一节已经介绍闰年的类别方法,据此编写程序如下:
#include<stdio.h>
main()
{
int year,leap;
scanf(″% d″,&year);
if(year%4==0)
{
if(year%100==0)
{if(year%400==0)
leap=1;
else leap=0;
}
else
leap=1;
第 4章 选择和循环结构程序设计
}
else
leap=0;
if(leap)
printf(″% d is″,year);
else
printf(″% d is not ″,year);
printf(″ a leap year.\n″ );
return 0;
}
5,if语句中条件表达式的灵活设置因为 C语言中是用非 0和 0来表示真假的,所以条件的表示可以有多种情况,
(1)用一个数值表示条件 。 如:
int m;
第 4章 选择和循环结构程序设计
scanf(″%d″?&m);
if(!m) printf(″Yes″) ;
其中 if(!m)等价于 if(m==0)。再有:
int m;
scanf(″%d″?&m);
if(m!=0) printf(″Yes″) ;
其中 if(m!=0)等价于 if(m)。
(2)将赋值运算和条件判断结合起来。如:
char ch;
if((ch=getchar())!='\n') putchar(ch);
这里先调用 getchar函数,输入一个字符,赋给 ch?再判断 ch是否为回车符,若不是回车符则将其输出 。
第 4章 选择和循环结构程序设计
(3)用函数调用作为条件。如:
if(printf(″*″)) printf(″it is a symbal \n″) ;
(4)用复合的逻辑表达式表示条件 。 如:
if(score>70&&score<80) printf(″ B″ );
此时常犯的错误是写成数学中的不等式形式:
if(70<score<80)
数学中的式子要经过适当改造才能用于 C程序中,不能直接照搬

4.4.2 条件运算符若 if语句中,在表达式为,真,和,假,时,且都只执行一个赋值语句给同一个变量赋值时,可以用简单的条件运算符来处理。
例如,若有以下 if语句:
第 4章 选择和循环结构程序设计
if(a>b) max=a;
else max=b;
可以下面的条件运算符来处理:
max=(a>b)?a:b;
其中,(a>b)?a:b”是一个,条件表达式,。 它是这样执行的:
如果 (a>b)条件为真,则条件表达式取值 a,否则取值 b。
条件运算符,?,,是 C语言中唯一的一个三目运算符?也即它有三个运算对象,分别由,?”和,,,把它们连接起来,构成一个条件表达式 。 条件表达式的一般形式为:
表达式 1? 表达式 2,表达式 3
说明:
( 1) 条件运算符的执行顺序:先求解表达式 1,若为非 0( 真
) 则求解表达式 2,此时表达式 2的值就作为整个条件表达式的值
。 若表达式 1的值为 0( 假 ),则求解表达式 3,表达式 3的值就是整个条件表达式的值 。
max=(a>b)? a:b;
第 4章 选择和循环结构程序设计执行结果就是将条件表达式的值赋给 max。也就是将 a和 b二者中大者赋给 max。
( 2)条件运算符优先于赋值运算符,因此上面赋值表达式的求解过程是先求解条件表达式,再将它的值赋给 max。
条件运算符的优先级别比关系运算符和算术符都低。因此
max=(a>b)?a:b
括号可以不要,可写成
max=a>b?a:b
如果有
a>b?a:b+1
相当于 a>b?a:(b+1),而不相当于 (a>b?a:b)+1。
第 4章 选择和循环结构程序设计
( 3)条件运算符的结合方向为,自右至左,。如果有以下条件表达式:
a>b? a:c>d? c:d
如果 a=1,b=2,c=3,d=4?则条件表达式的值等于 4。
( 4)条件表达式还可以写成以下形式:
a>b?(a=100):(b=100);

a>b?printf("%d",a):printf("%d",b);
即,表达式 2”和,表达式 3”不仅可以是数值表达式,还可以是赋值表达式或函数表达式 。 上面第二个条件表达式相当于以下 if-
else语句:
第 4章 选择和循环结构程序设计
if(a>b) printf("%d",a);
else printf("%d",b);
( 5) 条件表达式中,表达式 1的类型可以与表达式 2和表达式
3的类型不同 。 如
x?'a':'b'
x是整型变量,若 x等于 0,则条件表达式的值为 'b'。 表达式 2
和表达式 3的类型也可以不同,此时条件表达式的值的类型为二者中较高的类型 。 如
x>y?1:1.5
如果 x?则条件表达式的值为 1.5,若 x>y?值应为 1,由于 1.5是实型,比整型高,因此,将 1转换成实型值 1.0 。
【 例 4.7】 输入一个字符?判别它是否大写字母?如果是?将它转换成小写字母 ;如果不是?不转换,然后输出最后得到的字符

第 4章 选择和循环结构程序设计因为大小写字母之间的 ASCII值相差 32?因此大小写字母之间的转换是,将小写转换成大写?只要将小写字母减 32即可 ;将大写转换成小写?只需将该大写字母加 32即可 。
可直接编写程序:
#include<stdio.h>
main()
{
char ch;
scanf("%c"?&ch);
ch=(ch>='A'&&ch<='Z')?(ch+32):ch;
printf("%c"?ch);
return 0;
}
程序运行结果如下:
A↙
a
第 4章 选择和循环结构程序设计
【 4.8】 猜数游戏 。 程序预置一个常数 ( 称为幻数 ),让用户猜测,猜对时给出正确信息,否则会给出是大了还是小了的提示 。
#include<stdio.h>
main()
{
int magic=618,guess;
printf("input your guess:\n");
scanf("%d",&guess);
if(guess!=magic)
guess>magic?printf("High"):printf("Low");
else
{
printf("***right***\n");
printf("%d is the magic number.\n",magic);
}
return 0;
}
第 4章 选择和循环结构程序设计
4.4.3 switch语句
switch语句是多分支选择语句 。 if语句只有两个分支可供选择
,而实际问题中常常需要用到多分支的选择 。 例如,学生成绩分类 ( 85分以上为 'A'等,70~84分为 'B'等,60~69分为 'C'等 ……
) ;人口统计分类 ( 按年龄分为老,中,青,少,儿童 ) ;工资统计分类;银行存款分类 …… 。
当然这些都可以用嵌套的 if语句来处理,但如果分支较多,则嵌套的 if语句层数多,程序冗长而且可读性降低 。 C语言提供
switch语句直接处理多分支选择,它的一般形式如下:
switch(表达式 )
{
case 常量表达式 1:语句 1
case 常量表达式 2:语句 2
… … …
case 常量表达式 n:语句 n
default:语句 n+1
}
第 4章 选择和循环结构程序设计例如?要求按照考试成绩的等级打印出百分制分数段,可以用
switch语句实现:
switch(grade)
{ case 'A':printf("85~100\n");
case 'B':printf("70~84\n");
case 'C':printf("60~69\n");
case 'D':printf("<60\n");
default:printf("error\n");
}
说明:
(1)switch后面括弧内的,表达式,,ANSI标准允许经为任何类型 。
(2)当表达式的值与某一个 case后面的常量表达式的值相等时,
就执行此 case后面的语句,若所有的 case中的常量表达式的值都没有与表达式的值匹配的,就执行 default后面的语句 。
第 4章 选择和循环结构程序设计
(3)每一个 case的常量表达式的值必须不相同,否则就会出现互相矛盾的现象 (对表达式的同一个值,有两种或多种执行方案 )。
(4)各个 case和 default的出现次序不影响执行结果 。 例如,可以先出现,default:…,,再出现,case ′ D′,…,,然后是
,case ′ A′ …,。
(5)执行完一个 case后面的语句后,流程控制转移到下一个
case继续执行 。,case常量表达式,只是起语句标号作用,并不是在该处进行条件判断 。 在执行 switch语句时,根据 switch后面表达式的值找到匹配的入口标号,就从此标号开始执行下去,不再进行判断 。 例如,上面的例子中,若 grade的值等于 ′ A′,则将连续输出:
85~100
70~84
60~69
<60
error
第 4章 选择和循环结构程序设计因此,应该在执行一个 case分支后,使流程跳出 switch结构,
即终止 switch语句的执行 。 可以用一个 break语句来达到此目的 。
将上面的 switch结构改写如下:
switch(grade)
{ case 'A':printf("85~100\n");break;
case 'B':printf("70~84\n");break;
case 'C':printf("60~69\n");break;
case 'D':printf("<60\n");break;
default:printf("error\n");
}
最后一个分支 (default)可以不加 break语句 。 如果 grade的值为 ‘ B’,则只输出,70~84”。
在 case后面虽然包含了一个以上执行语句,但可以不必用花括弧括起来,会自动顺序执行本 case后面所有的执行语句。当然加上花括号也可以。
第 4章 选择和循环结构程序设计
(6)多个 case可以共用一组执行语句 。
【 例 4.9】 用 switch语句输出学生的分数等级 。 高分数小于等于 90分者为 A等,70分 ~90分为 B等 (含 70),60分 ~70分为 C(含 60)
,60分以下为 D等,分数为浮点数 。
编程思路,switch后的表达式必须是有序类型而且求出的结果应当是一个个离散的值,而不是一个数值范围 。 应该想办法把一个范围转换成一个确定的值,这是使用 switch语句的关键 。 在这里我们可以把分数除以 10再取整,即可变成离散的数值,就可以用 switch语句解决了 。
#include<stdio.h>
main()
{ int i;
float score;
printf(″ input a score\n″ );
scanf(″% f″,&score);
i=(int)score/10;
第 4章 选择和循环结构程序设计
switch(i)
{
case 9:
case 10,printf(″ A″ ); break;
case 7:
case 8,printf(″ B″ ); break;
case 6,printf(″ C″ ); break;
default,printf(″ D″ ); break;
}
return 0;
}
第 4章 选择和循环结构程序设计输入的分数是实数,但通过赋值语句就变成了整型,整型是有序类型,并且 i具有有限的离散值。 printf(″D″) 语句后面可以不要 break,但如果把其他地方的 break全去掉,则当输入分数 95.9时,会连续地输出 ABCD。因此一定要注意 break
的使用。
【 例 4.10】 运输公司对用户计算运费。路程 (s)越远,每公里运费越低。标准如下:
s<250km 没有折扣
250≤s< 500 2%折扣
500≤s< 1000 5%折扣
1000≤s< 2000 8%折扣
2000≤s< 3000 10%折扣
3000≤s 15%折扣第 4章 选择和循环结构程序设计设每公里每吨货物的基本运费为 p(price的缩写 ),货物重为
w(weight的缩写 ),距离为 s,折扣为 d(discount的缩写 ),则总运费 f(freight的缩写 )的计算公式为
f=p*w*s*(1-d)
分析此问题,折扣的变化是有规律的:折扣的,变化点,都是
250的倍数 (250,500,1000,2000,3000)。利用这一特点,可以设一变量 c代表 250的倍数,也即 c的值为 s/250,所以当 c<1时
,表示 s<250,无折扣; 1≤c< 2时,表示 250≤s< 500,折扣 d=2%; 2≤c< 4时,d=5%; 4≤c< 8时,d=8%; 8≤c< 12时,d=10%;
c≥ 12时,d=15%。
据此写出程序如下:
#include<stdio.h>
main()
第 4章 选择和循环结构程序设计
{
int c,s;
float p,w,d,f;
scanf(″% f,%f,%f″,&p,&w,&s);
if(s>=3000) c=12;
else c=(int)s/250;
switch(c)
{
case 0,d=0.0; break;
case 1,d=0.02; break;
case 2:
case 3,d=0.05; break;
case 4:
case 5:
case 6:
case 7,d=0.08; break;
第 4章 选择和循环结构程序设计
case 8:
case 9:
case 10:
case 11,d=0.1; break;
case 12,d=0.15; break;
}
f=p*w*s*d
printf(″ feight=%12.4f\n″,f);
return 0;
}
第 4章 选择和循环结构程序设计程序运行情况如下:
20,100,1002↙
801600.0000
请注意,c,s是整型变量,因此 c=s/250为整数。当 s≥ 3000时
,令 c=12,而不使 c随 s增大,这是为了在 switch语句中便于处理,用一个 case可以处理所有 s≥ 3000的情况。
第 4章 选择和循环结构程序设计
4.5 循环结构的程序设计到目前为止我们所遇到的程序都是简单程序,解决的问题都很简单。要解决复杂问题,并充分发挥计算机快速的优势,那么程序中很可能要用到循环语句。其实在许多问题需都要用到循环控制。
例如,要输入全校学生成绩;求若干个数之和;迭代求根等。几乎所有实用的程序都包含循环。循环结构是结构化程序设计的基本结构之一,它和顺序结构、选择结构共同作为各种复杂程序的基本构造单元。因此熟练掌握选择结构和循环结构和循环结构的概念及使用是程序设计的最基本的要求。 C语言提供了三种循环语句,for语句,while语句,do_while语句。下面分别加以讨论
4.5.1 while语句
while语句的基本形式为:
while(<表达式 >)
<语句 >
第 4章 选择和循环结构程序设计含义是:首先计算表达式的值,只要为真就执行循环体语句,直到表达式求值为假,然后退出循环。在循环体中,一定要对循环控制变量进行修改。其特点是:先判断表达式,后执行语句。
【 例 4.11】 求 1~100之间所有偶数之和 。
#include<stdio.h>
main()
{ int sum,i;
sum=0; i=2;
while(i<=100)
{sum=sum+i;
i+=2; }
printf(″ sum=%d\n″,sum);
return 0;
}
程序运行输出:
sum=2550
第 4章 选择和循环结构程序设计需要注意:
(1)循环体如果包含一个以上的语句,应该用花括弧括起来,
以复合语句形式出现 。 如果不加花括弧,则 while语句的范围只到 while后面第一个分号处 。 例如,本例中 while语句中如无花括号弧,则 while语句范围只到,sum=sum+i;,。
(2)在循环中应有使循环趋向于结束的语句 。 例如,在本例中循环结束的条件是,i>100”,因此在循环体中应该有使 i增值以最终导致 i>100的语句,今用,i++;,语句来达到此目的 。 如果无此语句,则 i的值始终不改变,循环永不结束 。
while语句多用在循环次数预先难以确定的循环中,如下例所示 。
【 例 4.12】 输入并输出一个字符,遇,#”结束 。
#include<stdo.h>
main()
{
char c;
第 4章 选择和循环结构程序设计
while((c=getchar())!=′#′)
putchar(c);
return 0;
}
程序运行时输入:
This is a string #↙
则输出为:
This is a string
程序在执行时并不是输入一个字符后立即把它送到屏幕,而是先放入内存缓冲区中,只有在打了回车符之后才把缓冲区里的内容一块输出。
第 4章 选择和循环结构程序设计
【 例 4.13】 爱因斯坦阶阶梯问题 。 设有阶梯,不知其除数,但知:
每步跨两阶最后剩 1阶;每步跨 3阶最后剩 2阶;每步跨 5阶最后剩
4阶;每步跨 6阶最后剩 5阶;每步跨 7阶正好到楼顶,求共有多少阶 。
编程思路:本题拟采用穷举法求解:从整数 1试起,一旦发现某个整数符合所有条件限制,就算找到了答案 。 这样逐次加 1地测试,虽然是可以的,但这未免也太机械了,我们可以根据条件,
找出一个相对快捷的算法 。
设阶数为 n,根据所给的条件有下列关系:
① n%2=1
② n%3=2
③ n%5=4
④ n%6=5
⑤ n%7=0
由 ⑤ 可知,阶梯数一定是 7倍数,所以测试的初值可以从 7开始并且在 7的倍数 14,21,28,35,…… 中测试 。
第 4章 选择和循环结构程序设计由①知,阶梯数一定是奇数,则进一步简化测试范围在 7,21,
35,…… 之中,这个数列的公差为 14。对这个数列中的数值再用
②、③、④式中的条件去检测,对②、③、④式全符合的数即为所求。
根据上面的分析,可编程如下:
#include<stdio.h>
main()
{ int n=7;
while(n%3!=2||n%5!=4||n%6!=5)
n+=14;
printf(″ Total=%d\n″,n);
return 0; }
第 4章 选择和循环结构程序设计程序执行输出如下:
Total=119
注意,while语句中表达式的写法,||是或运算符,表示只要有一个等式不成立,表达式就为真,就执行循环体,直到三个等式全成立为止。
【 例 4.14】 求两个正整数 a,b的最大公约数 GCD(Greatest
Common Divisor)。
分析:求最大公约用的是辗转相除法 。 即要使 a除以 b的余数等于 0为止,若不等于 0,则把余数作除数,除数作被除数,继续求余数,直到余数等于 0,那么此时的除数为所求 。 因此写出程序如下:
#include<stdio.h>
main()
第 4章 选择和循环结构程序设计
{
int a,b,t;
printf(″input 2 integers:\n″) ;
scanf(″%d%d″,&a,&b) ;
if(a<b)
{t=a; a=b; b=t; } /*要使被除数比除数大 */
while(b)
{
t=a%b;
a=b;
第 4章 选择和循环结构程序设计
b=t;
}
printf(″ The GCD=%d\n″,a);
return 0;
}
程序中 while(b)等价于 while(b!=0)。
【 例 4.16】 译密码 。 为使电文保密,往往按一定规律将其转换成密码,收报人再按定的规律将其译回原文 。 例如,可以按以下规律将电文变成密码:
将字母 A变成字母 E,a变成 e,即变成其后的第 4个字母,W变成 A,X变成 B,Y变成 C,Z变成 D。 字母殷实上述规律转换,非字母字符不变 。 如,China!”转换为,Glmre!”。 输入一行字符
,要求输出其相应的密码 。
程序如下:
#include<stdio.h>
第 4章 选择和循环结构程序设计
main()
{ char c;
while((c=getchar())!=′ \n′ );
{
if((c>=′ a′ &&c<=′ z′ )||(c>=′ A′ &&c<=′ Z′ ))
{ c=c+4;
if(c>′ Z′ &&c<=′ Z′ +4||c>′ z′ )) c=c-26;
}
printf(″% c″,c);
}
return 0;
}
程序运行结果如下:
China! ↙
Glmre!
第 4章 选择和循环结构程序设计
4.5.2 do_while语句
do_while语句的特点是先执行循环体,然后判断循环条件是否成立 。 其一般形式为
do
循环体语句
while(表达式 );
它是这样执行的:进入 do_while循环后,首先执行一次循环体,然后再测试表达式,如其为真则继续执行循环体,直至表达式求值为假 。
do_while语句与 while语句的差别仅仅在于,while语句是条件判断在前,循环体执行在后,如一开始就不满足条件,则循环体一次也不执行;而 do_while语句是先执行循环体,后判断条件,所以它至少执行循环一次 。
第 4章 选择和循环结构程序设计
【 例 4.17】 用 do_while语句求 。
程序如下:
#include<stdio.h>
main()
{
int i,sum=0;
i=1;
do
{sum=sum+i;
i++;
}
while(i<=100);
printf(″% d\n″,sum);
return 0;
}
100
1n
n
第 4章 选择和循环结构程序设计可以看到,对同一个问题可以用 while语句处理,也可以用
do_while语句处理。在一般情况下,用 while语句和用
do_while语句处理同一问题时,若二者的循环体部分是一样的,它们的结果也一样。如例 4-17换成用 while语句循环体是相同的,得到结果也相同。但如果 while后面的表达式一开始就为假 (0值 )时,两种循环的结果是不同的。
现在我们来观察前面的输入字符串的例子,用 do_while实现语句的结果:
#include<stdio.h>
main()
{
char c;
do
第 4章 选择和循环结构程序设计
{
c=getchar();
putchar(c);
}while(c!=′#′) ;
return 0;
}
程序运行,输入字符串,this is a string#↙
则输出为,This is a string#
【 例 4.18】 输入一个正整数,然后按反向输出。比如输入 23456
,则输出为 65432。
第 4章 选择和循环结构程序设计编程思路:输入时一次把一个整数完整地输入,而输出则是一次一个数字输出,并且要求把最低位先输出,所以首先应该把最低位数字分离出来输出,然后再分离出下一个最低位数字 ……,
怎样才能把最低位分离出来呢? 可用对 10求模的方法 。 然后用对
10求商的方法求出除掉最低位后的数,作为进一步倒置输出的基数 。
#include<stdio.h>
main()
{
int number,digit;
printf(″ inpu an integer\n″ );
scanf(″% d″,&number);
do
{ digit=number%10;
printf(″%d″,digit) ;
第 4章 选择和循环结构程序设计
number/=10
}while(number);
printf(″ \n″ );
return 0;
}
程序运行输出:
input an integer
23456↙
65432
4.5.3 for语句
C语言中的 for语句使用最为灵活,不仅可以用于循环次数已经确定的情况,而且可以用于循环次数不确定而只给出循环结束条件的情况,它完全可以代替 while语句。
第 4章 选择和循环结构程序设计
for语句的一般形式为:
for(表达式 1;表达式 2;表达式 3) 循环体它的执行过程如下:
(1) 先求解表达式 1。
(2) 求解表达式 2,若其值为真 (值为非 0),则执行 for循环体中指定的内嵌语句,然后执行下面第 (3)步 。 若为假 (值为 0),则结束循环,转到第 (5)步 。
(3) 求解表达式 3。
(4) 转回上面第 (2)步骤继续执行 。
(5) 循环结束,执行 for语句下面的一个语句 。
for语句最简单的应用形式也就是最易理解的如下形式:
for(循环变量赋初值;循环条件;循环变量增值 ) 语句例如:
for(i=1; i<=100; i++) sum=sum+i;
可以看到它相当于以下语句:
第 4章 选择和循环结构程序设计
i=1;
While(i<=100)
{
sum=sum+i;
i++;
}
显然,用 for语句简单,方便 。 对于以上 for语句的一般形式可以改写为 while循环的形式:
表达式 1;
while(表达式 2)
{
语句表达式 3;
}
说明:
第 4章 选择和循环结构程序设计
(1)for语句的一般形式中的,表达式 1”可以省略,此时应在 for
语句之前给循环量赋初值。注意省略表达式 1时,其后的分号不能省略。如 for(; i<=100; i++)sum=sum+i;执行时,跳过,求解表达式 1”这一步,其他不变。
(2)如果表达式 2省略,即不判断循环条件,循环无终止地进行下去 。 也就是认为表达式 2始终为真 。
例如:
for(i=1;; i++) sum=sum+i;
表达式 1是一个赋值表达式,表达式 2空缺 。 它相当于:
i=1;
while(1)
{sum=sum+i;
i++; }
第 4章 选择和循环结构程序设计
(3)表达式 3也可以省略,但此时程序设计者应另外设法保证循环能正常结束 。 如:
for(i=1; i<=100; )
{
sum=sum+i;
i++;
}
在上面的 for语句中只有表达式 1和表达式 2,而没有表达式 3。
i++的操作不放在 for语句的表达式 3的位置处,而作为循环体的一部分,效果是一样的,都能使循环正常结束 。
(4)可以省略表达式 1和表达式 3,只有表达式 2,即只给循环条件 。 如:
for(; i<=100; ) while(i<=100)
{ sum=sum+i 相当于 {sum=sum+i;
i++; } i++; }
第 4章 选择和循环结构程序设计在这种情况下,完全等同于 while语句。可见 for语句比 while
语句功能强,除了可以给出循环条件外,还可以赋初值,使循环变量自动增值等 。
(5)3个表达式都可以省略,如:
for(;; ) 语句相当于
while(1) 语句即不设初值,不判断条件 (认为表达式 2为真值 ),循环变量不增值 。 无终止地执行循环体 。
(6)表达式 1可以是设置循环变量初值的赋值表达式,也可以是与循环变量无关的其他表达式 。 如:
for(sum=0; i<=100; i++) sum=sum+i;
表达式 3也可以是与循环控制无关的任意表达式 。
表达式 1和表达式 3可以是一个简单的表达式,也可以是逗号表达式,即包含一个以上的简单表达式,中间用逗号间隔 。 如:
第 4章 选择和循环结构程序设计
for(sum=0,i=1; i<=100; i++) sum=sum+i;

for(sum=0,i=1; i<=100; sum=sum+i,i++) ;
表达式 1和表达式 3都是逗号表达式,各包含两个赋值表达式,
即同时设两个初值,使两个变量增值 。
在逗号表达式内按自左至右顺序求解,整个逗号表达式的值为其中最右边的表达式的值。如:
for(i=1; i<=100; i++,i++) sum=sum+i;
(7)表达式 2一般是关系表达式 (如 i<=100)或逻辑表达式 (如
a<b&&x<y),但也可以是数值表达式或字符表达式,只要其值为非零,就执行循环体 。 分析下面两个例子:
① for(i=0; (c=getchar())!=′ \n′ ; i+=c);
在表达式 2中先从终端接收一个字符赋给 c,然后判断此赋值表达式的值是否不等于 ′ \n′ (换行符 ),如果不等于 ′ \n′,就执行循环体 。 此 for语句的作用是不断输入字符,将它们的 ASCII
码相加,直到输入一个,换行,符为止 。
第 4章 选择和循环结构程序设计
② for(; (c=getchar())!=′ \n′ ; )
printf(″%c″,c) ;
只有表达式 2,而无表达式 1和表达式 3。其作用是每读入一个字符后立即输出字符,直到输入一个,换行,符为止。请注意,从终端键盘向计算机输入时,是在按 Enter键以后才送到内存缓冲区中去的。程序运行情况:
Computer↙ ( 输入 )
Computer (输出 )
从上面介绍可以知道 C语言中的 for语句功能强大,可以把循环体和一些与循环控制无关的操作也作为表达式 1或表达式 3
出现,这样程序可以短小简洁 。 但过分地利用这一特点会使
for语句显得杂乱,可读性降低,建议不要把与循环控制无关的内容放到 for 语句中 。
第 4章 选择和循环结构程序设计
【 例 4.19】 求 Fibonacci(菲波那契 )数列前 40个数。这个数列有如下特点:第 1,2两个数为 1,1。从第 3个数开始,该数是其前面两个数之和。即:
F1=1 (n=1)
F2=1 (n=2)
Fn=Fn-1+Fn-2 (n≥ 3)
这是一个有趣的古典数学问题:有一对兔子,从出生后第 3个月都生一对兔子 。 小兔子长到第 3个月后每个月又生一对兔子 。 假设所有兔子都不死,问每个月的兔子总数为多少?
可以从表 4.2看出兔子数的规律 。
第 4章 选择和循环结构程序设计不满 1个月的为小兔子,满 1个月不满 2个月的为中兔子,满 3个月以 上 的为 老兔 子,可 以看 到 每个 月的 兔子 总 数依 次 为
1,1,2,3,5,8,13,… 。 这就是 Fabonacci数列 。
程序如下:
第 4章 选择和循环结构程序设计
main()
{
long int f1,f2;
int i;
f1=1; f2=1;
for(i=1; i<=20; i++)
{
printf(″% 12ld%12ld″,f1,f2);
if(i%2==0) printf(″ \n″ );
f1=f1+f2;
f2=f2+f1;
}
}
程序运行结果为:
第 4章 选择和循环结构程序设计
1 1 2 3
5 8 13 21
34 55 89 144
233 377 610 987
1597 2584 4181 6765
10946 17711 28657 46368
75025 121393 196418 317811
514229 832040 1346269 2178309
3524578 57022887 9227465 14930352
24157817 39088169 63245986 102334155
第 4章 选择和循环结构程序设计程序中在 printf函数中输出格式符用,%12ld”,而不是用
,%12d”,这是由于在第 22个数之后,整数值已超过整数最大值
32767,因此必须用,%ld“格式输出 。
if语句的作用是使输出 4个数后换行 。 i是循环变量,当 i为偶数时换行,而 i每增值 1,就要计算和输出 2个数 (f1,f2),因此 i
每隔 2换一次行相当于每输出 4个数后换行输出 。
【 例 4.20】 计算复利 。 某人在银行存入 10000.00元钱,存期 8
年,年利率为 3.5%,求其每一年的存款额 。 计算复利的公式是
,a=p(1+r)n。 其中:
p:本金,初始存款值 r:利率
a:第 n年的总存款额 n:年数写出程序如下:
#include<stdio.h>
#include<math.h>
第 4章 选择和循环结构程序设计
main()
{
int n;
double a,p=10000.00,r=0.035;
printf(″% s%21s\n″,″ Year″,″ Amout″ );
for(n=1; n<=8; n++)
{
a=p*pow(1+r,n);
printf(″% 4d%21.2f\n″,n,a);
}
return 0;
}
其中引用了一个数学库函数 pow(x,y),其功能是求 x的 y次方,因此应把包含其信息说明的头文件 math.h包含进来 。
第 4章 选择和循环结构程序设计
4.5.4 循环的嵌套一个循环体内又包含另一个完整的循环结构,称为循环的嵌套,即循环体是由循环语句组成的循环语句 。 内嵌的循环中还可以嵌套循环,这就是多层循环 。
三种循环 (while循环,do_while循环和 for循环 )可以互相嵌套 。 例如,下面几种都是合法的形式:
(1) while() (2) while()
{? {?
while() do
{?} {? }
while();
}?
}
第 4章 选择和循环结构程序设计
(3) do{?
do (4) for(;; )
{? {?
}while(); while()
{?}
}while();?
}
(5) for(;; )
{ (6) do
{
for(;; )?
{? } for(;; )
{?}
} }while();
第 4章 选择和循环结构程序设计
【 例 4.21】 计算 1到 5的乘法表 。
#include<stdio.h>
main()
{
int i,j;
for(i=1; i<=5; i++)
{
for(j=1; j<=5; j++)
printf(″ %d*%d=%2d″,i,j,i*j);
printf(″ \n″ );
}
return 0;
}
运行程序,发现有同义反复的式子,如 2*3=6和 3*2=6这种情况 。 为避免这种情况的出现,应研究一下控制变量的使用问题 。
第 4章 选择和循环结构程序设计注意到内层控制变量和外层控制变量之间的制约关系,如果把内层控制变量的初值由 j=1改为 j=i,或 j<=i即可去掉上面所说的同义反复。这种情况在今后还会遇到。
【 例 4.22】 搬砖问题 。 有 36块砖,由成年男,女和小孩共 36人来搬,男子每人搬 4块,女子每人搬 3块,两个小孩抬一块,要求一次全搬完,问需要男,女,小孩各几人?
编程思路:先从代数学入手,根据所给关系设变量,列方程,限条件,定算法 。 设男子 x人,女子 y人,小孩 z人,则 z=36-x-y。
x的取值范围,0≤x≤ 9
y的取值范围,0≤y≤ 12
这类问题可采用穷举法:使 x在 0~9之间变化,当 x取一值后再让 y
在 0~12之间变化,在 x,y各取一值的情况下,由公式求出 z的值
。 最后再测试条件 4x+3y+z/2=36是否成立 。
第 4章 选择和循环结构程序设计程序如下:
include<stdio.h>
main()
{
int x=0,y,z;
while(x<=9)
{
y=0;
while(y<=12)
{
z=36-x-y;
第 4章 选择和循环结构程序设计
if((4*x+3*y+0.5*z==36)
printf(″ x=%d,y=%d,z=%d \n″,x,y,z) ;
y++;
}
x++;
}
return 0; }
注意:在程序中,对两个小孩抬一块砖我们没有用 z/2的形式,而是用 0.5*z代替之 。 这是因为,如果用 z/2,则不管 z
为偶数或是奇数,其结果总是个整数,这就有可能出现 z为奇数而仍符合条件的情况,那将会引出荒谬的结果 。
第 4章 选择和循环结构程序设计
4.5.5 break语句和 continue语句在本章 4.4.3节中已经介绍过用 break语句可以使流程跳出
switch结构,继续执行 switch语句下面的一个语句 。 实际上,
break语句还可以用来从循环体内跳出循环体,即提前结束循环,
接着执行循环下面的语句,它的一般形式为:
break;
【 例 4.23】
#include<stdio.h>
main()
{int I=0;
for(;; )
{ printf(″% 4d″,I);
I++;
if(I==5)
break; }
return 0;
}
第 4章 选择和循环结构程序设计程序运行输出:
0 1 2 3 4
当 I的值为 5时终止 for循环 。
如果处在嵌套的内层循环中,break只能终止它所在的那层循环,不能终止外层循环 。 例如:
#include<stdio.h>
main()
{
int I,j;
for(j=1; j<5; j++)
{
I=0;
for(;; );
{
printf(″% 4d″,I);
I++;
第 4章 选择和循环结构程序设计
If(I==5) break;
}
printf(″ \n″ );
}
return 0;
}
程序运行输出:
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
外层循环由 j控制,仍要重复 4次 。
和 break语句相反,在循环体中 continue的作用不是跳出循环体。对 while和 do_while语句来说,continue的作用是跳到第 4章 选择和循环结构程序设计条件表达式处,对 for语句来说,continue的作用是跳到 for语句头中的第 3个表达式处,从而忽略循环体中处在它以下的那些语句。
它的一般形式:
continue;
其作用为结束本次循环,即跳过循环体中下面尚未执行的语句
,接着进行下一次是否执行循环的判定 。
【 例 4.24】 把输入串中除小写元音字母以外的字符打印出来 。
#include<stdio.h>
main()
{ char c;
while((c=getchar())!=′ \n′ )
{
if(c==′ a′ ||c==′ e′ ||c==′ i′ ||c==′ o′ ||c==′ u′ )
continue;
putchar(c); }
第 4章 选择和循环结构程序设计
return 0;
}
continue语句和 break语句的区别是,continue语句只结束本次循环,而不是终止整个循环的执行 。 而 break语句则是结束整个循环过程,不再判断执行循环的条件是否成立 。
第 4章 选择和循环结构程序设计
4.6 程序设计
x (x<1)
【 例 4.25】 有一函数 y= 2x-1 (1≤x< 10)
3x-11 (x≤ 10)
题中已经很明显的给出了 x的范围来求 y的值,所以应该用选择语句来完成 。 可以写出程序如下:
#include<stdio.h>
main()
{float x,y;
scanf(″% f″,&x);
if(x<1) y=x;
else if(x>=1&&x<10) y=2*x=1;
else y=3*x-11;
printf(″ x=%-5.2f,y=%-5.2f\n″,x,y);
return 0; }
第 4章 选择和循环结构程序设计
【 例 4.26】 判断 m是否为素数 。
分析:不能被 2~ m-1之间的任意数字整除才是素数 。 因此,要判断 m是否为素数,只要让 m被 2到 m-1除,如果 m能被 2~m-1之中某个或更多的数整除,则提前结束循环,输出,不是素数,,此时
I必然小于或等于 m-1;如果 m不能被 2~m-1之间的任一整数整除,
则在完成最后一次循环后,I还要加 1,因此 I=m-1+1=m,然后才终止循环 。 在循环之后判别 I的值是否大于或等于 m,若是,则表明未曾被 2~m-1之间任一整数整除过,因此输出,是素数,。
程序如下:
#include<stdio.h>
main()
{
int m,I,k;
scanf(″% d″,&m);
for(i=1; i<=m-1; i++)
if(m%I==0) break;
第 4章 选择和循环结构程序设计
if(I>m) printf(″%d is a prime nuber \n″,m) ;
else printf(″%d is not a prime number \n″,m) ;
return 0;
}
对以上程序:如果 m是素数,且 2~m-1的前半部分数据中没有能被
m整除的数,则后半部分绝对也没有,甚至在之前没有能被 m整除的数,在这之后绝对也没有。这样该程序就可以大大缩小循环的次数,读者自己写写该程序。
【 例 4.27】 求 100~200之间的全部素数,
在例 4-25的基础上,再加上之前的分析,可写出程序如下:
#include<stdio.h>
#include<math.h>
main()
第 4章 选择和循环结构程序设计
{
int m,k,I,n=0;
clrscr();
for(m=101; m<=200; m=m+2)
{
k=sqrt(m);
for(I=2; i<=k; i++)
if(m%I==0) break;
if(I>=k+1) {printf(″% -5d″,m); n=n+1; }
if(n%10==0) printf(″ \n″ );
}
printf(″ \n″ );
return 0;
}
程序运行结果如下:
第 4章 选择和循环结构程序设计
101 103 107 109 113 127 131 137 139 149
151 157 163 167 173 179 181 191 193 197
199
该程序 main函数函数体第三行用了清屏函数 clrscr(),它可以把这之前的全部内容删除,只保留本程序的运行结果,方便检测程序的结果是否正确 。
【 例 4.28】 将 316换成 11的倍数和 13的倍数相加 。
分析:只需拿 316减 11得差,316减 11*2,…,若差值为 13的倍数,则停止求解 。 写出程序:
#include<stdio.h>
main()
{
int I=1,j,k;
do
{I++;
k=316-11*I;
第 4章 选择和循环结构程序设计
}while(k%13);
j=k/13;
printf(″ 316=11*%d+13*%d\n″,I,j) ;
I=1;
do
{I++;
k=316-13*I;
}while(k%11);
j=k/11;
printf(″ 316=13*%d+11*%d\n″,I,j);
return 0; }
第 4章 选择和循环结构程序设计程序运行结果为:
316=11*11+13*15
316=13*4+11*24
【 例 4.29】 打印输出,A
BBB
CCCCC
……
总共的行数由执行时输入的数值而定 。
分析:由于计算机都是顶格输出数据 (即左对齐 ),因此类似于这样的图形打印时,都应考虑空格和字母的输出 。 假设要求输出 4行,则每行上空格的个数为 3,2,1,0,字母的个数第 4章 选择和循环结构程序设计为 1,3,5,7,也即第一行需使 j=1至 j=3循环 3次输出空格
,使 k=1至 k=1循环 1次输出字母;第二行需使 j=1至 j=2循环 2
次输出空格,使 k=1至 k=3循环 3次输出字母; …… 。那么可以引进 I变量代表行数 (1~4),则 j在每一行上的最大值可以表示为 4-I,k在每一行上的最大值可以表示为 2*I-1,因此可以写出程序如下:
#include<stdio.h>
main()
{
int I,j,k,n;
char a=′ A′ ;
scanf(″% d″,&n);
第 4章 选择和循环结构程序设计
for(I=1; i<=n; i++)
{
for(j=1; j<=n-I; j++)
printf(″ ″) ;
for(k=1; k<=2*I-1; k++)
printf(″%c″,a) ;
a++;
printf(″ \n″) ;
}
return 0;
}