第三章 语句 与 控制流
★ 内容提要:
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!
若要真正起到多分支判断选择执行功能,须在其后加 br e 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 as e 可以共用一组执行语句
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] 求 。源程序如下:?
1 0 0
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] 求 。源程序如下:?
1 0 0
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] 求 。源程序如下:?
1 0 0
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 );
}
输入,coun t li nes ↙
w ord 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] 百鸡问题:鸡翁一值钱五 ; 鸡母一值钱三 ; 鸡雏三值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何?
采用枚举的算法思想,对每一种可能的组合进行判断。
void main(){
int cock,h en,chicken;
for(cock=0; cock<=100; cock++ )
for(hen =0; hen<=100; hen ++ )
for(chicken=0; chicken<=100; chicken++)
if( cock+hen+chic ken==100 &&
cock*5+hen* 3+chic ken/3.0==100 )
printf (" % d % d % d \ n",cock,h en,chicken);
}
结果:
0 25 75
4 18 78
8 11 81
12 4 84
■ 循环次数的计算:外循环执行一次内循环需要执行
100 次,依次类推,因此内层循环体 if 语句需要一百万次判断。因此有必要考虑优化算法。
101 次
101 次
101 次
void main(){
int cock,h en,chicken;
for(cock=0; cock<=100; cock++ )
for(hen =0; hen<=100; hen ++ )
for(chicken=0; chicken<=100; chicken++)
if( cock+hen+chic ken==100 &&
cock*5+hen* 3+chic ken/3.0==100 )
printf (" % d % d % d \ n",cock,h en,chicken);
}
优 化 算 法 减少判断次数:
void main(){
int cock,h en,chicken;
for(cock=0; cock<=20 ; cock++)
for(hen =0; hen<=33 ; hen ++ )
for(chicken=0; chicken<=100 - cock - hen ; chicken++)
if( cock+hen+chic ken==100 &&
cock*5+hen* 3+chic ken/3.0==100 )
printf (" % d % d % d \ n",cock,hen,chicken);
}
cock 数不会大于,100 ÷ 5=20
hen 数不会大于,100 ÷ 3=33
chicken 数应为,100 - cock - hen
void main(){
int cock,h en,chicken;
for(cock=0; cock<=20 ; cock++)
for(hen =0; hen<=33 ; hen ++ )
for(chicken=0; chicken<=100 - cock - hen ; chicken++)
if( cock+hen+chic ken==100 &&
cock*5+hen* 3+chic ken/3.0==100 )
printf (" % d % d % d \ n",cock,hen,chicken);
}
要求程序按层次缩进,同层 对齐的格式书写,
便于阅读调试。
(五) return 语句
Return 语句形式:
return( 表达式 ); 或 return;
功能:
① 将程序控制(执行流程控制)返回到主调函数的调用处。
② 在有表达式时,将表 达式的值带回到主调函数的调用处。无表达式时,调用处的值是不确定的。
例 [11] 编一函数,返回任一实数的符号。当自变量 X 的值大于 0 时返回 1 ;自变量 X 的值等于 0 时返回 0 ;自变量
X 的值小于 0 时返回 - 1 。
# incl ud e < std io,h>
int sign(d oub le x ){
if( x <0 ) ret urn( - 1);
el se return(( x == 0)?0:1) ;
}
void main(){
dou ble a;
scan f (" lf",&a) ;
printf (" sign= % d \ n",s ign(a));
}
在一个函数中,
根据需要可多处设置 return 语句,但最多只执行其中的一个。
输入,-123
输出,sign= -1
(六) break 中断语句
break 语句形式,break;
功能,① 强迫终止循环的执行使提前退出循环;
② 中断 switch 语句的执行。
w hile ( ){
┇
break;
┇
}
w hile ( ){
┇
break;
┇
}
s w itch( ){
┇
break;
┇
}
s w itch( ){
┇
break;
┇
}
do{
┇
break;
┇
} w hile ( );
do{
┇
break;
┇
} w hile ( );
for( ){
┇
break;
┇
}
for( ){
┇
break;
┇
}
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
注意,不能用于循环语句和 switch 语句之外的任何地方。
(七)(七) co n t i n u eco n t i n u e 语句语句
continue 语句形式,continue;
功能,结束本次循环,即跳过循环体中本语句下面尚未执行的语句,接着进行下一次是否继续循环的判断。(只能用于循环体)
w hile ( ){
┇
continu e;
┇
}
w hile ( ){
┇
continu e;
┇
}
do{
┇
continu e;
┇
} w hile ( );
do{
┇
continu e;
┇
} w hile ( );
for( ){
┇
continu e;
┇
}
for( ){
┇
continu e;
┇
}
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
break 与 continue 语句的区别
break 是中断包含 break 语句的最内层的整个循环语句的执行,终止本层循环,或 switch 语句;
continue 只是中断当前循环体 的本次执行,而不是终止整个的循环。
w hile( ){
┇
break ;
┇
}
w hile( ){
┇
break ;
┇
}
s w itch( ) {
┇
break ;
┇
}
s w itch( ) {
┇
break ;
┇
}
do{
┇
break ;
┇
} w hile( );
do{
┇
break ;
┇
} w hile( );
f or( ) {
┇
break ;
┇
}
f or( ) {
┇
break ;
┇
}
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
┇
w hile( ){
┇
contin ue;
┇
}
w hile( ){
┇
contin ue;
┇
}
do{
┇
contin ue;
┇
} w hile( );
do{
┇
contin ue;
┇
} w hile( );
f or( ) {
┇
contin ue;
┇
}
f or( ) {
┇
contin 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
void main(){
int n;
scan f (" % 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 语句与标号 ( 示例说明。求 。 )?
1 0 0
1n
n
void main () {
int i,sum =0;
i=1;
loop,if( i<=10 0){
sum =su m+ i;
i++;
goto loop;
}
print f ("%d \ n",su m) ;
}
说明:
1,任何语句前允许加标号形式,标号:语句注意,
① 其中标号用表识符表示,取名规则同变量名,
不能用整数形式表示。
② 标号的作用域为标号所在函数,即只允许在本函数内的语句引用。
(八) goto 语句与标号 ( 示例说明。求 。 )?
1 0 0
1n
n
void main () {
int i,sum =0;
i=1;
loop,if( i<=10 0){
sum =su m+ i;
i++;
goto loop;
}
print f ("%d \ n",su m) ;
}
说明:
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));The end
培 育 英 才 钻 研 科 学书山有径勤为路学海无边苦作舟书山有径勤为路书山有径勤为路学海无边苦作舟学海无边苦作舟