第4章 程序的控制结构_第1页
第4章 程序的控制结构_第2页
第4章 程序的控制结构_第3页
第4章 程序的控制结构_第4页
第4章 程序的控制结构_第5页
已阅读5页,还剩84页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第4章程序的控制结构C程序设计语言1内容提要算法的描述方法基本控制结构基本控制语句常用算法,如累加、累乘、统计、递推、迭代、穷举等结构化程序设计的基本思想C程序结构C程序源程序文件1源程序文件2源程序文件3编译预处理命令全局变量声明函数1函数n…函数首部函数体局部变量声明执行语句什么是结构化程序设计?StructuredProgramming,简称SP1965年,最早由E.W.Dijkstra在一次国际会议上提出1966年,C.Bohm和G.Jacopini首先证明了:只用顺序、选择、循环三种基本的控制结构就能实现任何单入口、单出口的程序给结构化程序设计奠定了基础1971年,IBM公司的Mills提出:程序应该只有一个入口和一个出口进一步补充了结构化程序的规则什么是结构化程序设计?目前,还没有一个严格的定义1974年,D.Gries教授将已有的对结构化程序设计的不同解释归纳为13种。一个比较流行的定义是:结构化程序设计是一种进行程序设计的原则和方法,它避免使用goto语句,采用“自顶向下、逐步求精”方法进行程序设计,按照这种原则和方法设计出的程序的特点为:结构清晰容易阅读容易修改容易验证糟糕的gotoSTART_LOOP:if(fStatusOk){

if(fDataAvaiable)

{i=10;

gotoMID_LOOP;}

else

{

gotoEND_LOOP;}}else

