第 4章 C语言程序结构
4.1 程序结构概述
4.2 顺序结构
4.3 选择结构
4.4 循环结构
4.5 无条件转向语句
4.1概述
任何一个结构化程序都可以由三种基本控制结构来表示
(1)顺序结构
顺序结构是最简单的一种基本结构。它是按语句出现的先后顺序依次执行的,,执行完 A操作后,再执行 B操作。
(2)选择结构
选择结构又称分支结构,在这种结构中包含一个条件判定,
根据条件是否成立而确定是执行 A还是执行 B。
(3)循环结构
循环结构又称重复结构。它是在给定的条件成立的情况下,
重复执行某一程序段 (循环体 ),直到条件不满足为止程序的三种基本控制结构顺序结构:按语句出现的先后顺序依次执行的选择结构:根据条件是否成立而确定是执行 A还是执行循环结构:它是在给定的条件成立的情况下,重复执行某一程序段,直到条件不满足为止上述三种基本控制结构的共同特点有 3个:
① 具有一个入口和一个出口;
②结构内的每一部分都有机会被执行到;
③结构内不存在“死循环”。
C语言的所有基本语句,按照它们在运行时的结构可分为四类,顺序结构语句、选择结构语句、循环结构语句以及转向结构语句。在编写程序时,力求使用前三种基本结构语句,尽可能不用转向语句,因为转向语句会破坏程序结构中的单入口单出口特性,
从而影响程序的清晰度和易读性。
4.2顺序结构
C语言中的顺序语句结构主要由表达式语句、说明语句、
输入 /输出语句、空语句和复合语句组成。顺序语句结构流程图中语句以分号“;”为结束标志,因此只要有分号的地方就有一个语句,不管它前面是否有内容。
顺序结构实例
#include"stdio.h"
#include"math.h"
void main()
{
float x1,y1,z1,q1,area1;
printf("请输入三角形 I的三条边 x1,y1,z1,");
scanf("%f%f%f",&x1,&y1,&z1);
q1=1/2.0*(x1+y1+z1);
area1=sqrt(q1*(q1-x1)*(q1-y1)*(q1-z1));
printf("三角形 I的面积是,%f\n",area1);
{
float x2,y2,z2,q2,area2;
printf("请输入三角形 II的三条边 x2,y2,z2,");
scanf("%f%f%f",&x2,&y2,&z2);
q2=1/2.0*(x2+y2+z2);
area2=sqrt(q2*(q2-x2)*(q2-y2)*(q2-z2));
printf("三角形 II的面积是,%f\n",area2);
}
}
程序结果
4.3选择结构
通常,计算机程序是按语句在程序中书写的顺序执行的,
然而,在许多场合,需要根据不同的情况执行不同的语句,称这种程序结构为选择结构。 C语言提供的条件语句和开关语句可用于实现选择结构程序设计。
4.3.1选择结构简介
选择结构体现了程序的判断能力。在程序执行过程中能依据运行时某些变量的值确定某些操作是否执行,或者确定若干个操作中选择哪个操作执行,这种程序结构称为选择结构,又称为分支结构。
4.3.2简单的 if语句
if结构是一种常用的分支结构,用它可以构成复杂的判断选择。
if语句是最简单的一种单分支结构,其一般形式为,
if(<表达式 >)
<语句 A>
其中,<表达式 >一般为条件表达式或逻辑表达式,if结构的功能是,先判断 <表达式 >的逻辑值,若该逻辑值为“真”,
则执行 <语句 A>,否则,什么也不执行。
必须注意的是,if语句中的 <语句 A>一般情况下都是以复合语句的形式出现,即用一对花括号将语句括起来。
4.3.3 if-else语句结构说明
双分支结构是按照某个条件判断出执行两个语句 (可以是复合语句 )中的哪个语句。
语句 1和语句 2可以是单条语句、复合语句或是内嵌 if语句等,
也可以是空语句;
表达式可以是任何类型,常用的是关系表达式或逻辑表达式;
else与 if配对,不能单独出现;
if-else的配对原则是,else总是与它上面的最近的尚未配对的 if语句配对在使用 if-else语句时,有以下两点注意事项。
由于 if或 else子句中只允许有一条语句,因此,需要多条语句时必须用复合语句,即把需要执行的多条语句用一对大花括号括起来。
if子句中内嵌 if语句时,因为 else子句总是与距离它最近的且没有配对的 if相结合,而与书写的缩进格式无关,
所以,如果内嵌的 if语句没有 else分支,即不是完整的 if-
else形式,则极容易发生 else配对错误。为了避免这类逻辑错误的发生,有两个有效的办法:一是将 if子句中内嵌的 if语句用一对大花括号括起来,二是尽量采用在
else子句中内嵌 if语句的形式编程。
猜数游戏
#include<stdio.h>
#include<stdlib.h>
void main()
{
int guess,magic;
magic=rand(); /*获取一个随机数 */
printf("请输入你猜的数字,");
scanf("%d",&guess);
if(guess==magic)
printf("很遗憾,猜错了! \n");
else
printf("恭喜你,猜对了! \n");
}
游戏结果
4.3.4if-else-if语句
else if结构是分支嵌套常用的一种形式,它并不是 C语言中的一种语句。它常用于多分支处理,其常用结构为,
if(表达式 1)
语句 1
else if(表达式 2)
语句 2;
else if(表达式 3)
语句 3;
else

