第三章 程序的控制结构
3.1 选择结构
3.2 循环结构
3.3 编译预处理问题提出,
计算分段函数:
y=
3-x x≤0
2/x x>0
解题的步骤:
输入 x
x≤0

y=3-x y=2/x
否输出 y的值
C语言提供的选择结构有两种,if语句,switch语句 。
3.1 选择结构
3.3.1 if 语句
if语句:对所给条件进行判定,根据判定结果决定是否执行程序段 。
语句形式:
if (表达式 ) {语句 };
语句执行流程,表达式语句真 (非 0)
假 (0)
例 3-1,读程序,理解数值作为 if 表达式
#include <stdio.h>
void main()
{ int i=10,m=3;
if(i!=0)
printf(“i is not 0\n”);
if(m)
printf(“i is not 0\n”);
}
程序运行结果:
i is not 0
i is not 0
例 3-2,读程序,理解” ==”与” =”的作用及区别
#include <stdio.h>
void main()
{ int m=10;
if(m==100)
printf(“m==%d”,m);
if(m=100)
printf(“m is assigned %d\n”,m);
}
程序运行结果:
m is assigned 100
if (表达式 ) {语句 1; }
else {语句 2; }
表达式语句 1
真 (非 0)
假 (0)
语句 2
3.3.1 if-else 语句
if-else 语句适合于解决双分支选择问题语句形式:
语句执行流程:
例 3-3,输入一个整数,判断该整数的奇偶性
#include <stdio.h>
void main()
{
int m;
printf(“input m:”);
scanf(“%d”,&m);
if(m%2==0)
printf(“%d 是偶数 \n”,m);
else
printf(“%d 是奇数 \n”,m);
}
输入 m
m%2==0
偶数结束真 假奇数例 3-4,读程序,理解浮点数的运算与比较
#include <stdio.h>
void main()
{
float f;
f=1.0; f=f/13.0; f=f*13.0;
if( f==1.0)
printf(,f is still 1.0\n”);
else
printf(,f isn?t still 1.0\n”);
}
程序运行结果:
f isn?t 1.0
注意:
有的 if-else语句可以用 条件运算符(?,) 来实现
if( a>b)
max=a’
else
max=b;
max=(a>b)?a,b;
例 3-5,输入一个英文字符,若为大写则改为小写,输出得到的字符。
#include <stdio.h>
void main()
{ char zm;
scanf(“%c”,&zm);
zm=(zm>=?A?&& zm<=?Z?)?(zm+32):zm) ;
printf(“%c”,zm);
}
程序运行结果:
B
b
if (表达式 1) 语句 1;
else if (表达式 2) 语句 2;
… …
else if (表达式 n)语句 n;
else 语句 n+1;
3.1.3 嵌套的 if-else 语句语句形式:
表达式 1
语句 1
真 (非 0)
假 (0)
语句 2
表达式 2
真 (非 0)
表达式 2
语句 n 语句 n+1
假 (0)
假 (0)
语句执行流程:
例 3-6,将 0~100分的百分制换算成 A~E的五级学分制。
#include <stdio.h>
void main()
{
int s;
scanf(“%d”,&s);
if(s>=90)
printf(“score is A \n”);
else if(s>=80)
printf(“score is B \n”);
程序运行结果:
84
B
else if(s>=70)
printf(“score is C \n”);
else if(s>=60)
printf(“score is D \n”);
else
printf(“score is e \n”);
}
例 3.7,计算分段函数,
假输入 x
X<0

X=0
y=1y=0y=-1
假真