{

for(i=0;i<100;i++)

{MID_LOOP://lotsofcodehere

}

gotoSTART_LOOP;}END_LOOP:什么是结构化程序设计?不能简单的认为避免使用goto语句的程序设计方法就是结构化程序设计方法用goto跳向共同的出口位置`voidInit(void){

char*p1=NULL;

char*p2=NULL;

char*p3=NULL; p1=(char*)malloc(256);

if(p1==NULL)

goto

Exit;

p2=(char*)malloc(256);

if(p2==NULL)

goto

Exit;

p3=(char*)malloc(256);

if(p3==NULL)

goto

Exit;

/*正常处理的代码*/Exit:

if(p1!=NULL)

free(p1);

if(p2!=NULL)free(p2);if(p3!=NULL)

free(p3);

return;}结构化程序设计关注的焦点结构化程序设计关注的焦点程序结构的好坏有无goto,并不是程序结构好坏的标志限制和避免使用goto,只是得到结构化程序的一个手段,而不是我们的目的结构化程序设计的核心思想采用顺序、选择和循环三种基本结构作为程序设计的基本单元只有一个入口;只有一个出口;无死语句,即不存在永远都执行不到的语句;无死循环,即不存在永远都执行不完的循环。采用“自顶向下、逐步求精”和模块化的方法进行结构化程序设计什么是结构化程序设计?结构化程序设计语言按照结构化程序设计的要求设计出的语言结构化程序利用结构化程序设计语言或按照结构化程序设计思想编制出的程序如何设计结构化的程序?Top-down,Stepwiserefinement自顶向下、逐步求精1971年,wirth提出的结构化程序设计方法先全局后局部先整体后细节先抽象后具体自顶向下、逐步求精的

结构化程序设计方法BAA2A1B2B1A12A11A22A21B12B11B22B21算法的概念

数据结构+算法=程序只对面向过程的语言(C)成立面向对象程序=对象+消息算法:为解决一个具体问题而采取的确定的有限的操作步骤,仅指计算机能执行的算法算法的特性

有穷性在合理的时间内完成确定性,无歧义

如果x≥0,则输出Yes;如果x≤0,则输出No;有效性

能有效执行负数开平方没有输入或有多个输入

有一个或多个输出

算法的分类

数值运算算法:解决求数值解问题非数值运算算法:需要用分析推理、逻辑推理才能解决的问题例如人工智能中的许多问题,查找、分类等算法的表示方法自然语言表示传统的流程图表示在1966年,Bohra与Jacopini提出N-S结构化流程图表示1973年,美国学者I.Nassi和B.Shneiderman提出伪代码表示起止框输入框判断框处理框流程线连接点注释框BANS图传统流程图顺序结构BABN如果

成绩<60

那么

通知补考否则

告知你考试成绩AY条件PABNY条件P分支结构(选择结构)当型循环A真假假条件P循环结构A当P成立直到型循环条件PA假真循环结构A直到P为假A条件PA当型循环直到型循环真假假条件P假真循环结构复合语句{}括住的若干条语句构成一个语句块,称为复合语句语句块内可以定义变量变量仅在定义它的复合语句内有效变量必须在复合语句的开头定义复合语句可以用在任何可以使用语句的地方if-else选择结构的一种最常用形式if(表达式)

{

语句1;

} else

{

语句2;

}语句3表达式值非0时,执行语句1,然后语句3;表达式值为0时,执行语句2,然后语句3{

语句1;

}

{

语句2;

}

if-elseelse部分可以没有if(表达式)

{

语句1;

} 语句3if-else嵌套使用时,注意else和谁配对的问题当表达式值为0时,直接执行语句3{

语句1;

}

例4.4:年龄判断#include<stdio.h>main(){

intyourAge,hisAge; printf("Pleaseenteryourage:"); scanf("%d",&yourAge);/*输入你的年龄yourAge*/ printf("Pleaseenteryourfriend'sage:"); scanf("%d",&hisAge);/*输入你朋友的年龄hisAge*/

if(yourAge>=hisAge) { printf("Youareolder!Yourageis=%d\n",yourAge); }

else

{ printf("Yourfriendisolder!Hisageis=%d\n",hisAge); }}条件表达式含义:如果表达式1的值非0(为真),则该条件表达式的结果就是表达式2的值否则,是表达式3的值

表达式3N表达式2Y表达式1表达式1?表达式2:表达式3例4.4:年龄判断#include<stdio.h>main(){

intyourAge,hisAge; printf("Pleaseenteryourage:"); scanf("%d",&yourAge);/*输入你的年龄yourAge*/ printf("Pleaseenteryourfriend'sage:"); scanf("%d",&hisAge);/*输入你朋友的年龄hisAge*/

max=(yourAge>=hisAge)?yourAge:hisAge;

printf("Theolderageis=%d\n",max);}else-ifif的一种扩展形式——相当于else分支嵌套if(表达式1)

语句1;

elseif(表达式2)

语句2;

elseif(表达式3)

语句3;

…………

else

语句4;

语句5;表达式1

语句1语句2语句3语句4表达式2表达式3

图4-9多分支选择结构语句1;语句2;语句3;语句4;例4.5:体型判断按“体指数”对肥胖程度进行划分:

体指数t=w/h2

(体重w单位为公斤,身高h单位为米)当t<18时,为低体重;当18≤t<25时,为正常体重;当25<t<27时,为超重体重;当t≥27时,为肥胖。编程从键盘输入你的身高h和体重w,根据给定公式计算体指数t,然后判断你的体重属于何种类型。用3种方法编程:算法1:用不带else子句的if语句编程算法2:用在if子句中嵌入if语句的形式编程算法3:用在else子句中嵌入if语句的形式编程例4.5用不带else子句的if语句编程#include<stdio.h>main(){

floath,w,t; printf("Pleaseenterh,w:"); scanf("%f,%f",&h,&w); t=w/(h*h);

if(t<18) { printf("t=%f\tLowerweight!\n",t); }

if(t>=18&&t<25) { printf("t=%f\tStandardweight!\n",t); }

if(t>=25&&t<27) { printf("t=%f\tHigherweight!\n",t); }

if(t>=27) { printf("t=%f\tToofat!\n",t); }}当t<18时,为低体重;当18≤t<25时,为正常体重;当25<t<27时,为超重体重;当t≥27时,为肥胖。例4.5用在if子句中嵌入if语句的形式编程

#include<stdio.h>main(){

floath,w,t; printf("Pleaseenterh,w:"); scanf("%f,%f",&h,&w); t=w/(h*h);

if(t<27) {

if(t<25) {

if(t<18)printf("t=%f\tLowerweight!\n",t);

elseprintf("t=%f\tStandardweight!\n",t); }

elseprintf("t=%f\tHigherweight!\n",t); }

elseprintf("t=%f\tToofat!\n",t);}182527当t<18时,为低体重;当18≤t<25时,为正常体重;当25<t<27时,为超重体重;当t≥27时,为肥胖。例4.5用在else子句中嵌入if语句的形式编程

#include<stdio.h>main(){

floath,w,t; printf("Pleaseenterh,w:"); scanf("%f,%f",&h,&w); t=w/(h*h);

if(t<18)

printf("t=%f\tLowerweight!\n",t);

elseif(t<25) printf("t=%f\tStandardweight!\n",t);

elseif(t<27) printf("t=%f\tHigherweight!\n",t);

else printf("t=%f\tToofat!\n",t);}当t<18时,为低体重;当18≤t<25时,为正常体重;当25<t<27时,为超重体重;当t≥27时,为肥胖。182527switch多路选择switch(表达式){

case

常数1:

语句序列1;

case

常数2:

语句序列2;

…………

default:

语句序列3;

}default可以没有,但最好不省略不要忘记break语句序列1;语句序列2;语句序列n;例4.8:计算器程序编程设计一个简单的计算器程序,要求根据用户从键盘输入如下形式的表达式:操作数1运算符op操作数2

然后,计算并输出表达式的值指定的运算符为加(+)减(-)乘(*)除(/)main(){

intdata1,data2;/*定义两个操作符*/

charop;/*定义运算符*/ printf("Pleaseentertheexpression:"); scanf("%d%c%d",&data1,&op,&data2);/*输入运算表达式*/

switch(op) {

case'+':/*处理加法*/ printf("%d+%d=%d\n",data1,data2,data1+data2);

break;

case'-':/*处理减法*/ printf("%d-%d=%d\n",data1,data2,data1-data2);

break;

case'*':/*处理乘法*/ printf("%d*%d=%d\n",data1,data2,data1*data2);

break;

case'/':/*处理除法*/

if(0==data2) printf("Divisionbyzero!\n");

else

printf("%d/%d=%d\n",data1,data2,data1/data2);

break;

default: printf("Unknownoperator!\n"); }}例4.8思考题语句if(0==data2)的必要性1998年11月《科学美国人》杂志,描述了美国导弹巡洋舰约克敦号上的一起事故,除零错导致军舰推进系统的关闭如果要求程序能进行浮点数的算术运算,语句if(0==data2)还能用于比较实型变量data2和常数0的大小吗?if(fabs(data2)<=1e-7)如果要求输入的算术表达式中的操作数和运算符之间可以加入任意多个空格符,那么程序如何修改?scanf("%d%c%d",&data1,&op,&data2);scanf("%d%1s%d",&data1,&op,&data2);取绝对值函数作业P143~152习题4.7,4.9循环——while语句,for语句while(表达式)

{

语句;}for(表达式1;表达式2;表达式3)

{

语句;}语句;语句;while语句while(表达式)

{

语句;}只要表达式的值为非0,就重复执行语句,直到表达式值为0时止语句真假假表达式语句;for语句for(表达式1;表达式2;表达式3)

{

语句;}首先执行表达式1。如果表达式2的值为非0,就重复执行语句和表达式3,直到表达式2的值为0时止语句;循环起始条件循环结束条件循环增量for语句for(表达式1;表达式2;表达式3)

{

语句;}相当于:

表达式1和表达式3可以没有或者是用逗号分隔的多个表达式的组合。但最好不要有太多的表达式组合语句;

表达式1;

while(表达式2){

语句;

表达式3;

}do-while语句do

{

语句;

}while(表达式);首先执行语句,然后判断表达式的值。如果表达式为0,继续向下执行,否则,再次执行语句,再次判断表达式的值语句会被至少执行一次表达式语句假真语句;条件PA当型循环直到循环真假假条件PA假真假条件P条件PA假当循环条件第一次就为假时选择三种循环的一般原则如果循环次数已知,用for如果循环次数未知,用while如果循环体至少要执行一次,用do-while这只是“一般”原则,不是“原则”注意在for和while语句之后一般没有分号有分号表示循环体就是分号之前的内容(空循环体)while(i<100);

i++;for(i=0;i<100;i++);

printf("%d",i);for通常有一个循环变量控制循环的次数,不要在循环体内改变这个变量现场编程计算1+2+…+100=?分别用如下语句编程forwhiledo-while循序渐进式编程

——例4.6:猜数游戏想一个1~100之间的数猜对:right猜错:wrong并提示大小只猜1次直到猜对为止最多猜10次猜多个数10次猜不对就猜下一个数循序渐进式编程

——例4.6:猜数游戏猜数游戏用到的库函数怎样模拟计算机“想”一个数呢?随机函数rand()产生[0,RAND_MAX]

之间的随机数magic=rand();#include<stdlib.h>RAND_MAX在stdlib.h中定义,不大于双字节整数的最大值32767产生[0,b-1]之间的随机数magic=rand()%b;产生[a,a+b-1]之间的随机数magic=rand()%b+a;#include<stdlib.h>#include<stdio.h>

main(){

intmagic;/*计算机"想"的数*/

intguess;/*人猜的数*/

magic=rand()%100+1;/*“想”一个[1,100]之间的数magic*/ printf("Pleaseguessamagicnumber:"); scanf("%d",&guess);

if(guess>magic) {printf("Wrong!Toohigh!\n"); }

elseif(guess<magic) {printf("Wrong!Toolow!\n"); }

else

{ printf("Right!\n"); printf("Thenumberis:%d\n",magic); }}只猜1次#include<stdlib.h>#include<stdio.h>main(){

intmagic;

intguess;

intcounter;/*记录人猜次数的计数器变量*/ magic=rand()%100+1;

counter=0;/*计数器变量count初始化为0*/

do{ printf("Pleaseguessamagicnumber:"); scanf("%d",&guess);

counter++;/*计数器变量count加1*/

if(guess>magic) printf("Wrong!Toohigh!\n");

elseif(guess<magic) printf("Wrong!Toolow!\n");

}while(guess!=magic);

printf("Right!\n"); printf("counter=%d\n",counter);}直到猜对为止#include<stdlib.h>#include<stdio.h>main(){

intmagic;

intguess;

intcounter;

magic=rand()%100+1; counter=0;

do{ printf("Pleaseguessamagicnumber:"); scanf("%d",&guess); counter++;

if(guess>magic) printf("Wrong!Toohigh!\n");

elseif(guess<magic) printf("Wrong!Toolow!\n"); }while((guess!=magic)&&(counter<10));

printf("Right!\n"); printf("counter=%d\n",counter);}最多猜10次例4.11:国王的许诺相传国际象棋是古印度舍罕王的宰相达依尔发明的。舍罕王十分喜欢象棋,决定让宰相自己选择何种赏赐。这位聪明的宰相指着8×8共64格的象棋盘说:陛下,请您赏给我一些麦子吧,就在棋盘的第一个格子中放1粒,第2格中放2粒,第3格放4粒,以后每一格都比前一格增加一倍,依此放完棋盘上的64个格子,我就感恩不尽了。舍罕王让人扛来一袋麦子,他要兑现他的许诺。

国王能兑现他的许诺吗?试编程计算舍罕王共要多少麦子赏赐他的宰相,这些麦子合多少立方米?(已知1立方米麦子约1.42e8粒)

总粒数为:sum=1+2+22+23+…+263

例4.11方法1#defineCONST1.42e8#include<stdio.h>#include<math.h>main(){

intn;

doubleterm,sum=0;/*累加求和变量赋初值*/

for(n=1;n<=64;n++){

term=pow(2,n-1);

/*根据累加项的规律计算累加项

*/sum=sum+term;/*作累加运算*/}

printf("sum=%e\n",sum);/*打印总麦粒数*/

printf("volum=%e\n",sum/CONST);/*折合总麦粒体积数*/}

例4.11方法2#defineCONST1.42e8#include<stdio.h>main(){

intn;

doubleterm=1,sum=1;/*累乘求积累加求和变量赋初值*/

for(n=2;n<=64;n++){

term=term*2;/*根据后项总是前项的2倍计算累加项*/sum=sum+term;/*作累加运算*/}

printf("sum=%e\n",sum);/*打印总麦粒数*/

printf("volum=%e\n",sum/CONST);/*折合总麦粒体积数*/}

作业P143~152习题4.12,4.16,4.18嵌套循环使用嵌套的循环体时,应注意以下问题

在嵌套的各层循环体中,使用复合语句(即用一对大花括号将循环体语句括起来)保证逻辑上的正确性

内层和外层循环控制变量不应同名,以免造成混乱

嵌套的循环最好采用右缩进格式书写,以保证层次的清晰性

自己阅读P278-283,代码风格问题,网站上代码规范的ppt循环嵌套不能交叉,即在一个循环体内必须完整的包含着另一个循环

例4.14:打印乘法九九表

例4.14#include<stdio.h>main(){

intm,n;

for(m=1;m<10;m++) printf("%4d",m);/*打印表头*/ printf("\n");

for(m=1;m<10;m++) printf("-"); printf("\n");

for

(m=1;m<10;m++)

{

for

(n=1;n<10;n++) { printf("%4d",m*n); } printf("\n"); }}例4.15:打印下三角乘法九九表

#include<stdio.h>main(){

intm,n;

for(m=1;m<10;m++) printf("%4d",m);/*打印表头*/ printf("\n");

for(m=1;m<10;m++) printf("-"); printf("\n");

for

(m=1;m<10;m++)

{

for

(n=1;

n<=m;n++) { printf("%4d",m*n); } printf("\n"); }}例4.15例4.16:马克思手稿中的趣味数学题有30个人,其中有男人、女人和小孩,在一家饭馆里吃饭共花了50先令,每个男人各花3先令,每个女人各花2先令,每个小孩各花1先令,问男人、女人和小孩各有几人?

解方程组穷举法例4.16方法1:

采用三重循环穷举x,y,z的全部可能的组合

#include<stdio.h>main(){

intx,y,z;

printf("Man\tWomen\tChildern\n");

for(x=0;x<=30;x++)

for(y=0;y<=30;y++)

for(z=0;z<=30;z++)

if(x+y+z==30&&3*x+2*y+z==50)

printf("%3d\t%5d\t%8d\n",x,y,z);}

例4.16方法2:改进算法

#include<stdio.h>

main(){

intx,y,z;

printf("Man\tWomen\tChildern\n");

for(x=0;x<=16;x++)

for(y=0;y<=25;y++){

z=30–x-y;

if(3*x+2*y+z==50)

printf("%3d\t%5d\t%8d\n",x,y,z);}}

作业P143~152习题4.20,4.21,4.22,4.25,4.27,4.28流程的转移控制break语句continue语句goto语句break和continue对for、while、do-while循环进行内部手术break,退出一层循环或者switchcontinue,中断此次循环体的执行,开始下一次break和continue少用为妙break和continue假假真真break表达式1表达式2循环语句的下一条语句循环语句的下一条语句假假真真

表达式1表达式2continue例4.17:单步运行演示break语句和continue语句的用法区别#include<stdio.h>main(){

inti,n;

for(i=1;i<=5;i++) { printf("Pleaseentern:"); scanf("%d",&n);

if(n<0)

break; printf("n=%d\n",n); } printf("Programisover!\n");}Pleaseentern:10↙n=10Pleaseentern:-10↙Programisover!例4.17:单步运行演示break语句和continue语句的用法区别#include<stdio.h>main(){

inti,n;

for(i=1;i<=5;i++) { printf("Pleaseentern:"); scanf("%d",&n);

if(n<0)

continue; printf("n=%d\n",n); } printf("Programisover!\n");}Pleaseentern:10↙n=10Pleaseentern:-10↙Pleaseentern:20↙n=20Pleaseentern:-20↙Pleaseentern:30↙n=30Programisover!标号举例error:goto举例gotoerror;一般形式

goto语句标号;……

语句标号:……或语句标号:…………goto语句标号;goto与标号(label)是goto的过错?还是程序员的过错?破坏了结构化设计风格容易带来错误隐患

gotonext;

intsum=0;/*被goto跳过*/…next:Evilgoto’s?MaybeNot…

凌波微步,未必摔跤现代观点认为:混乱根源不在goto,而在标号任何程序都可以不用goto就实现其功能但在某些情况下,使用goto可以让程序更清晰两种适合使用goto的情况跳向共同的出口位置,进行退出前的处理工作跳出多重循环的一条捷径{…{…{…gotoerror;}}}使用goto的原则主张少用、慎用,而不是禁用保证使用之后,程序仍然是单入口,单出口不要使用一个以上的标号不要用goto往回跳,要向下跳不要让goto制造出永远不会被执行的代码其他流程转移控制return语句将在第5章讲解标准库函数exit()

作用是终止整个程序的执行,强制返回操作系统调用该函数需要嵌入头文件<stdlib.h>例4.19:输入一个整数,判断它是否是素数

goto语句例4.19:方法1#include<math.h>main(){

intm,i,k;

printf("Pleaseenteranumber:");

scanf("%d",&m); k=sqrt(m);

for(i=2;i<=k;i++) {

if(m%i==0) {

printf("No!\n");

gotoend; } }

printf("Yes!\n");end:

printf("Programisover!\n");}Pleaseenteranumber:

6

Programisover!No!#include<math.h>main(){

intm,i,k;

printf("Pleaseenteranumber:");

scanf("%d",&m); k=sqrt(m);

for(i=2;i<=k;i++) {

if(m%i==0) {

printf("No!\n");

gotoend; } }

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论