4.3.4if-else-if语句
该语句执行过程是,先判断条件 1(表达式 1),若条件 1成立,
则执行语句 1后,退出该 if结构;否则,再判断条件 2(表达式
2)。若条件 2成立,则执行语句 2后,退出该 if结构;否则,
再判断条件 3(表达式 3)。若条件 3成立,则执行语句 3后,退出该 if结构 ……
注意:多分支结构可在条件为真时执行指定的操作,条件为假时,进一步判断下一步条件。
计算运费
#include<stdio.h>
void main()
{
int s;
float p,w,d,f;
printf("请输入每千米每吨货物的基本运费为 p、货物重量为 w和距离为 s:
\n");
scanf("%f%f%d",&p,&w,&s);
if(s<250)d=0;
else if (s<500) d=2;
else if (s<1000) d=5;
else if (s<2000) d=8;
else if (s<3000) d=10;
else d=15;
f=p*w*s*(1-d/100.0); /*依据不同的折扣计算总运费 */
printf("总的运费为,%f\n",f);
}
运行结果
4.3.5if语句的嵌套
if结构可以嵌套使用,即 if语句中的执行语句又是 if语句。简单 if结构中可以包含简单 if结构; if-else结构中可以包含 if-
else结构; if-else-if结构中可以包含 if-else-if结构。当然,还可以相互嵌套使用,如简单 if结构中可以包含 if-else结构,if-
else结构中也可以包含简单 if结构等。
1.简单 if语句的嵌套
一般形式为,
if(表达式 1)if(表达式 2)语句 A
单分支 if语句的内嵌语句本身又是一个单分支 if语句。程序在执行时先判断表达式 1,若条件 1成立,再判断表达式 2。当条件 2成立时,才会执行语句 A,否则退出 if语句。
简单 if结构的嵌套
#include<stdio.h>
#include<math.h>
void main()
{
float x,y,z,q,area;
printf("请输入三角形的三条边,");
scanf("%f%f%f",&x,&y,&z);
if(x+y>z)
if(y+z>x)
if(z+x>y)
{ q=1/2.0*(x+y+z);
area=sqrt(q*(q-x)*(q-y)*(q-z)); /*求取三角形的面积 */
printf("三角形的面积为,%f\n",area);}
}
运行结果
2.if-else语句的嵌套
if-else语句嵌套的一般形式为:
if(表达式 1)
if(表达式 2)
语句 A
else
语句 B内嵌语句
else
if(表达式 3)
语句 C
else
语句 D内嵌语句注意:
C语言不限制内嵌层数。
( 1) if-else结构尽量缩格对齐;
( 2)在 else分支上嵌套,应注意 if和 else的配对关系。为了避免二义性,C语言规定,else 总是与它前面最近的 if配对。
三数先大后小输出
#include<stdio.h>
void main()
{
int x,y,z;
printf("请输入三个整数 x,y,z,");
scanf("%d%d%d",&x,&y,&z);
if(x>y)
if(y>z)
/*x>y>z*/
printf("三个数由大到小为,%d,%d,%d\n",x,y,z);
else if(x>z)
/*x>z>y*/
printf("三个数由大到小为,%d,%d,%d\n",x,z,y);
程序接上页
else
/*z≥x>y*/
printf("三个数由大到小为,%d,%d,%d\n",z,x,y);
else if(x>z)
/*y≥x>z*/
printf("三个数由大到小为,%d,%d,%d\n",y,x,z);
else if(y>z)
/*y>z≥x*/
printf("三个数由大到小为,%d,%d,%d\n",y,z,x);
else
/*z≥y≥x*/
printf("三个数由大到小为,%d,%d,%d\n",z,y,x);
}
运行结果
4.3.6switch 语句
当问题需要讨论的情况较多时 (一般大于 3种 ),通常使用开关语句代替条件语句来简化程序的设计。开关语句就像多路开关一样,使程序控制流程形成多个分支,根据一个表达式可能产生的不同结果值,选择其中一个或几个分支语句去执行。
因此,它常用于各种分类统计、菜单等程序的设计。
C语言中的开关语句为 switch语句,其格式为:
switch(表达式 )
{
case <常量表达式 1>,[语句 1;][ break; ]
case <常量表达式 2>,[语句 2;][ break; ]
case <常用表达式 n-1 >,[语句 n-1 ;][ break;]
[ default,语句 n;]
}
可以是整型表达式、字符表达式或枚举表达式关键字常量表达式应与 switch后的表达式类型相同,
且各常量表达式的值不允许相同关键字,可省略,该语句的功能是退出
switch语句关键字,可省略,可出现在 switch语句体内的任何位置但程序依 switch语句体的顺序执行。
switch语句一般形式的流程图具有独立分支的 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");
defaclt,printf("输入有误 !\n");
}
而在上面的 switch语句中加入 break语句后,程序如下
void main()
{
char grade;
printf(“请输入考试成绩等级:” );
scanf(“%c”,&grade);
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("输入错误 !\n");
}
}
运行结果
switch()语句时需要注意以下几点,
( 1)各个情况所执行的子句可以由多个语句组成,可以不用 { }括起来。若子句前面有情况表达式,后边有 break语句,
则不必写成复合语句形式。
( 2)多分支选择开关语句的情况表达式与情况常量的数据类型必须一致,但对于整型与字符型来讲,允许它们之间直接进行比较,而不必进行转换。
( 3) case和 default可以按任意顺序出现在 switch()语句体中,
而不会影响程序执行结果,default子句可以省略不用。但是每个 case所包含的情况常量应该与其他情况常量互不相同。
( 4)应该在 switch()语句的成分子句中使用 break中断语句,
使之从 switch()语句体中退出。
switch()语句时需要注意以下几点,
( 5)在 switch()语句中,允许多种情况执行相同的成分子句,
并且允许将其成分子句写成缺省形式,即将共同执行的成分子句写在最后一种情况之后。
( 6)如果在每个情况的子句部分都没给出 break显式的控制转移,则在一个情况的成分子句执行后将继续执行后继的
case或 default后面的成分子句。这一点特别需要注意。
( 7) switch语句与 if语句的不同之处在于,switch语句只能对整型 (含字符型 )表达式的值是否等于给定的值进行判断,而 if
语句可以用于判断各种表达式。
( 8) switch语句中,case后面只能是常量,且各常量表达式的值不能相同,否则会出现错误。
4.4循环结构
4.4.1循环结构简介
循环结构也称重复结构,是程序设计三种基本结构之一。利用循环结构进行程序设计,一方面降低了问题的复杂性,减少了程序设计的难度 ;另一方面也充分发挥了计算机自动执行程序、运算速度快的特点。所谓循环就是在给定条件成立时,
反复执行某程序段,直到条件不成立为止。给定的条件称为循环条件,反复执行的程序段称为循环体在程序中,需反复执行的程序段称为循环体,用来控制循环进行的变量称为循环变量。在程序设计过程中,要注意程序循环条件的设计和在循环体中对循环变量的修改,以免陷入死循环。在实际应用中根据问题的需要,可选择用单重循环或多重循环来实现循环,并要处理好各循环之间的依赖关系。
C语言提供的循环语句有四种,while语句,do-while语句,
for语句,if-goto。 for循环的使用较为灵活,且不需要在循环体中对循环变量进行修改 ;而 while和 do-while必须在循环体中对循环变量进行修改。
4.4.2 while循环结构
while语句用来实现“当型”循环的结构。其格式为
while(<表达式 >)语句 A
其中,表达式的作用是进行条件判断的,为一关系表达式或逻辑表达式。语句 A是 while语句的内嵌语句,是循环体。
当程序执行到 while语句时,先判断表达式 (条件 )的值,若为非 0(真 ),则执行 while语句的内嵌语句 A,然后再判断条件,
一直循环下去,直到表达式的值为 0。若为 0(假 ),执行 while
后面的语句。
输出一个数字和三个空格符
#include<stdio.h>
main()
{
int i=0;
for(i; i<5; i++)
printf("%d ",i); /*输出一个数字和三个空格符 */
printf("\n");
}
运行结果计算阶乘
因为 n! =1× 2× 3× … × (n-1)× n,计算的过程就是实际连乘的过程,所以其算法和实现连加的算法是类似的计算阶乘
#include<stdio.h>
main()
{
int i=1,n; /*定义 i和 n变量,并为 i赋初值 1*/
long fac=1; /*因阶乘值取值范围较大,故 p定义为长整型,并赋初值 1*/
printf("请输入一个正整数,");
scanf("%d",&n); /*输入 n值 */
while(i<=n) /*先判断后后执行,循环 n次 */
{
fac=fac*i; /*做累乘运算 */
i++; /*累乘次数计数器加 1*/
}
printf("%d!=%1d\n",n,fac); /*以长整型格式输出计算结果,即 n的阶乘值 */
}
运行结果使用 while语句时应注意以下几点:
① 由于 while语句先判断表达式,后执行循环体。 while语句中的表达式一般是关系表达或逻辑表达式,如果表达式的值一开始就为假,则循环体一次也不执行。
② while语句的表达式要用圆括号括起来 ;当循环体有多个语句时,要用花括号括起,以形成复合语句。
③在循环体中应该有使表达式的值有所变化的语句,以使循环能趋于终止,否则会形成死循环。
4.4.3do-while循环语句
do...while语句也可用来实现程序的循环,其格式为
do<语句 A>
while(<表达式 >);
其中,语句 A和表达式的作用与
while语句的相同。
当程序执行到 do...while语句时,
先执行内嵌语句 A(循环体 ),再判断表达式 (条件 ),当表达式的值为非 0(真 )时,返回 do语句重新执行内嵌语句,如此循环,
直到表达式的值为 0(假 )为止,
才退出循环。
求 sin(x)=x-x3/3! +x5/5! -x7/7! +… 直到最后一项绝对值小于
1e-7(即 10-7)为止
#include<math.h>
#include<stdio.h>
void main()
{
double s,t,x;
int n=1;
printf(“请输入一个弧度值:” )
scanf("%lf",&x);
t=x;
s=x;
do
{
n=n+2;
t=t*(-x*x)/(n*(n-1));
s=s+t;
}while(fabs(t)>=1e-7); /*循环结束条件是 t的绝对值小于
1e-7*/
printf("sin(%lf)=%lf\n",x,s);
}
运行结果
4.4.4 for循环语句
for语句是 C语言中使用最为灵活的语句,不论循环次数是已知,还是未知,都可以使用 for语句。 for语句的格式如下:
for([表达式 1] ;[表达式 2] ;[表达式 3] )语句
for语句的执行过程如下:
step l:先计算表达式 1的值。
step 2:再计算表达式 2(条件 )的值,若表达式 2的值为非
0(“真”,条件成立 ),则执行 for语句的循环体语句,然后再执行第 3步 ;若表达式 2的值为 0(“假”,条件不成立 ),
则结束 for循环,直接执行第 5步。
step 3:计算表达式 3的值。
step 4:转到第 2步。
step 5:结束 for语句 (循环 ),执行 for语句后面的语句。
for语句的执行流程图求 1+2+3+… + 100的和根据算法流程图可写出程序代码如下:
#include<stdio.h>
void main()
{
int i,sum;
sum=0;
for(i=1;i<=100;i++)
sum=sum+i;
printf("sum=%d\n",sum);
}
运行结果说明
for([表达式 1] ;[表达式 2] ;[表达式 3] )
for语句中的表达式,分别对应着循环控制中的 3个基本组成部分,即
表达式 1:循环控制变量的初始化 (只执行 1次 );
表达式 2:循环判断条件,是循环的入口,若条件满足则执行循环体,否则结束循环;
表达式 3:改变循环控制变量操作 (循环控制变量的增量 ),
执行完循环体后,执行该语句 ;执行完毕,转去执行表达式 2。因此,for语句也可以写成如下形式:
for(循环变量赋初值 ;循环条件 ;循环变量增值 )
( 2)循环体由“语句”部分来描述,和其他循环一样,
它也可以是一条语句,空语句或复合语句。
<初始表达式 >可以省略,但须保留分号 (;),同时在 for
之前必须给循环变量赋值,形式为:
<初始表达式 >;
for(;<条件表达式 >;<循环表达式 >)
<循环语句体 >
<条件表达式 >一般不可省略,否则为无限循环。
如:
for(i=l;;i++)
sum=sum+i;
相当于条件总为真,程序会一直不停的执行直到“数据溢出”。
<循环表达式 >亦可省略,但在循环语句体中必须有语句来修改循环变量,以使条件表达式的值在某一时刻为 0,
从而能正常结束循环。
三个表达式均省略,即 for(;;),为无限循环,程序中要避免这种情况的发生。
条件表达式可以是关系表达式、数值表达式。只要表达式的值 ≠0。就执行循环语句。
如:
for(i=0;(c=getchar())!='/n';i+=c);
初始表达式、循环表达式可以是逗号表达式,以使循环变量值在修改时可以对其他变量赋值。
如:
for(sum=0,i=1;i<=100;i++,i++)
相当于,sum=0;
for(i=1;i<=100;i=i+2)
for循环也可以嵌套,执行时是先内后外。
goto语句(也是一种无条件转向语句)
goto语句是一种无条件转移语句。 goto 语句的使用格式为,
goto 语句标号;
其中标号是一个有效的标识符,这个标识符加上一个,:”
一起出现在函数内某处,执行 goto语句后,程序将跳转到该标号处并执行其后的语句。另外标号必须与 goto语句同处于一个函数中,但可以不在一个循环层中。通常 goto
语句与 if条件语句连用,当满足某一条件时,程序跳到标号处运行。
4.4.5几种循环语句的比较
while语句 ;do-while语句; goto语句和 for语句四种循环语句的比较。
( 1)四种循环都可以对同一个问题进行处理,通常四者可以互换。但具体情况下有所侧重。其中 for语句与 while语句执行过程相同,但 for语句简洁、清晰,它将初始条件、判断条件和循环变量增量在一行书写、显得直观、明了。
( 2) while和 for属于“当型循环”,do-while属于“直到型”
循环。
for语句和 while语句是判断条件后执行循环体,循环体可能一次都不执行 ;而 do-while是先执行循环体后判断条件,无论条件是否满足都要执行一次循环体。
( 3)用 while和 do-while循环时,循环变量的初始化操作是在 while和 do-while语句之前完成的,对循环变量的修改是在循环体中完成的。而 for语句则是在表达式 1中实现对循环变量的初始化,在表达式 3中实现对循环变量的修改的。
( 4) goto语句通常不用,主要因为它将使程序层次不清,且不易读,但在多层嵌套退出时,用 goto语句则比较合理。
4.4.6 循环结构的嵌套
循环结构的嵌套有很多种,while循环结构的循环体中可以包含 while循环 ;do_while循环结构的循环体中可以包含 do_while循环 ;for循环结构的循环体中可以包含 for
循环。此外,这几种循环结构之间还可以相互嵌套。一般循环体中的循环称为“内循环”,包含内循环的循环称为“外循环”,当然,这只是指二重循环。另外还有多层嵌套的情况,这属于多重循环。
编程输出如下由,*”组成的三角形
*
***
*****
*******
*********
分析:
读者已经了解,
执行循环语句:
for(i=1;i<=10;
i++)
printf("*");
程序代码
#include<stdio.h>
void main()
{
int i,j;
for(i=1;i<=5;i++)
{
for(j=1;j<=2*i-1;j++)
printf("*");
printf("\n");
}
}
运行结果
4.5 无条件转向语句
无条件转向语句是指当程序执行到该语句时,程序立即转移到程序的其他地方执行,至于转移到什么地方,要看使用何种无条件转向语句。 C语言提供三个无条件转向语句,break语句,continue语句和 goto语句。
break语句主要用于循环结构和 switch语句结构中。
continue语句主要用于循环结构中。
结构化程序设计要求少用或尽量不用 goto语句,但有些场合还在应用。
4.5.1 break语句
格式,break;
作用:强迫终止程序的执行,即提前退出程序的执行。
用法:只能用在 switch语句和循环体中使用。当 break语句在循环体中的
switch语句体内时,其作用是跳出该
switch语句体。当 break语句在循环体中时,其作用是跳出本层循环体。
4.5.2 continue语句
格式,continue;
作用:结束本次循环,不再执行 continue语句之后的循环体语句,直接使程序回到循环条件,判断是否提前进入下一次循环。
continue语句只用在 for,while,do-while等循环体中,通常与 if条件语句一起使用,用来加速循环。
循环体中单独使用 continue语句无意义。
continue语句和 break语句在流程中的转向
4.5.3 goto语句
因为使用 goto语句会破坏结构化程序的逻辑结构,所以结构化程序设计语言不提倡使用 goto语句。但在程序设计的某些场合,goto语句也会使程序设计得以简化,所以一般结构化程序设计语言中又都保留了无条件转移语句 goto,只是限制其使用而已。
goto语句是无条件转移语句。它的一般形式如下:
goto语句标号 ;
其中,goto为保留字。语句标号用标识符表示,用来标识一条语句,它出现在语句的前面,用冒号与语句隔开。
如:
语句标号:语句
goto语句的执行过程是:将执行转移到标号所标识的语句去执行。
goto语句
goto语句只能在所在的函数体内转移,即 goto与标号在同一函数内。
goto语句与 if语句配合使用,也能构成循环,但按照结构化程序设计原则,应该限制使用。
goto语句最常见的用法是用来退出多重循环,而前面介绍的 break语句只能退出一层循环。但要注意。使用
goto语句只能从循环内部跳转到循环外部,而不能由循环外部向循环内部跳转。
另外,有时在遇到特殊情况 (如某种出错 )时用来转出正常控制结构,可以使用 goto语句提早结束正常处理的程序段。