y=
-1 (x<0)
0 (x=0)
1 (x>0)
#include <stdio.h>
void main()
{ int x,y;
scanf(" %f ",&x);
if (x<0) y=-1;
else if (x==0) y=0;
else y=1;
printf("x=%d,y=%d\n",x,y);
}
语句形式:
switch ( 表达式 )
{
case 常量 1,语句 1;
case 常量 2,语句 2;
case 常量 3,语句 3;
.......
case 常量 n,语句 n;
default,语句 n+1;
}
根据表达式的不同值
,选择不同的程序分支,又称开关语句 。
数值型或字符型常量表达式的值必须互不相同,否则执行时将出现矛盾,即同一个开关值,将对应多种执行方案。
千万不能接 (; )号
3.1.4 switch 语句语句执行流程:
指语句的最后一条是否为 break
简单语句或复合语句
break break
有无
break
有无有计算表达式常量 1 常量 2 常量 n
=
语句 1

= = =
语句 2 语句 n
其它
=
语句 n+1
无值
case语句出现的次序并不影响执行结果。
例 3-8,按照考试成绩等级打印出百分制分数段。
程序运行结果:
B
80~89
#include <stdio.h>
void main()
{ char grade;
scanf(" %c ",&grade);
switch( grade)
{ case?A?∶ printf(” 90~100\n”); break;
case?B?∶ printf (” 80~89\n”); break;
case?C?∶ printf (” 70~79\n”); break;
case?D?∶ printf (” 60~69\n”); break;
case?E?∶ printf (” 0~59\n”); break;
default∶ printf (“error\n”);
}
}
switch 的嵌套,switch语句允许嵌套,即 switch本身可以作为另一个层 switch语句的一部分
switch( i )
{ case 0:
switch ( j )
{ case 0:printf(“i==j”);break;
case 1:printf(“i<j”);
}
break;
case 1:
……,
}
switch几个注意点
1,if语句能测试关系和逻辑表达式,而 switch只能测试相等。
2,switch语句的每个 case后面的常熟必须是整型或字符型,在使用字符常量时。自动转换成整数。
3,switch语句中每个 case常熟必须不同。
在 C语言中有三种循环结构,while,do-while
和 for循环,利用 有关的运算符构造表达式,以控制循环的执行。
3.2 循环结构循环,就是在给定的条件成立时反复执行某一程序段,被反复执行的程序段称为循环体。
3.2.1 while语句真 (非零 )
表达式循环体假 (零 )
1,while 语句的形式,
while (表达式)
{循环体; }
2,while 语句 常称为,当型,循环语句。
3、说明,
先判断表达式,后执行语句。
表达式同 if语句后的表达式一样,可以是任何类型的表达式。
循环体多于一句时,用一对 { }括起 。
while循环结构常用于循环次数不固定,根据是否满足某个条件决定循环与否的情况。
例:分析下列程序段的循环次数
i=1;
while (i<=100)
putchar(?*?);
i++;
i=1;
while (i<=100)
{putchar(?*?);
i++;
}
例 3- 9,用 while编程实现 1~100的和。
#include <stdio.h>
void main()
{ int i,sum;
i=1;
sum=0 ;
while (i<=100)
{ sum=sum+i;
i++;
}
printf(″%d\n″,sum);
}
程序运行结果:
5050
例 3-10,用 while语句 计算 n!。
#include <stdio.h>
void main()
{ int n,m,temp;
scanf(“%d”,&n);
m=1;
temp=n;
while (n>=1)
{ m=m*n;
n--;
}
printf(“%d!=%d\n”,temp,m);
}
程序运行结果:
5
5!=120
注意表达式在判断前,必须要有明确的值。
循环体中一般有改变条件表达式的语句。
while (表达式 )后面没有分号。
3.2.2 do--while语句
1,do--while的形式:
do
{循环体;
} while (表达式);
2,do--while语句 常称为,直到型,循环语句。
真 (非零 )
表达式循环体假 (零 )
例 3-10,用 do-while编程实现 1~100的和。
#include <stdio.h>
void main()
{ int i,sum=0 ;
i=1;
do
{ sum=sum+i;
i++;
} while (i<=100);
printf(″%d\n″,sum);
}
程序运行结果:
5050
例 3-11,用 while语句 计算 5!。
#include <stdio.h>
void main()
{ int t=1,i=2;
do
{ t=t*i;
i++;
} while (i<=5);
printf(“5!=%d\n”,t);
}
程序运行结果:
5
5!=120
3、说明,
do-while语句 先 执行 语句,后判断 表达式 。
第一次条件为真时,while,do-while等价;第一次条件为假时,二者不同。
void main()
{
int i,sum=0;
scanf("%d",&i);
do
{ sum += i;
i++;
}while(i<=10);
printf("%d",sum);
}
void main()
{
int i,sum=0;
scanf("%d",&i);
while(i<=10)
{ sum += i;
i++;
}
printf("%d",sum);
}
在 if,while语句中,表达式后面都没有分号,而在 do-
while语句的表达式后面则必须加分号。
do-while和 while语句相互替换时,要注意修改循环控制条件 。
3.2.3 for语句
1,for的形式:
for (初始表达式 1;条件表达式 2;循环表达式 3)
{循环体 ;}
表达式 1:用于循环开始前为循环变量设置初始值 。
表达式 2:控制循环执行的条件,决定循环次数表达式 3:循环控制变量修改表达式 。
循环体语句,被重复执行的语句 。
表达式 3
计算表达式 1
循环体判断表达式 2
零非零
for的下一条语句
2、执行过程例 3- 13,用 for语句编程实现 1~100的和。
#include <stdio.h>
void main()
{ int i,sum=0;
for(i=1;i<=100;i++)
sum=sum+i ; printf(“%d\n”,
sum);
}
程序运行结果:
5050
例 3- 14,用 for语句编程计算 1~9的平方。
#include <stdio.h>
void main()
{ int i,j;
for(i=1,j=1;i<10;i++,j++)
printf(“%d*%d=%4d\n”,i,j,i*j);
}
注意:
三个表达式都可以是逗号表达式。
三个表达式都是任选项,都可以省略,但要注意省略表达式后,分号间隔符不能省略。
( 1)在进入累加前先给累加器赋初值(一般为 0);
( 2)用循环语句实现累加;
for(循环变量赋初值;循环条件;循环变量改变规律)
( 3)循环体语句的设计。
累加器当前值 =累加器原值 +循环变量当前值 ;
典型例题分析
【 例 】 求累加和 1+2+3+… +1000
基本方法,
属于,累加器,类型问题。
累加器赋初值思考,求偶数和
2+4+6+… +100
参考程序:
void main()
{ long int k,s;
s=0;
for(k=1;k<=1000;k++)
s=s+k;
printf(" s=%ld ",s);
}
累加
( 1) 给累乘器赋初值,一般为 1;
( 2) 用循环语句实现累乘;
for( 循环变量赋初值;循环条件;循环变量改变规律 )
( 3) 循环体设计 。
累乘器当前值 =累乘器原值 *循环变量当前值;
例,求累乘积。 如,1× 2× 3×,..× 100
基本方法,
属于,累乘器,类型问题。
累乘器赋初值思考,求 n!=1 × 2 × 3
× … n
参考程序:
void main()
{ double s=1;
int k;
for(k=1;k<=100;k++)
s=s*k;
printf(" s=%lf ",s);
}
累乘整数连乘结果一定是整数,而本例中结果数值相当大,用 long型都无法存放,因此将存放累乘结果的变量 s定义为 double型 。
在循环体语句中又包含有另一个完整的循环结构的形式,
称为循环的嵌套。如果内循环体中又有嵌套的循环语句,
则构成多重循环。
3.2.4 循环的嵌套嵌套在循环体内的循环体称为内循环,外面的循环称为外循环。
while,do-while,for三种循环都可以互相嵌套。
下面几种都是合法的形式:
(1) while( ) (2) do (3) for(;;)
{… {… {
while( ) do for(;;)
{…} {… } {… }
} while( ); }
} while( );
(4) while( ) (5) for(;;) (6) do
{… {… {…
do{…} while( ) for(;;){ }
while( ) { } …
{…} … }
} } while( )
循环语句之间的关系
for(...)
{...
for(...)
{...
}
...
}
内循环外循环
for(....)
{...
}
for(...)
{...
}
并列循环嵌套循环真真外循环初始条件内循环初始条件内循环体外循环条件假内循环条件 假内循环循环条件外循环循环条件循环结束二重循环嵌套结构执行流程例 3-15 编程输出如下形式的九九乘法表
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
2 4 6 8 10 12 14 16 18
3 6 9 12 15 18 21 24 27
4 8 12 16 20 24 28 32 36
5 10 15 20 25 30 35 40 45
6 12 18 24 30 36 42 48 54
7 14 21 28 35 42 49 56 63
8 16 24 32 40 48 56 64 72
9 18 27 36 45 54 63 72 81
#include <stdio.h>
void main()

