第三章 语句 与 控制流
★ 内容提要:
C 语句的分类
空语句与复合语句
条件分支语句
循环控制语句与嵌套
执行流程强制转移
编程常用技巧
? 语句分类表
? 空语句与复合语句
? 条件分支语句
? 循环控制语句
? 程序示例
? 流程强制转移
C 语言是一种很好的结构化程序设计
语言,它提供了比 FORTRAN, PASCLE 更丰
富的流程控制语句,还提供了将多个语
句组合成一个语句的复合语句。
第三章 语句 与 控制流
以上语句添加标号,构成标号语句,标号语句
for 循环for( ) ~
直到型循环do ~ while( )
当循环while( ) ~
循
环
无条件转移语句break,continue,return,goto
多分支选择语句switch
条件分支语句if( ) ~ else ~分
支
转
移
流
程
控
制
语
句
花括号括起来的语句复合语句
只有一个分号的语句空语句
表达式加分号构成表达式语句
函数调用加分号构成函数调用语句
简单的顺
序执行语
句
~
~
~
循
环
~ ~分
支
转
移
流
程
控
制
语
句
句
C 语 句 的 分 类
以上语句添加标号,构成标号语句,标号语句
for 循环for( ) ~
直到型循环do ~ while( )
当循环while( ) ~
循
环
无条件转移语句break,continue,return,goto
多分支选择语句switch
条件分支语句if( ) ~ else ~分
支
转
移
流
程
控
制
语
句
花括号括起来的语句复合语句
只有一个分号的语句空语句
表达式加分号构成表达式语句
函数调用加分号构成函数调用语句
简单的顺
序执行语
句
~
~
~
循
环
~ ~分
支
转
移
流
程
控
制
语
句
句
C 语 句 的 分 类
约定:为叙述简捷方便,
凡以后在语法形式中出现的
‘ 语句 ’ 一词, 均指以上表
中的各种语句 。
一、空语句与复合语句
空语句,只有一个分号的语句,属于不进行任
何操作的语句 。
过滤掉输入字符流中的空 白、回车换行和制表符的
语句。循环体是一个空语句:
while((c=getchar())==' '||c==' \ n'||c==' \ t');
计算字符串的长度语句,其 循环体是一个空语句:
for( i=0; a[i]!=' \ 0'; i++ ) ;
复合语句, 在程序中用大括号括起来的若干语
句成为复合语句。 一般形式:
{
数据说明部分;
执行语句部分;
}
? 执行语句可以是简
单语句、构造语句,
还可以是复合语句。
? 在复合语句内部定
义的变量,其作用 域
仅限于该复合语句 的
内部;
例 [1],比较 a,b 的大小,且把大者赋给变量 x, 小的
赋给变量 y, 并打印输。
# include <stdio.h>
void main(){
int a,b,x,y;
a=2; b=3;
if(a>b){
x=a; y=b;
}
else{
x=b; y=a;
}
printf("x=%d y=%d \ n",x,y);
}
运行结果:
x=3 y=2
二、条件语句 ( if )
1,两种基本形式,
基本形式 1,
if( 表达式)语句 1 else 语句 2
表达式?
语句 1 语句 2
非零(真) 零
?
零
表达式?
语句 1
非零(真) 零零
基本形式 2,
if( 表达式)语句 1
例 [2],比较 a,b 的大小,且把大者赋给变量 x, 小
的赋给变量 y, 并打印输。
# include <stdio.h>
void main(){
int a,b,x,y; a=2; b=3;
if(a>b){
x=a; y=b;
}
else {
x=b; y=a;
}
printf("x=%d y=%d \ n",x,y);
}
运行结果:
x=3 y=2
2,if 语句的嵌套
( 1 )在基本形式 1 的 else 后的语句 2 位置层层
嵌套基本形式 1 语句。
基本形式 1,
if( 表达式)语句 1
else 语句 2
基本形式 2,
if( 表达式)语句 1
if ( 表达式 1 ) 语句 1
else if ( 表达式 2 )语句 2
……
……
else if ( 表达式 n ) 语句 n
else 语句 n+1;
2,if 语句的嵌套
基本形式 1,
if( 表达式)语句 1
else 语句 2
基本形式 2,
if( 表达式)语句 1
if ( 表达式 1 )
if ( 表达式 2 )
if ( 表达式 2 )语句 1
else 语句 2
else 语句 3
else 语句 4
( 2 )在基本形式 1 的语句 1 位置层层嵌套基本
形式 1 。
2,if 语句的嵌套
基本形式 1,
if( 表达式)语句 1
else 语句 2
基本形式 2,
if( 表达式)语句 1
if ( 表达式 1 )
if ( 表达式 2 )语句 1
else 语句 2
( 3 )在基本形式 1 的语句 1 位置嵌套基本形式 2
else究竟与哪一个 if配对?
基本形式 1, if( 表达式)语句 1 else 语句 2
基本形式 2, if( 表达式)语句 1
● 语法规定 else 总是与它前面最接近的还没
有配对的 if 配对;
● 进入 if 语句后,不管其层层嵌套有多复杂,
最多只执行其中的一个语句。
注意:
void main(){
int snum,score; char grade;
scanf("%d%d",&snum,&score );
if(score>94)
grade='5';
else if(score>79)
grade='4';
else if(score>59)
grade='3';
else
grade='2';
printf("%d %c \ n",snum,grade );
}
? 分层缩进对齐的形式,
便于阅读,便于调试。
? else 总是与它前面最接
近的还没有配对的 if 配对
? 进入 if 语句后至多执行
其中的一个语句,即使 嵌
套形式也不例外;
三、多分之选择语句 ( switch )
switch( 表达式 ){
case 常量表达式 1,语句 1
case 常量表达式 2,语句 2
……
case 常量表达式 n, 语句 n
[ default, 语句 n+1 ]
}
switch 语句形式:
功能:根据表
达式的值是否
与某常量表达
式 i 相同,来选
择执行若干语
句中的一个语
句或一个语句
序列。若要真
正起到多分支
选择执行功能
,须配合使用
break 语句。
switch( 表达式 ){
case 常量表达式 1,语句 1; break ;
case 常量表达式 2,语句 2; break ;
……
case 常量表达式 n, 语句 n; break ;
[ defalt, 语句 n+1 ]
}
真正能起到多分支选择执行功能的形式:
break语句用于终止 switch 语
句的执行, 跳出 switch 结构 。
说明:
? 表达式和常量表达式 i 要求是
整形或字符形,且两者类型相
同;
? 常量表达式 i 的值必须互不相
同,它们只起相当于语句入口
标号的作用,没有条件判断分
支执行的功能;
? 执行时若常量表达式 i 的值与
表达式相等,就顺序执行其后
的语句,否则执行 defalt 后
的语句 n+1 ;
switch( 表达式 ){
case 常量表达式 1,
语句 1; break ;
case 常量表达式 2,
语句 2; break ;
……
case 常量表达式 n,
语句 n; break ;
[ defalt,
语句 n+1 ]
}
void main(){
char grade;
scanf("%c",&grade );
switch(grade){
case 'A',printf("grade>85 \ n");
case 'B',printf("grade>75 \ n");
case 'C',printf("grade>60 \ n");
case 'D',printf("grade<60 \ n");
default, printf("error!" );
}
}
输入,A
输出,grade>85
grade>75
grade>60
grade<60
error!
? 若要真正起到多分支判断选择执行功能,须
在其后加 bre a k 语句。
void main(){
char grade;
scanf("%c",&grade );
switch(grade){
case 'A',printf("grade>85 \ n"); break;
case 'B',printf("grade>75 \ n"); break;
case 'C',printf("grade>60 \ n"); break;
case 'D',printf("grade<60 \ n"); break;
default, printf("error!" );
}
}
输入,A
输出,grade>85
? 多个 c ase 可以共用一组执行语句
void main(){
char grade;
scanf("%c",&grade );
switch(grade){
case 'A':
case 'B':
case 'C',printf("grade>60 \ n"); break;
case 'D',printf("grade<60 \ n"); break;
default, printf("error!" );
}
}
输入,A
输出,grade>85
void main(){
double x,y; char operate;
scanf("%lf",&x);
while((operate=getchar())!='='){
scanf("%lf",&y);
switch(operate){
case '+',x+=y; break;
case ' - ',x - =y; break;
case '*',x*=y; break;
case '/',x/=y; break;
}
}
printf("%f \ n",x);
}
例 [4] 模拟袖珍计算器的加减乘除四则运算编程,读
入数据,并按算式计算结果。
输入,10.8+0.13*10=
输出,109.300000
void main(){
double x,y;
char operate;
scanf("%lf",&x);
while((operate=getchar())!='='){
scanf("%lf",&y);
switch(operate){
case '+',x+=y; break;
case ' - ',x - =y; break;
case '*',x*=y; break;
case '/',x/=y; break;
}
}
printf("%f \ n",x);
}
输入,1 0, 8+ 0, 1 3 * 1 0 =
输出,1 0 9,3 0 0 0 0 0
设问,若去掉 break语
句执行结果将如何?
输入,10.8+0.13*10=
输出,10.8
void main(){
double x,y; char operate;
scanf("%lf",&x);
while((operate=getchar())!='='){
scanf("%lf",&y);
switch(operate){
case '+',x+=y; break;
case ' - ',x - =y; break;
case '*',x*=y; break;
case '/',x/=y; break;
}
}
printf("%f \ n",x);
}
说明三个问题:
1) switch 语句的应用;
2) 数据的输入与读取数据技巧(输入
缓冲区概念);
3) 该程序的运算是一步步进行的,相
当于计算器,没有运算符优先级处
理功能。
说明三个问题:
1) switch 语句的应用;
2) 数据的输入与读取数据技巧(输入
缓冲区概念);
3) 该程序的运算是一步步进行的,相
当于计算器,没有运算符优先级处
理功能。
四、循环语句
( 1 )当循环( while 语句)
while( 表达式 ) 语句
特点,先判断后执行,它
对循环体可能一次也不执
行。通常用于事先不能确
定循环次数的情况。
零
非零
表达式?
语句(循环体)
零
# include <stdio.h>
void main(){
int i,sum=0;
i=1;
while( i<=100 ){
sum=sum+i;
i++;
}
printf("%d \ n",sum);
}
例 [5] 求 。源程序如下:?
?
100
1n
n
循环控制变量,在表达式中出
现的变量称为循环控制变量。
必须注意的几个问题:
①循环控制变量必须有正确
的初值;
②在循环体内应有改变其值
的语句;
③其值的改变应使得表达式
的值最终趋向于零(循环结束
条件),否则将形成死循环。
# include <stdio.h>
void main(){
int i,sum=0;
i=1;
while( i<=100 ){
sum=sum+i;
i++;
}
printf("%d \ n",sum);
}
例 [5] 求 。源程序如下:?
?
100
1n
n
注意,循环体如果包
含一个以上的语句,
应该用花括号括起来
,以复合形式出现,
若 不 加 花 括 号, 则
while 语句的范围只到
while 后面的第一个语
句处。
输出结果,5050
( 2 )直到型循环( do ~ while 语句)
do
语句
while( 表达式 ) ;
特点,先执行后判断,循
环体至少执行一次 。适用
于循环体至少执行 一次,
且总次数不确定的情况。
零
非
零
表达式?
语句(循环体)
零
非
零
# include <stdio.h>
void main(){
int i,sum=0;
i=1;
do{
sum=sum+i;
i++;
}while( i<=100 );
printf("%d \ n",sum);
}
例 [5] 求 。源程序如下:?
?
100
1n
n
说明, do ~ while
语句与 while 语句
类似,只不过是将
条件表达式从语句
的开始移到了尾部
,因此循环体至少
执行一次
输出结果,5050
输出结果,5050
while((c= getchar ())!=EOF){
++ nc ;
if(c==' \ n') ++ nl ;
if(c==' '||c==' \ n'||c==' \ t')
inword =NO;
else if( inword ==NO){
inword =YES; ++ nw ;
}
}
printf ("%d %d %d \ n",nl,nw,nc );
}
输入,co unt l ine s ↙
w or d s ↙
^D
输出,2 3 18
EOF为文件结束标志
UNIX系统为 ctrl+d
微机系统为 ctrl+z
13543)(
23
???? xxxxf设
其中:
1) 已知牛顿迭代,)(/)(
'
1 kkkk
xfxfxx ??
?
2)
589)(
2'
??? xxxf
3) 允许误差 ( 计算精度 ),当
的绝对值小于 1 E - 6 时,就作为方程的解。
)(/)(
'
kkk
xfxfd ??
1?k
x
4) 采用高效的计算表达式形式,以提高计算速度。
)13*)5*)4*3(((13543)(
23
???????? xxxxxxxf
5*)8*9((589)(
2'
?????? xxxxxf
★ 采用精度作为循环结
束标志,是编程中经常
使用的方法之一 ★
# include <math.h>
#define EPS 1E - 6
void main(){
double x,d; //d 为允许误差
printf ("x=");
scanf ("%lf",&x);
do{
d= - (((3*x - 4)*x - 5)*x+13)/((9*x - 8)*x - 5);
x=x+d;
}while( fabs (d)>EPS);
printf ("the root is %f \ n",x);
}
输入,x=2
输出,the root is -1.548910
(四)循环的嵌套
? 一个循环体内又包含另一个完整的循环结
构,称为循环嵌套。内层循 环中还可以继续嵌
套循环,这就是多重循环。
? 三种循环( w h i l e,d o - w h i l e,f o r ) 可以
互相多重嵌套,还可以与分支选择语句( if,
switch ) 构成互相多重嵌套。
? 在语法结构上必须注意,全包含不交叉!全包含不交叉!全包含不交叉!全包含不交叉!
例 [10] 百鸡问题:鸡翁一值钱五 ; 鸡母一值钱三 ; 鸡雏
三值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何?
采用枚举的算法思想,对每一种可能的组合进行判断。
voi d ma in( ){
int co ck,hen,c hic ken;
for (co ck= 0; c oc k< = 100 ; c oc k+ + )
for (hen= 0; he n< = 100 ; he n+ + )
for (chi cke n= 0; c hic ken< = 100 ; c hic ken+ + )
if ( c oc k+ hen+ chi cke n= = 100 &&
co ck* 5+ hen*3 + chi cke n/3,0= = 100 )
pri ntf ("% d % d % d \ n",coc k,hen,c hic ken);
}
结果:
0 25 75
4 18 78
8 11 81
12 4 84
■ 循环次数的计算:外循环执行一次内循环需要执行
100 次,依次类推,因此内层循环体 if 语句需要一百万
次判断。因此有必要考虑优化算法。
101 次
101 次
101 次
voi d ma in( ){
int co ck,hen,c hic ken;
for (co ck= 0; c oc k< = 100 ; c oc k+ + )
for (hen= 0; he n< = 100 ; he n+ + )
for (chi cke n= 0; c hic ken< = 100 ; c hic ken+ + )
if ( c oc k+ hen+ chi cke n= = 100 &&
co ck* 5+ hen*3 + chi cke n/3,0= = 100 )
pri ntf ("% d % d % d \ n",coc k,hen,c hic ken);
}
优 化 算 法 减
少判断次数:
voi d ma in( ){
int co ck,hen,c hic ken;
for (co ck= 0; co ck< = 20 ; c oc k+ + )
for (hen= 0; hen< = 33 ; he n+ + )
for (chi cke n= 0; chi cke n< = 100 - co ck - hen ; c hic ken+ + )
if ( c oc k+ hen+ chi cke n= = 100 &&
co ck* 5+ hen*3 + chi cke n/3,0= = 100 )
pri ntf (" % d % d % d \ n",co ck,he n,chi cke n);
}
cock 数不会大于,100 ÷ 5=20
hen 数不会大于, 100 ÷ 3=33
chicken 数应为, 100 - cock - hen
voi d ma in( ){
int co ck,hen,c hic ken;
for (co ck= 0; co ck< = 20 ; c oc k+ + )
for (hen= 0; hen< = 33 ; he n+ + )
for (chi cke n= 0; chi cke n< = 100 - co ck - hen ; c hic ken+ + )
if ( c oc k+ hen+ chi cke n= = 100 &&
co ck* 5+ hen*3 + chi cke n/3,0= = 100 )
pri ntf (" % d % d % d \ n",co ck,he n,chi cke n);
}
要求程序按层次缩进,同层 对齐的格式书写,
便于阅读调试。
(五) return 语句
Return 语句形式:
return( 表达式 ); 或 return;
功能:
① 将程序控制(执行流程控制)返回到主调
函数的调用处。
② 在有表达式时,将表 达式的值带回到主
调函数的调用处。无表达式时,调用处的值是
不确定的。
例 [11] 编一函数,返回任一实数的符号。当自变量 X 的
值大于 0 时返回 1 ;自变量 X 的值等于 0 时返回 0 ;自变量
X 的值小于 0 时返回 - 1 。
# inc lude < stdio,h>
int sig n(doubl e x ){
if ( x < 0 ) r eturn( - 1);
el se r etur n((x = = 0)?0,1);
}
voi d ma in( ){
doubl e a ;
scanf ("lf ",&a);
pri ntf ("sign= % d \ n",s ig n(a));
}
? 在一个函数中,
根据需要可多处设
置 return 语句,但
最多只执行其中的
一个。
输入,-123
输出,sign= -1
(六) break 中断语句
break 语句形式,break;
功能, ① 强迫终止循环的执行使提前退出循环;
② 中断 switch 语句的执行。
w hil e( ){
┇
bre ak;
┇
}
w hil e( ){
┇
bre ak;
┇
}
s w it ch( ){
┇
bre ak;
┇
}
s w it ch( ){
┇
bre ak;
┇
}
do{
┇
bre ak;
┇
} w hil e( );
do{
┇
bre ak;
┇
} w hil e( );
for ( ){
┇
bre ak;
┇
}
for ( ){
┇
bre ak;
┇
}
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
注意, 不能用于循环语句和 switch 语句之外的任何地方。
(七)(七) con ti nu econ ti nu e 语句语句
continue 语句形式,continue;
功能, 结束本次循环,即跳过循环体中本语句
下面尚未执行的语句,接着进行下一次是否继
续循环的判断。(只能用于循环体)
w hil e( ){
┇
co nti nue;
┇
}
w hil e( ){
┇
co nti nue;
┇
}
do{
┇
co nti nue;
┇
} w hil e( );
do{
┇
co nti nue;
┇
} w hil e( );
for ( ){
┇
co nti nue;
┇
}
for ( ){
┇
co nti nue;
┇
}
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
break 与 continue 语句的区别
? break 是中断包含 break 语句的最内层的整个循环语
句的执行,终止本层循环,或 switch 语句;
? continue 只是中断当前循环体 的本次执行,而不是
终止整个的循环。
w hil e( ) {
┇
bre ak ;
┇
}
w hil e( ) {
┇
bre ak ;
┇
}
s w itc h( ) {
┇
bre ak ;
┇
}
s w itc h( ) {
┇
bre ak ;
┇
}
do{
┇
bre ak ;
┇
} w hil e( ) ;
do{
┇
bre ak ;
┇
} w hil e( ) ;
f or( ){
┇
bre ak ;
┇
}
f or( ){
┇
bre ak ;
┇
}
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
w hil e( ) {
┇
con tin ue;
┇
}
w hil e( ) {
┇
con tin ue;
┇
}
do{
┇
con tin ue;
┇
} w hil e( ) ;
do{
┇
con tin ue;
┇
} w hil e( ) ;
f or( ){
┇
con tin ue;
┇
}
f or( ){
┇
con tin ue;
┇
}
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
例 [12] 求 1 ~指定数之间的素数。素数是大于 1,且除
了 1 和它本身外,不能被其它任何整数除的整数。
讨论,根据素数的定义可知
2, 3, 5, 7, 11, 13, 17 等是素数。
1, 4, 6, 8, 10, 12, 14, 15 不是素数。
为了判断某数 i 是否为素数,一个最简单的办法是用
2, 3, 4, 5, …, i - 1 这些数逐个去除 i, 看能否除尽。
若被其中一个数除尽了,则 i 不是素数,否则(全部除
不尽) i 是素数。当 i 较大时,用这种办法,除的 次数
太多。
例 [12] 求 1 ~指定数之间的素数。素数是大于 1,且除
了 1 和它本身外,不能被其它任何整数除的整数。
讨论,根据素数的定义可知
2, 3, 5, 7, 11, 13, 17 等是素数。
1, 4, 6, 8, 10, 12, 14, 15 不是素数。
根号法求素数,
用 2, 3, 4, …, 去除,如果除不尽,则 i 是素数。
这是因为,如果小于等于 的数除不尽,则大于
的数也不能除尽 i 。
i
i i
voi d ma in( ){
int n;
scanf (" % d ",&n);
sushu ( n );
}
输入:
100
输出
2 3 5 7 11 13 17 19 23 29
31 37 41 43 47 53 59 61 67 71
73 79 83 89 97
25
(八) goto 语句与标号 ( 示例说明。求 。 )?
?
100
1n
n
voi d main(){
int i,s um=0;
i=1;
lo op,if(i<=10 0){
sum=sum+i;
i++;
goto lo op;
}
pri ntf ("% d \ n",s um);
}
说明:
1, 任何语句前允许加标号
形式,标号:语句
注意,
① 其中标号用表识符表
示,取名规则同变量名,
不能用整数形式表示。
② 标号的作用域为标号
所在函数,即只允许在本
函数内的语句引用。
(八) goto 语句与标号 ( 示例说明。求 。 )?
?
100
1n
n
voi d main(){
int i,s um=0;
i=1;
lo op,if(i<=10 0){
sum=sum+i;
i++;
goto lo op;
}
pri ntf ("% d \ n",s um);
}
说明:
2, goto 语句形式:
goto 语句标号;
作用:无条件转移。
①可实现从循环体内跳
转到循环体外,但不能
从循环体外转入体内;
②构成 goto 型循环。
# include <stdio.h>
#include <math.h>
#define EPS 1e - 7
void main(){
double udf_sin(double x); // 用户自定义函数原型说明
double a; scanf("%lf",&a);
printf("%f %f \ n",udf_sin(a),sin(a));
}
double udf_sin( double x ){ // 用户自定义函数
double sum,term,n=1; sum=term=x;
while( fabs(term) > EPS ){
n=n+1;
term=term*( - x*x)/((2*n - 2)*(2*n - 1));Th e end
培 育 英 才 钻 研 科 学
书山有径勤为路
学海无边苦作舟
书山有径勤为路书山有径勤为路
学海无边苦作舟学海无边苦作舟