C语言程序设计
2002 年第四章 流程控制
4.1 复合语句(块)
形式,用,{}”括起的一组语句,等价于一条语句。
{
说明部分语句部分
}
例,if (a>b)
{ int t;
t=a; a=b; b=t;
}
4.2 if 语句格式一,if (表达式) 语句;
例:如果 a大于 b则交换 a和 b的值。
解法 1:用问号、逗号组成表达式语句:
a>b? t=a,a=b,b=t,a? a>b? t=a,a=b,b=t,a;
解法 2:用 if语句:
if (a>b)
{ t=a; a=b; b=t;}
表达式语 句非 0
0
格式二,if (表达式)语句 1 else 语句 2
例:解方程 ax+b=0,a和 b从终端输入。
分析:输入,a和 b,类型 float;
输出,x,类型 float;
数据关系,x=-b/a a≠0。
#include,stdio.h”
main()
{ float a,b,x;
printf(“input a,b”); scanf(“%f%f”,&a,&b);
if (!a) /*如果 a==0*/
printf (“input error”);
else { x=-b/a; printf(“x=%.4f\n”,x); }
}
语句 2
表达式语句 1
非 0 0
if子句
else子句
if 语句的嵌套当 if子句或 else子句中又包括 if语句时,成为 if语句的嵌套。
例:求下面函数的值。
1 x>0
y= 0 x=0
-1 x<0
方法 1:
if (x>0)
y=1;
else if (x==0)
y=0;
else y=-1;
方法 2:
if (x>0) y=1;
if (x==0) y=0
if (x<0) y=-1;
方法 3,(错误)
if (x>0) y=1;
if (x==0)
y=0;
else y=-1;
嵌套的 if语句的配对规则:
例:程序段,if (n>0)
if (a>b) z=a;
else z=b;
n>0
a>b
z=a z=b
0
非 0
0
非 0
n>0
a>b
z=a z=b
0
非 0
0
非 0
两种理解,二义性编译约定,else与前面最靠近的 if配对 。
if (n>0) if (n>0)
if (a>b) z=a; 等价于 {if (a>b) z=a; 实现
else z=b; else z=b;}
a,n>0且 a>b
z=
b,n>0且 a≤b
a,n>0且 a>b
z=
b,a≤b
if (n>0)
{ if (a>b) z=a; }
else z=b;
例:学生总成绩按下列标准分等(其中 x为学生的平均成绩):
平均成绩 等级英文名
90≤x ≤100 excellent(优 )
80≤x < 90 good(良 )
60≤x < 80 middle(中 )
x<60 bad(差 )
输入学生的平均成绩,输出对应的等级。
#include,stdio.h”
main()
{ float x;
printf(“input average score”);
scanf(“%f”,&x);
if (x>100 || x<0)
printf(“input error”);
else if (x<=100 && x>=90)
printf(“excellent”);
else if (x<90 && x>=80)
printf(“good”);
else if (x<80 && x>=60)
printf(“middle”);
else printf(“bad”);
}
#include,stdio.h”
main()
{ float x;
printf(“input average score”);
scanf(“%f”,&x);
if (x>100 || x<0)
printf(“input error”);
else if (x<=100 && x>=90)
printf(“excellent”);
else if ( x>=80)
printf(“good”);
else if ( x>=60)
printf(“middle”);
else printf(“bad”);
}
4.3 switch语句形式:
switch (表达式 e) {
case 常量表达式 exp1:语句序列 1;
case 常量表达式 exp2:语句序列 2;
……….
case 常量表达式 expn:语句序列 n;
default,语句序列 n+1;
}
说明,( 1)表达式 e为基本类型,各语句序列不需加 {};
( 2) default部分可省略;
( 3)常量表达式指在编译时(执行前)能确定值的表达式。
执行流程,计算表达式 e
语句序列 1
语句序列 n+1
语句序列 2
语句序列 n
e=exp1 真
e=exp2
e=expn
有 default
真真真起点终点说明:
语句 break可使流程从各语句序列直接转移到终点;
无 break时顺序执行执行
break
main()
{float x; int i;
printf(“input score”); scanf(“%f”,&x);
i=x/10; /*i的正确值应为,0至 10*/
if (i>10 || i<0) printf(“input error”);
else
switch ( i ) {
case 10:
case 9,printf(“excellent”); break;
case 8,printf(“good”); break;
case 7:
case 6,printf(“middle”); break;
default,printf(“bad”);
}
}
4.4 while语句问题:求 S=
解法 1,S=1+2+3+4+5+6+7+8+9+10;
不适合大规模运算解法 2:逐步累加 S
s=0;
s=s+ 1;
s=s+ 2;
……..
s=s+ 10;
10
1i
i
用 i控制其变化
s=0; i=1;
while (i<=10)
{ s=s+i;
i++;
}
while语句的形式,
while (表达式) 语句其中:
表达式可为任何类型;
语句为循环体,仅一条语句,
多条时用复合语句;
当表达式非 0时执行循环体,
注意:
为避免死循环,循环变量在循环开始前初始化,
表达式中应包括循环变量,循环体中修改,
最终可使表达式为 0,终止循环。
语句表达式非 0 0
例 1:求 S=
#include,stdio.h”
main()
{
int s,i;
s=0; i=1;
while (i<=10)
{ s=s+i;
i++;
}
printf(“s=%d”,s);
}
s+i?s
i<=10
非 0
0
开始结束
0?s;i?1
i+1?i
输出 s
10
1i
i
例 2,循环体中没有改变循环变量的值。死循环。
i=k=1;
while (i<4) {
k+=2*i;
printf(“i=%d,k=%d\n”,i,k);
}
例 3,循环变量的改变不能使循环控制表达式为 0。死循环。
i=4;
while (i<=4) {
putchar (?#?);
i--;
}
例 4:将来自标准输入文件的正文复制到标准输出文件中,
每次输入和复制一个字符。
分析:
正文以系统常量 EOF(输入时按 CTRL+Z)为结束标志的字符序列;
每次输入一个字符(输入条件),复制(输出)一个,
重复处理直到输入的字符为 EOF,典型的循环控制。
C≠EOF
非 0
0
开始结束输入字符 C
复制输出 C
C≠EOF
非 0
0
开始结束输入字符 C
复制输出 C
输入字符 C
改成当型循环
#include,stdio.h”
main()
{
char c;
printf(“input a text end of ctrl+z\n”);
c=getchar();
while(c!=EOF)
{
putchar(c );
c=getchar();
}
}
该程序执行时,输入一行,
显示一行,遇到有 EOF的行则显示完后程序终止,且 EOF后的字符不显示。
#include,stdio.h”
main() {
char c;
printf(“input a text end of ctrl+z\n”);
while((c=getchar())!=EOF)
putchar(c );
}
优化后的程序例 5:输入一行字符,按字母、数字和其它字符分成三类,
分别统计各类字符的数目(换行字符‘ \n?不统计在内)。
分析:
输入一行字符(输入条件),以换行字符‘ \n?作为结束标志,须逐个逐个输入字符,用一变量 C来表示;
统计的各类字符的数目(输出)分别用 alpha,digit、
others表示,统计初值都为 0;
统计时,逐个分析每次输入的 C的分类:
字母,c>=?a? && c<=?z? || c>=?A? && c<=?Z?
数字,c>=?0? && c<=?9?
循环加分支结构
C≠?\n?
非 0
0
开始结束输入字符 C
统计分类输入字符 C
初始化分类输出分类
C≠?\n?
非 0
0
开始结束输入字符 C
alpha加 1
输入字符 C
alpha=digit=other=0
输出分类
C是字母
C是字母
0
digit加 1 other加 1
非 0
非 0 0
细化求精例 6:求计算机的字长(机器字长)
main()
{ unsigned word; /*(有)无符号整数存储与机器字长有关 */
int n;
word=~0;
n=1;
while((word=word>>1)!=0) /*左右移动皆可 */
++n;
printf(“word-length=%d\n”,n);
}
4.5 do while 语句
while语句的形式,
do 语句 while (表达式)
其中:
表达式可为任何类型;
语句为循环体,仅一条语句,
多条时用复合语句;
当表达式非 0时继续执行循环体,
循环体至少执行一次。
语句表达式非 0
0
例:计算 sin x=x - — + — + — + …,直到最后一项的绝对值小于 10-7为止。
分析,在 math.h中已有 sinx的说明,x为弧度,此例用 do—
while 语句实现该函数。通项分析:
an=(-1)n+1 ——— n=1,2,3….,a n-1=(-1)n ——— n>1
a1=x,迭代初值迭代公式
an=an-1 —————— n>=2
x3 x5 x7
3! 5! 7!
x2n-1
(2n-1)!
x2n-3
(2n-3)!
- x2
(2n-2)(2n-1)
|an|>=10-7
非 0 0
开始结束
0?sum,1?n
sum+an?sum
n++,修改 an
x?an
输出结果输入 x,转换弧度
#include,stdio.h”
#include,math.h”
#define PI 3.14259
#define EPS 1e-7
main()
{ int n; double x,an,sum;
printf(“input a angle:”); scanf(“%lf”,&x);
x=x*PI/180; an=x;
sum=0; n=0;
do { sum+=an; n++;
an*=(-x*x)/(2*n-2)*(2*n-1);
} while (fabs(an)>=EPS);
printf(“sin(%.4lf)=%.4lf\n”,x,sum);
}
4.6 for语句功能最强、使用最灵活的循环语句。
for语句的一般形式
for(表达式 1;表达式 2;表达式 3) 语句说明:
表达式 1的作用通常给循环变量赋初值;
表达式 2的作用控制循环体是否执行;
表达式 3的作用通常修改循环变量。
三个表达式可省略,但分号不能省略。
表达式 2
非 0
0
表达式 1
语句表达式 3
例:求 S=
#include,stdio.h”
#define N 10
main()
{
int s,i;
s=0;
for(i=1;i<=N; i++)
s+=i;
printf(“s=%d”,s);
}
s+i?s
i<=10
非 0
0
开始结束
0?s;i?1
i+1?i
输出 s
10
1i
i
表达式的缺省:
( 1) s=0; i=1;
for( ; i<=N; i++)
s+=i;
( 2) s=0; i=1;
for( ; ; i++) /*表达式 2缺省相当于逻辑真 (1)*/
if (i <=N) s+=i;
else break;
( 3) for(s=0,i=1;i<=N;)
{ s+=i;
i++;
}
s+=i++;
例:输入一批整数,以 0为结束,输出其中最大的一个值。
分析:用“打擂台”的方式,先假设输入的第一个数为最大数,
以后每输入一个数,都和最大数比较,若比最大数大,则产生新的最大数。结束标记 0不参与比较。
#inlcude,stdio.h”
main()
{ int x,max;
printf(“input a group integer end of 0:\n”);
scanf(“%d”,&x); max=x;
while(x) { if (x>max) max=x;
scanf(“%d”,&x);
}
printf(“max=%d”,max);
}
x≠0
非 0
0
开始结束
x?max
x?max
输入整数 x
x>max
输入整数 x
非 0
0 输出 max
#inlcude,stdio.h”
main()
{ int x,max;
printf(“input a group integer end of,\n”);
scanf(“%d”,&x); max=x;
for( ; x!=0 ; )
{ if (x>max) max=x;
scanf(“%d”,&x);
}
printf(“max=%d”,max);
}
例:求 n!,n从终端。
分析,n! =1*2*3*…..*n 为连乘;
fac=1;
fac*= 1;
fac*= 2;
………
fac*= n;
为避免溢出,fac的类型可为:
long 或 unsigned long
#include,stdio.h”
main()
{ int n,i;
unsigned long fac;
printf(“input n:”);
fac=1;
for(i=1;i<=n;i++)
fac*=i;
printf(“%d!=%lu”,n,fac);
}
循环初值循环终值步长,1
例:输入一个大于或等于 2的整数 n,判断 n是否为一个素数。
分析:
若 n为合数,
n=n1*n2 (n1>1 且 n2>1)
则:在 2~ 中必然有一个 n的因子 i,
即 n%i ==0
否则,n1>,n2>
导致,n1*n2>n。
n
nn
#include,stdio.h”
#include,math.h”
main()
{ int n,i,j,r=1; /* r作标识使用,非 0表示 n为素数 */
do {
printf(“input a integer (>=2)”);
scanf(%d”,&,n);
} while (n<2); /* 重复输入 n,直到 n不小于 2为止 */
for(i=2,j=sqrt(n); r && i<=j; i++) /*测试 2 ~ 内的所有整数 */
r=n%i; /*一旦有因子,则 r为 0,n为合数,循环结束 */
if (r) /* r非 0表示 n为素数 */
printf(“%d is a prime”,n);
else
printf(“%d is not a prime”,n);
}
n
4.7 多重循环指循环体是一个循环语句,或循环体包含循环语句;
又称嵌套的循环;三种循环可互相任意嵌套。
二重循环:
for(i=1;i<10;i++)
for(j=1;j<i;j++)
printf(“%4d”,i*j));
三重循环:
while (… )
{……….
for(… ; …;…)
{ …….
do {…….
} while (…)
}
while (…) {….}
}
例:计算 s=11+22+33+…+n n,
n由终端输入。
i<=n
非 0
0
开始结束
0?s,1?i
输入整数 n
i++
输出 s
i<=n
非 0
0
开始结束
0?s,1?i
term*i?term
输入整数 n
j<=i
j++
非 0
0 输出 s
计算 ii?term
s+term?s
1?term,1?j
i++
s+term?s
#include,stdio.h”
main()
{ int i,j,n;
long s,term;
printf(“please input n?”);
scanf(“%d”,&n);
for(s=0,i=1; i<=n; i++)
{for(term=1,j=1; j<=i; j++) term*=i;
s+=term;
}
printf(“s=%d”,s);
}
内层循环体提示:
外、内层循环应用不同的循环变量,避免控制混乱。
外层循环体执行 n次,i的值依次为 1,2、。。。 n
内层循环,
i=1 内层循环体执行 1次,j的值依次为 1;
i=2 内层循环体执行 2次,j的值依次为 1,2;
i=3 内层循环体执行 3次,j的值依次为 1,2,3;
………
i=n 内层循环体执行 n次,j的值依次为 1,2、。。。 n;
内层循环体共执行 1+2+。。。 +n=n(n+1)/2次。
例:在屏幕正中(屏幕宽度为 80字符)输出下列形式的三角形,三角形的高度 n由输入确定,3≤n<10。例如输入 5,
则输出下面的图形。
1
2 2
3 3 3
4 4 4 4
5 5 5 5 5
40列 1*****
37列 2*****2*****
34列 3*****3*****3*****
31列 4*****4*****4*****4*****
28列 5*****5*****5*****5*****5*****
i<=n
非 0
0
开始结束
1?i
输入 n[3,10)
i++
40-3*(i-1)个空格输出 i个数字 i
#include,stdio.h”
main()
{ int i,j,n,w=6;
do { printf(“input n:”);
scanf(“%d”,&n);
} while (n<3 || n>9);
for(i=1;i<=n;i++)
{
printf(“%*c”,40-w/2*(i-1),);
for(j=1;j<=i;j++)
printf(“%-*c”,w,?0?+i);
putchar(?\n?);
}
}
for(e1;e2;e3)
{ …….
while (e)
{…..
if (exp) break;
……
}
……
}
……….
for(e1;e2;e3)
{ …….
if (exp) break;
……
}
……
4.8 转移语句和标号语句改变由三种基本结构语句预定的程序流程。
1,break语句用途,( 1)用于 switch语句从中途退出 switch语句;
( 2)用于退出循环。
例:打印 2~ 100之间的所有素数。
#include,stdio.h”
#include,math.h”
main()
{ int i,n,k,m=1;
for(k=0,n=2;n<100;n++)
{ for(i=2;i<=sqrt(n);i++) /*在 2 ~ sqrt(n)范围内找因子 */
if((m=n%i)==0) break; /*只要找到一个因子,就退出 */
if (m) { printf(“%6d”,n);
if(++k%10==0) printf(“\n”);
}
}
}
2,continue语句
for(e1;e2;e3)
{
…….
if (exp) continue;
……
}
例:输入 10个整数,输出其中正数的个数及平均值。
#include,stdio.h”
main()
{ int a,i,k,x;
printf(“input 10 integer:\n”);
for(a=i=k=0;i<10;i++)
{ scanf(“%d”,&x);
if (x<=0) continue;
a+=x; k++;
}
if (k)
printf(“numbers=%d,average=%f”,k,1.0*a/k);
3,goto语句无条件地转移到标号所指示的语句处。结构化程序设计不提倡使用 goto语句。 过多使用 goto语句容易降低程序的可读性。有些场合适当使用 goto语句能简化程序的复杂度。
main()
{ int i,s=0;
i=1;
l1,if (i<=10) goto l2;
s+=i;
i++;
goto l1;
l2,printf(“1+2+…+10=%d”,s);
}
用 goto语句模拟的 while循环,可读性较低。
4,return语句
#include <stdio.h>
void main(void)
{
int a,b,c;
a=10;
b=20
c=max(a,b);
printf(“max=%d\n”,c);
}
int max(int x,int y)
{
int z;
if (x>y)
z=x;
else
z=y;
return (z);
}
将 z的值传回,
程序控制转移