int i,j;
for (i=1; i<=9; i++)
printf(“%4d”,i); /*打印表头,第一行 */
printf ("\n");
for (i=1; i<=36;i++)
printf ("%c",'-');
printf ("\n");
for (i=1;i<=9; i++) /*被乘数 i从 1变到 9*/
{ for (j=1; j<=9;j++) /*乘数 j从 1变到 9*/
printf (“%4d”,i*j); /*输出第 i行 j列的值 i*j*/
printf (“\n”); /*换行,打印下一行 */
}

1.break语句
3.2.5 break语句和 continue语句
(1) 语句形式,
break;
(2)作用,
结束 break所在的 switch语句。
结束当前循环,跳出 break所在的循环结构。
例 3-16,计算半径为 1,2…8 的圆面积,但当面积大于
100时结束计算。
#include <stdio.h>
void main()
{ int r;
float area;;
for(r=1;r<=8;r++)
{ area=3.14i*r*r;
if(area>100)
break;
printf(“%\n”,area);
}
}
程序运行结果:
3.140000
12.560000
28.260000
50.240002
78.500000
例 3-17,break语句用法示例
#include <stdio.h>
void main()
{ int i;
for(i=0;i<=6;i++)
{ printf(“%d\n”,i);
if(i==5) break;
}
}
程序运行结果:
0
1
2
3
4
5思考:为什么不输出 6
( 1)语句形式,
continue;
( 2)语句作用,
结束 本次循环 。
2,continue 语句
( 3)语句执行流程,
continue语句可以结束本次循环,即不再执行循环体中 continue 语句之后的语句,转入下一次循环条件的判断与执行。
例 3-18,continue语句用法示例
#include <stdio.h>
void main()
{ int i;
for(i=0;i<=6;i++)
{
if(i==5) continue;
printf(“%d\n”,i);
}
}
程序运行结果:
0
1
2
3
4
5
6
例 3-19,输出 1~50之间不能被 3整除的数。
#include "stdio.h"
void main()
{int n;
for(n=0;n<=50;n++)
{if(n%3==0) continue;
printf(,%d",n);
}
}
while(条件 )
{ 语句 A;
break;
语句 B;
}
真语句 B
条件语句 A
break
假结束循环
3,break语句与 continue语句的区别至此位置
while(条件 )
{ 语句 A;
continue;
语句 B;
}
真语句 B
条件语句 A
continue
假结束循环至此位置
#include "stdio.h"
void main()
{int a,b;
for(a=1,b=1; a<=10; a++)
{if(b>=10) break;
if(b%3==1)
{b+=3; continue;}
}
printf("%d\n",a);
}
【 例 】 分析以下程序的运行结果。
3.3 编译预处理
– 作用,对源程序编译之前做一些处理,生成扩展 C
源程序
– 种类
宏替换 #define
文件包含 #include
条件编译 #if--#else--#endif等
– 格式:
,#”开头
占单独书写行
语句尾不加分号
3.3.1 宏替换
– 不带参数宏定义
一般形式,#define 宏名 [宏体 ]
功能,用指定标识符 (宏名 )代替字符序列 (宏体 )
宏展开:预编译时,用宏体替换宏名 ---不作语法检查
#include <stdio.h>
#define PI 3.1415926
void main()
{float l,s,r,v;
printf("input radius:");
scanf("%f",&r);
l=2.0*PI*r;
s=PI*r*r;
v=4.0/3*PI*r*r*r;
printf("l=%10.4f\ns=%10.4f\nv=%10.4f\n",l,s,v);
}
程序运行结果:
l= 25.1327
s= 50.2655
v= 150.7964
– 带参数宏定义
一般形式,#define 宏名 (参数表 ) 宏体例 #define S (r) PI*r*r
相当于定义了不带参宏 S,代表字符串,(r) PI*r*r”
宏展开,形参用实参换,其它字符保留
宏体及各形参外一般应加括号 ()
例 #define S(a,b) a*b
………,.
area = S(3,2);
宏展开,area = 3*2;
不能加空格
#include <stdio.h>
#define PI 3.1415926
#define S(r) PI*r*r
void main()
{float a,Area;
scanf(“a=%f”,&a);
Area=S(a);
printf("Area=%f\n",a,Area);
}
运行情况如下:
a=3.6
Area=40.715038
例 3-21 用带参数宏实现圆面积的计算赋值语句,area=S(a);,经 宏展开 后为:
area=3.1415926*a *a;
(1)带参的宏只是进行简单的字符替换;而函数调用是先求出实参值,然后代入形参。
(2)宏展开则是在编译前进行的,展开时并不分配内存单元,不进行值的传递处理,也没有,返回值,的概念;而函数调用是在程序运行时处理的,为形参分配临时的内存单元。
(3) 宏不存在类型问题,宏名无类型,其参数也无类型,只是一个符号代表,展开时代入指定字符串即可。宏定义时,字符串可以是任何类型的数据;而对函数中的实参和形参类型要求一致。
(4)宏可以设法得到多个结果,而调用函数只可得到一个返回值。
(5) 宏展开后源程序变长,而函数调用不会使源程序变长。
(6) 宏替换不占运行时间,只占编译时间。而函数调用则占运行时间(分配单元、保留现场、值传递、返回)。
带参数的宏和第 7章函数的区别:
#include <stdio.h>
#define PI 3.1415926
#define CIRCLE(R,L,S,V)
L=2*PI*R;S=PI*R*R;V=4.0/3.0*PI*R*R*R
void main()
{ float r,l,s,v;
scanf("%f",&r);
CIRCLE(r,l,s,v);
s=PI*r*r;
v=3.0/4*PI*r*r*r;
printf("r=%6.2f,l=%6.2f,s=%6.2f,v=%6.2f\n",r,l,s,v
);
}
例 3-22 返回多个结果的宏。
3.2.2,文件包含,处理
– 功能,一个源文件可将另一个源文件的内容全部包含进来
– 一般形式,#include,文件名,
或 #include <文件名 >
#include,file2.c”
file1.c
file2.c
file1.c
file2.c
A
B
A
– 处理过程,预编译时,用被包含文件的内容 取代该预处理命令,再对,包含,后的文件作一个源文件编译
< > 直接按标准目录搜索
,” 先在 当前目录 搜索,再搜索标准目录可指定路径例 3-22 文件包含示例程序
(1)将格式宏做成头文件 format.h
#include <stdio.h>
#define PR printf
#define NL "\n"
#define R "%d"
#define R1 D NL
#define R2 D D NL
#define R3 D D D NL
#define S "%s"
(2)主文件 file1.c
#include <stdio.h>
# include "format.h"
void main()
{ int a,b,c;
char str[]=“china";
a=1;b=2;c=3;;
PR(R1,a);
PR(R2,a,b);
PR(R3,a,b,c);
PR(S,str);
}
程序运行结果:
12
123
china