函数和结构化编程课件_第1页
函数和结构化编程课件_第2页
函数和结构化编程课件_第3页
函数和结构化编程课件_第4页
函数和结构化编程课件_第5页
已阅读5页,还剩89页未读 继续免费阅读

付费下载

下载本文档

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

文档简介

函数和结构化编程学习目标1.掌握源程序结构中函数的组织方法;2.理解结构化程序设计思想,并能利用它来解决问题;3.理解函数嵌套调用的概念,并能熟练利用函数的嵌套调用来解决问题;4.理解递推、递归及其算法实现;5.理解编译预处理的概念,能熟练应用宏定义和文件包含;6.了解用户自定义库模块。7.1结构化编程结构化程序设计(StructuredProgramming)是一种良好的程序设计技术,它由著名计算机科学家E·W·Dijkstra于1969年提出7.1.1自顶向下分析问题自顶向下分析问题就是把一个较大的复杂问题分解成几个小问题后再解决。

待解决的问题模块2模块1模块3模块2.1模块2.27.1.2模块化设计模块化设计时要遵循模块独立性的原则,即模块之间的联系应该尽量简单。具体体现在:1.一个模块只完成一个指定的功能2.模块间只通过参数进行调用3.一个模块只有一个入口和一个出口4.模块内慎用全局变量在C语言中,模块一般通过函数来实现,一个模块对应一个函数。7.1.3结构化编码经模块化设计后,每个模块都可以独立编码。编程时应选用顺序、选择和循环3种控制结构,并使程序具有良好的风格。1.见名知义命名对象名2.使用注释3.使程序结构清晰4.使程序具有良好的交互性例:读入一组整数存入一个整型数组中,要求显示出计数、当前整数、当前数为止的所有整数之和、当前数为止的最小整数以及当前数为止的最大整数。除此之外,假设必须要显示如下所示的标题及标题下方分列显示的信息。*******************************************************

runningsums,minimums,andmaximums*******************************************************CountItemSumMinimumMaximum预处理命令/函数原型声明/主函数:#include<stdio.h>#include<stdlib.h>voidprn_banner(void); /*函数声明*/voidprn_headings(void); /*函数声明*/voidread_and_prn_data(void); /*函数声明*/voidmain(void){prn_banner();

prn_headings();

read_and_prn_data();}显示标题函数:voidprn_banner(void){printf("\n***************************************************");printf("\nrunningsums,minimums,andmaximums");printf("\n***************************************************\n");}显示各列上部的标题函数:voidprn_headings(void){printf("%5s%12s%12s","Count","Item","Sum");printf("%12s%12s\n\n","Minimum","Maximum");}初始化数据并按要求显示函数:voidread_and_prn_data(void){inti,sum,smallest,biggest;inta[10]={1,2,6,7,0,-6,19,52,10,-10};sum=0;smallest=biggest=a[0];for(i=0;i<10;i++){sum+=a[i];smallest=min(a[i],smallest);biggest=max(a[i],biggest);printf("%5d%12d%12d%12d%12d\n",i+1,a[i],sum,smallest,biggest);}}#include<stdio.h>

/*预处理命令/函数原型声明/主函数:

*/#include<stdlib.h>voidprn_banner(void);/*函数声明*/voidprn_headings(void);/*函数声明*/voidread_and_prn_data(void);/*函数声明*/voidmain(void){prn_banner();

prn_headings();

read_and_prn_data();getch();}/*显示标题函数:*/voidprn_banner(void){printf("\n***************************************************");

printf("\nrunningsums,minimums,andmaximums");

printf("\n***************************************************\n");}/*显示各列上部的标题函数:*/voidprn_headings(void){printf("%5s%12s%12s","Count","Item","Sum");

printf("%12s%12s\n\n","Minimum","Maximum");}/*初始化数据并按要求显示函数:*/voidread_and_prn_data(void){inti,sum,smallest,biggest;

inta[10]={1,2,6,7,0,-6,19,52,10,-10};

sum=0;smallest=biggest=a[0];

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

{sum+=a[i];

smallest=min(a[i],smallest);

biggest=max(a[i],biggest);

printf("%5d%12d%12d%12d%12d\n",i+1,a[i],sum,smallest,biggest);

}

}7.2函数的嵌套调用main函数调用a函数结束a函数调用b函数b函数a函数结束b函数结束函数嵌套调用结构示意图11求组合数,可以转化为求3次阶乘#include<stdio.h>floatfac(intn){inti;floatf=1;for(i=2;i<=n;i++)f*=i;returnf;}floatcmn(intm,intn){floatres;res=fac(m)/(fac(n)*fac(m-n));returnres;}voidmain(){intm,n;floatt;printf("Inputm&n:");scanf("%d%d",&m,&n);t=cmn(m,n);printf("C(%d,%d)=%10.0f\n",m,n,t);getch();}例:求组合数。#include<stdio.h>floatfac(intn){inti;floatf=1;for(i=2;i<=n;i++)f*=i;returnf;}floatcmn(intm,intn){floatres;res=fac(m)/(fac(n)*fac(m-n));returnres;}voidmain(){intm,n;floatt;

printf("Inputm&n:");scanf("%d%d",&m,&n);t=cmn(m,n);printf("C(%d,%d)=%10.0f\n",m,n,t);}例:设计一个用于计算常用圆形体体积的计算器,该计算器可支持多次反复计算。采用菜单方式输入1或2或3,分别表示需要计算球体、圆柱体和圆锥体的体积,计算时需输入函数所需的相应参数。main函数calculate函数vol_cylind函数vol_ball函数vol_cone函数圆形体体积计算器函数调用结构#include<stdio.h>#include<math.h>#definePI3.141592654voidcalculate(int);voidmain(void){intsel;/*循环选择计算圆形体的体积,直到输入非1~3数字为止*/

while(1)

{printf("\t\t%s","1--ball\n");

printf("\t\t%s","2--cylind\n");

printf("\t\t%s","3--cone\n");

printf("\t\t%s","other--exit\n");

printf("\t\tPleaseinputyourselete:");

scanf("%d",&sel);

if(sel<1||sel>3)

{printf("\ninputerror\npleaseinput1~3\n");break;}

else

calculate(sel);

}}voidcalculate(intsel){doublevol_ball(void);doublevol_cylind(void);doublevol_cone(void);switch(sel){case1:printf("ball:%.2lf\n",vol_ball());break;case2:printf("cylind:%.2lf\n",vol_cylind());break;case3:printf("cone:%.2lf\n",vol_cone());

break;}}/*ball:v=4/3*PI*r*r*r*/doublevol_ball(){doubler;printf("Pleaseinputr:");scanf("%lf",&r);

return4.0/3*PI*r*r*r;}/*cylind:v=PI*r*r*h*/doublevol_cylind(){doubler,h;

printf("Pleaseinputr&h:");scanf("%lf%lf",&r,&h);returnPI*r*r*h;}/*cone:v=PI*r*r*h/3.0*/doublevol_cone(){doubler,h;

printf("Pleaseinputr&h:");scanf("%lf%lf",&r,&h);returnPI*r*r*h/3.0;}7.3递推7.3.1递推的一般概念递推思路是通过数学推导,将一个复杂的运算化解为若干简单运算的重复执行。例:通过公式:计算的近似值,计算过程在所加项的值小于10-10时终止。

…一个有规律的数列的相邻位置上的数项之间通常存在着一定的关系,我们可以借助已知的项,利用特定的关系逐项推算出它的后继项的值,……,如此反复,直到找到所需的那一项为止,这样的方法称为递推算法。#include<stdio.h>doublefun(double);voidmain(){doubleeps=1e-10,sum;sum=fun(eps);printf("\nPI=%.8lf",sum);}doublefun(doubleeps){doublesum=0.5,t,t1,t2,t3;intodd=1,even=2;t=t1=t2=1.0;t3=0.5;while(t>1e-10){

t1=t1*(even-1)/even;/*t1=1*(1/2)*(3/4)*(5/6)*/

odd+=2;even+=2;/*t2=1/3t2=1/5t2=1/7*/

t2=1.0/odd;t3=t3/4.0;/*t3=1/8t3=1/32t3=1/128*/t=t1*t2*t3;sum+=t;}returnsum*6;}…例:A、B、C、D、E合伙夜间捕鱼,凌晨时都已疲惫不堪,各自在河边的树丛中找地方睡着了。目上三竿,A第一个醒来,他将鱼平分作5份,把多余的一条扔回湖中,拿自己的一份回家去了;B第二个醒来,也将鱼平分作5份,把多余的一条扔回湖中,只拿自己的一份;接着C、D、E依次醒来,也都按同样的办法分鱼。问5人至少合伙捕到多少条鱼?每个人醒来后看到的鱼数是多少条?fish[1]=5人所捕的总鱼数fish[2]=(fish[1]-1)*4/5fish[3]=(fish[2]-1)*4/5fish[4]=(fish[3]-1)*4/5fish[5]=(fish[4]-1)*4/5写成一般式为:fish[i]=(fish[i-1]-1)*4/5i=2,3,…,5intfish[6]={1,1,1,1,1,1},ifish[5]=fish[5]+5for(i=4;i>0;i--)fish[i+1]%5==1YNbreakfish[i]=fish[i+1]*5/4+1当fish[1]==1||fish[1]%5!=1输出计算结果fish[1]~fish[5]#include<stdio.h>voidmain(){intfish[6]={1,1,1,1,1,1},i;do{fish[5]=fish[5]+5;for(i=4;i>0;i--){if(fish[i+1]%5==1)fish[i]=fish[i+1]*5/4+1;elsebreak;}}while(fish[1]==1||fish[1]%5!=1);for(i=1;i<=5;i++)printf("%10d",fish[i]);printf("\n");}7.3.2递推数列

如果一个数列从某一项起,它的任何一项都可以用它前面的若干项来确定,这样的数列被称为递推数列,表示某项与其前面的若干项的关系就称为递推公式。例如Fibonacci数列如下:1,1,2,3,5,8,13,…,令fib(n)表示Fibonacci数列的第n项,依据数列中项与项之间的关系可写出如下Fibonacci数列的递推公式:fib(n)=fib(n-1)+fib(n-2)n=3,4,…

(通项公式)fib(1)=fib(2)=1(边界条件)23main(){inti;longintf[40]={1,1};

/*fib(1)=fib(2)=1(边界条件)*/for(i=2;i<40;i++)f[i]=f[i-2]+f[i-1];

/*fib(n)=fib(n-1)+fib(n-2)通项公式

*/for(i=0;i<40;i++){if(i%5==0)printf("\n");printf("%12ld",f[i]);}getch();}7.3.3递推算法的程序实现例:王小二自夸刀工不错,有人放一张大的煎饼在砧板上,问他:“饼不许离开砧板,切100刀最多能分成多少块?”

q(1)=1+1=2q(2)=1+1+2=4q(3)=1+1+2+3=7q(4)=1+1+2+3+4=11用归纳法不难得出:q(n)=q(n-1)+n(通项公式)q(0)=1

(边界条件,一刀不切只有一块)切1刀切饼问题示意图切2刀切3刀切4刀#include<stdio.h>#include<conio.h>#defineN100voidmain(){inti,q[101];q[0]=1;/*q(0)=1

(边界条件,一刀不切只有一块)*/for(i=1;i<=N;i++)q[i]=q[i-1]+i;/*q(n)=q(n-1)+n(通项公式)*/

printf("%d",q[N]);}7.4递归调用7.4.1递归函数的执行过程如果函数直接或间接地对自己进行调用,就说函数是递归的(分别称为直接递归和间接递归)。在C语言中,所有的函数都可以递归地使用,直接递归是最简单的形式。27递归是利用堆栈技术实现的,堆栈分析:⒈压栈①保护现场(参数、数据)②保护断点保存下条指令的首地址⒉出栈返回下条指令的首地址堆栈技术:先进后出,后进先出。PUSH

压入指令POP

弹出指令28movax,1234movbx,5678pushaxpushbxpopaxpopbxint3例:在屏幕上以降序形式依次显示1--10之间的整数。#include<stdio.h>voidfun(int);voidmain(void){fun(10);getch();}voidfun(intn){if(n){printf("%3d",n);fun(n-1);

}elseprintf("\nEND!");}#include<stdio.h>voidfun(int);voidmain(void){fun(10);getch();}voidfun(intn){if(n){

fun(n-1);printf("%3d",n);}elseprintf("\nEND!");}/*打印?*/例:计算前n个正整数之和。#include<stdio.h>voidmain(){printf("%d",sum(4));}intsum(intn){if(n<=1)returnn;elsereturn(n+sum(n-1));}函数调用返回值sum(1)1sum(2)2+sum(1)即2+1sum(3)3+sum(2)即3+2+1sum(4)4+sum(3)即4+3+2+131累加和1--nadd(intn){ints=0;if(n==0)s=0;elses=add(n-1)+n;return(s);}main(){intn;scanf("%d",&n);printf("%d,%d\n",n,add(n));getch();}7.4.2递归问题求解例:有5个人坐在一起,问第5个人多少岁?他说比第4个人大2岁;问第4个人多少岁?他说比第3个人大2岁;问第3个人多少岁?他说比第2个人大2岁;问第2个人多少岁?他说比第1个人大2岁;问第1个人,他说是10岁。请问第5个人多大?分析:age(5)=age(4)+2age(4)=age(3)+2age(3)=age(2)+2age(2)=age(1)+2age(1)=10可以用数学公式表述如下:

10(n=1)age(n)=age(n-1)+2(n>1)33age(5)=age(4)+2age(4)=age(3)+2age(3)=age(2)+2age(2)=age(1)+2age(1)=10age(2)=12age(3)=14age(4)=16age(5)=18回推PUSH递推POP结束条件34age(intn){intc;if(n==1)c=10;elsec=age(n-1)+2;return(c);}main(){printf("age(5)=%d\n",age(5));getch();}age(intn){intc;if(n==1)c=10;elsec=age(n-1)+2;

printf("age(%d)=%d\n",n,c);return(c);}main(){printf("age(5)=%d\n",age(5));getch();}35㈠递归条件⒈必须有完成函数任务的语句

c=age(n-1)+2;⒉有结束递归的条件表达式

if(n==1)c=10;⒊有调用语句age(5)⒋先判结束递归的条件,后递归㈡递归过程

⒈回推(表达式地址和数据入栈)⒉递推(表达式地址和数据出栈)36age(5)if(n==1)c=10;

elsec=age(n-1)+2;

return(c);……

age(5)

……main()age(4)if(n==1)c=10;

elsec=age(n-1)+2;

return(c);nc5nc4age(3)if(n==1)c=10;

elsec=age(n-1)+2;

return(c);nc3age(2)if(n==1)c=10;

elsec=age(n-1)+2;

return(c);nc2age(1)if(n==1)c=10;

elsec=age(n-1)+2;

return(c);nc11816101214输出18例:求Fibonacci数列的第40个数。Fibonacci数列有如下特点:第1、第2个数均为1,从第3个数开始的每一个数均是其前两个数之和。即:F1=1 (n=1)F2=1 (n=2)Fn=Fn-1+Fn-2 (n≥3)分析:根据任务要求,求Fibonacci数列可以用下列递归公式表示

1 (n=1,2)Fn=Fn-1+Fn-2 (n≥3)#include<stdio.h>longfib(intt){longintc;if(t==1||t==2)c=1;elsec=fib(t-1)+fib(t-2);returnc;}voidmain(){printf("%10ld",fib(40));}39阶乘jc(intn){intf;if(n==0||n==1)f=1;elsef=jc(n-1)*n;return(f);}main(){intn;scanf("%d",&n);printf("%d,%d\n",n,jc(n));getch();}40最大公约数gys(intm,intn){if(n==0)return(m);elsereturngys(n,m%n);}main(){inta,b,t;scanf("%d,%d",&a,&b);if(a<b)t=a,a=b,b=t;printf("%d,%d,gys=%d\n",a,b,gys(a,b));getch();}除数替换成被除数,余数替换成除数41数制变换递归法#include"stdio.h"inta[20],i=0;main(){inty,j;scanf("%d",&y);bin(y);printf("\n");for(j=0;j<i;j++)printf("%2d",a[j]);printf("\n");getch();}bin(intx){if(x/2>0)bin(x/2);printf("%2d",x%2),a[i++]=x%2;}

因递归使用堆栈,先压入低位(i=0时)#include"stdio.h"main(){inty;scanf("%d",&y);bin(y);printf("\n");getch();}bin(intx){if(x/2>0)bin(x/2);printf("%2d",x%2);}42数制变换不用递归#include"stdio.h"inta[20],i=0;main(){inty,j;scanf("%d",&y);bin(y);printf("\n");getch();}bin(intx){do{a[i++]=x%2;x/=2;}while(x!=0);for(--i;i>=0;--i)printf("%2d",a[i]);}43P10第(3)题longfunc(longx){if(x<100)returnx%10;elsereturnfunc(x/100)*10+x%10;}main(){printf("Theresultis:%ld\n",func(132645));getch();}x/100=1326,132645%10=5,第一次压入:()*10+5x/100=13,1326%10=6,第二次压入:

()*10+613<100,结束递归,返回13%10=3,然后递推第一次弹出:3*10+6第二次弹出:36*10+5=365例:Hanoi塔问题。相传在古代印度的Bramah庙中,有位僧人整天把3根柱子上的金盘倒来倒去,原来他是想把64只一个比一个大的金盘从一根柱子上移到另一根柱子上去,移动过程要遵循下列规则:(1)每次只允许移动一只盘;(2)任何时刻任何柱子上都不允许大盘摞在小盘的上面。如图7.7所示。ABC汉诺塔分析如下:1.如果n=1,并假定盘号为1,则将盘1从A直接移动到C。2.如果n=2,则:(1)将A上的n-1(等于1)个盘移到B上;(2)再将A上的一个盘移到C上;(3)最后将B上的n-1(等于1)个盘移到C上。3.如果n=3,则:(1)将A上的n-1(等于2,令其为n`)个盘移到B(借助于C)

①将A上的n-1(等于1)个盘移到C上;②将A上的一个盘移到B上;③将C上的n-1(等于1)个盘移到B上。(2)将A上的一个盘移到C

(3)将B上的n-1(等于2,令其为n)个盘移到C(借助A)①将B上的n-1(等于1)个盘移到A;②将B上的一个盘移到C;③将A上的n-1(等于1)个盘移到C。从上面分析可以看出,当n大于等于2时,

移动的过程可分解为三个步骤:第一步:把A上的n-1个盘借助C移到B上;第二步:把A上的一个盘移到C上;第三步:把B上的n-1个盘借助A移到C上。其中第一步和第三步是类同的,可以用递归解决。递归函数中使用了四个参数:(1)准备移动的盘数;(2)最初放置这些盘的柱子;(3)最后放置这些盘的柱子;(4)临时存放的柱子。47#include"stdio.h"voidmove(charx,chary){printf("%c-->%c\n",x,y);}voidhanoi(intn,charone,chartwo,charthree)/*将n个盘从one柱借助two柱,移到three柱*/

{if(n==1)move(one,three);

else

{hanoi(n-1,one,three,two);

move(one,three);

hanoi(n-1,two,one,three);}

}voidmain(){intm;

printf("inputthenumberofdiskes:");

scanf("%d",&m);

printf("thesteptomoving%3ddiskes:\n",m);

hanoi(m,'A','B','C');}7.4.3递归算法举例例:在屏幕上绘制图案#include<stdio.h>#defineSYMBOL'*'#defineOFFSET0#defineLENGTH19voiddisplay(char,int,int);voiddraw(char,int);voidmain(void){display(SYMBOL,OFFSET,LENGTH);}voiddisplay(charc,intm,intn){if(n>0){draw('',m);draw(c,n);putchar('\n');display(c,m+1,n-2);}}voiddraw(charc,intk){if(k>0){putchar(c);draw(c,k-1);}}

运行结果:************************************例:用递归处理串:(1)求串长(2)模拟字符串比较函数。用递归求串长#include<stdio.h>voidmain(void){charstr[]="OneWorld!OneDream!";printf("%d\n",r_strlen(str));}intr_strlen(chars[]){if(*s=='\0')return0;elsereturn1+r_strlen(s+1);}(2)用递归模拟字符串比较函数#include<stdio.h>voidmain(void){charstr1[]="OneWorld!",str2[]="OneDream!";printf("%d\n",r_strncmp(str1,str2,10));}/*Recursivestringncompare.*/intr_strncmp(char*s1,char*s2,intn){if(*s1!=*s2||*s1=='\0'||n==1)return*s1-*s2;elsereturnr_strncmp(++s1,++s2,--n);}例:整型数组a有n个元素值,求其中的最大数和最小数。#include<stdio.h>#include<stdlib.h>/*stdlib.h是杂项说明,内含求两数中的大数、求两数中的小数等函数原型说明*/voidminmax(inta[],intn,int*min_ptr,int*max_ptr){intmin1,max1,min2,max2;if(n==1)*min_ptr=*max_ptr=a[0];/*子问题只有一个元素的情况*/

elseif(n==2)/*子问题有两个元素的情况*/

{*min_ptr=min(a[0],a[1]);*max_ptr=max(a[0],a[1]);}

else

{minmax(a,n/2,&min1,&max1);/*求前半部分中的最小值和最大值*/

minmax(a+n/2,n-n/2,&min2,&max2);/*求后半部分中的最小值和最大值*/*min_ptr=min(min1,min2);/*两部分中最小值中的较小者赋给min_ptr指向的对象*/

*max_ptr=max(max1,max2);/*两部分中最大值中的较大者赋给max_ptr指向的对象*/

}}voidmain(){inta[10]={87,13,556,673,849,643,394,583,523,3};intfmin,fmax;minmax(a,10,&fmin,&fmax);printf("minis:%d\nmaxis:%d\n",fmin,fmax);}7.5编译预处理7.5.1预处理的概念预处理:在C编译系统对程序进行通常的编译前,先对程序中以“#”开头的命令进行的特殊处理。然后再将这些预处理的结果和源程序一起再进行通常的编译处理,从而得到目标代码。一条预处理命令以“#”开头,且占用单一的书写行;预处理命令一般放在源程序的前面,且一般不以“;”结束。54C语言与其他高级语言的一个重要区别是可以使用预处理命令和具有预处理的功能。C提供的预处理功能主要有以下三种:1.宏定义2.文件包含3.条件编译这些功能分别用宏定义命令、文件包含命令、条件编译命令来实现。为了与一般C语句相区别,这些命令以符号“#”开头。例如:

#define

#include

#ifdef标识符程序段1#else

程序段2

#endif7.5.2宏定义宏:代表一个字符串的标识符;宏名:被定义为“宏”的标识符;宏代换(宏展开):在编译预处理时,对程序中所有出的“宏名”,用宏定义中的字符串去代换的过程。一、宏替换

1.无参宏的定义格式:#define标识符字符串如:(1)#definePI3.1415926

(2)#defineM(y*y+3*y)例:由键盘输入y值,求表达式:

3(y2+3y)+4(y2+3y)+5(y2+3y)#defineM

(y*y+3*y)main(){ints,y;printf(“Inputanumber:”);scanf(“%d”,&y);s=3*M+4*M+5*M;printf(“s=%d\n”,s);}先宏展开:s=3*(y*y+3*y)+4*(y*y+3*y)+5*(y*y+3*y)再与源程序一起编译。说明:1.宏定义中表达式两边的括号不能省;2.宏名习惯上用大写字母;3.使用宏名使程序易读、易修改;4.宏定义不是说明或语句,不作语法检查,不分配内存空间;如:#definePI3.14I59265.宏名的作用域一般自定义起到本源程序结束;6.可用#undef终止宏定义的作用域;如:

#defineG9.8

main()

{…}

#undefG

f1()

…7.宏定义允许嵌套;如:

#definePI3.1415926#defineSPI*y*y…printf(“%f”,S);…8.宏名在源程序中若用引号括起来,则TC中预处理不对其作宏代换;如:

#defineOK100main(){printf(“OK”);prinf(“\n”);}9.对“输出格式”进行宏定义,可以减少书写麻烦;如:#definePprintf#defineD“%d,%d,%d\n”#defineF“%6.2f,%6.2f,%6.2f\n”main(){inta=5,c=8,e=11;floatb=3.8,d=9.7,f=21.08;P(D,a,c,e);P(F,b,d,f);P(F,a+b,c+d,e+f);}二、有参宏格式:#define宏名(参数1,参数2,…,参数n)字符串如:#defineS(a,b)a*b

area=S(3,2);对带参的宏展开后,为area=3*2;

再如:#defineM(y)y*y+3*y

k=M(5);

…对其展开后,为k=5*5+3*5;例:利用宏定义求两个数中的大数。#defineMAX(a,b)(a>b)?a:bmain(){intx,y,max;scanf(“%d%d”,&x,&y);max=MAX(x,y);printf(“max=%d\n”,max);}本例中宏展开后的语句为:max=(x>y)?x:y用于计算x、y中的大者。例:#definePI3.1415926#defineS(r)PI*r*rmain(){floata,area;

a=3.6;

area=S(a);

printf(“r=%f\narea=%f\n”,a,area);}说明:1.带参宏定义中,宏名与参数间不能有空格;2.如上例程序改为:

#definePI3.1415926#defineS(r)PI*r*r

main()

{floata,b,area;

a=3.6;b=4.1;

area=S(a+b);

printf(“r=%f\narea=%f\n”,a+b,area);

}则宏展开为:area=3.1415926*a+b*a+b3.带参宏定义,形参不分配内存单元,因此不必作类型定义(与函数区别之一);4.带参宏与函数的区别之二:见以下例题65#defineSQ(y)((y)*(y))main(){inti=1;while(i<=5)printf("%d",SQ(i++));getch();}展开后:

printf(“%d\n”,(i++)*(i++));结果:

212302*14*36*5带参宏与函数的区别main()

{inti=1;

while(i<=5)printf(“%d”,SQ(i++));}SQ(inty)

{return(y)*(y);}结果:

1491625在多数系统中对函数参数的求值顺序是自右向左。66#defineSQ(y)((y)*(y))main(){inti=1;while(i<=5)printf("i=%d,SQ(i++)=%d,i=%d\n",i,SQ(i++),i);getch();}函数和带参数宏的区别区别类型函数带参数的宏是否计算实参的值先计算出实参表达式的值,然后传给形参不计算实参表达式的值,直接用实参进行简单的替换。何时进行处理、分配内存单元在程序运行时进行值的处理、分配临时的内存单元。编译前,由预处理程序进行宏展开,不分配内存单元。不进行值的处理类型要求实参和形参要定义类型,且类型一致。不存在类型问题,只是一个符号表示。调用情况函数的代码只作为一个拷贝存在,对程序较大、调用次数多的较合算,但调用函数时有一定数量的处理开销。在源代码中遇到宏定义时,都将其扩展为代码,程序调用几次宏就扩展为代码几次,但调用宏时没有处理的开销。68说明:⑴宏定义时,宏名与带参数的括号之间不加空格。⑵对带参数的宏展开只是将宏名后括号内的实参

字符串代替#define命令行中的形参。例(为便于口算,将3.14改为3)#defines(r)3*r*rmain(){floata,area,b;a=4;area=s(a);printf("area=%f\n",area);getch();}改成

#defines(r)3*(r)*(r)

b=3;

+b展开为3*a+b*a+b展开为3*(a+b)*(a+b)area=48.000000area=27.00000069#defines(r)2*r*rmain(){inta,x,b;a=4;b=2;x=s(a);printf("x=%d\n",x);?getch();}x=32#defines(r)2*r*rmain(){inta,x,b;a=4;b=2;x=s(a+b);printf("x=%d\n",x);?getch();}x=18s=(a+b)=2*4+2*4+2=18rr70带参的宏定义和函数不同的另一种描述:1、函数调用时,先求实参表达式值,后代入。

带参宏只是进行简单的字符替换。2、函数调用是在程序运行时处理的,分配内存单元。

宏展开是在编译时进行的,不分配内存单元。3、函数中的实参和形参都要定义类型,类型应一致。

宏不存在类型问题,宏名和参数无类型.4、函数调用则占用运行时间。

宏替换不占运行时间,只占编译时间。71输出6个数及和#defineP(var)printf(#var"=%d\n",var)#include<stdlib.h>main(){intx,i,s=0;randomize();for(i=0;i<6;i++){x=rand()%100;P(x);s=s+x;}P(s);getch();}72求2个随机数的大数#defineP(var)printf(#var"=%d\n",var)#defineMAX(x,y,m)m=(x>y?x:y);P(m);#include<stdlib.h>main(){inta,b,c=0;randomize();a=rand()%100;P(a);b=rand()%100;P(b);MAX(a,b,c);getch();}73求3个数的最大值、最小值1.#defineP(var)printf(#var"=%d\n",var)#defineM(a,b,c,max,min)max=(a>b?a:b)>c?(a>b?a:b):c;\min=(a<b?a:b)<c?(a<b?a:b):c#include<stdlib.h>main(){intc,d,e,mx,mn;randomize();#defineRrand()%100;c=R;d=R;e=R;P(c);P(d);P(e);M(c,d,e,mx,mn);P(mx);P(mn);getch();}742.#defineP(var)printf(#var"=%d\n",var)#defineRrand()%100;#defineM(a,b,c,max,min)a=R;b=R;c=R;P(a);P(b);P(c);\max=(a>b?a:b)>c?(a>b?a:b):c;\min=(a<b?a:b)<c?(a<b?a:b):c#include<stdlib.h>main(){intc,d,e,mx,mn;randomize();M(c,d,e,mx,mn);P(mx);P(mn);getch();}#defineP(var)printf(#var"=%d\n",var)#defineRrand()%100;#defineM(a,b,c,max,min)a=R;b=R;c=R;P(a);P(b);P(c);\max=(a>b?a:b)>c?(a>b?a:b):c;\min=(a<b?a:b)<c?(a<b?a:b):c;P(mx);P(mn)#include<stdlib.h>main(){intc,d,e,mx,mn;randomize();M(c,d,e,mx,mn);getch();}75判别闰年#include<stdio.h>#defineIS_LEAP_YEAR(y)y%4==0&&y%100!=0||y%400==0#defineP(y)printf("%dleap\n\n",y)#defineP1(y)printf("%dnotleap\n\n",y)main(){intyear;printf("year:");scanf("%d",&year);if(IS_LEAP_YEAR(year))P(year);elseP1(year);getch();}#include<stdio.h>#defineIS_LEAP_YEAR(y)(y%4==0&&y%100!=0||y%400==0)?\printf("%dleap\n\n",y):printf("%dnotleap\n\n",y)main(){intyear;printf("year:");scanf("%d",&year);IS_LEAP_YEAR(year);getch();}7.5.3文件包含文件包含是C预处理程序的另一个重要功能。文件包含命令行的一般形式为:

#include"需包含的文件名"或

#include<需包含的文件名>例如:#include"stdio.h"#include<math.h>

说明:包含命令中的文件名可以用双引号括起来,也可以用尖括号括起来,但这两种形式是有区别的:使用尖括号(<…>):表示预处理程序在规定的磁盘目录(通常为include子目录)查找文件。使用双引号(“…”):表示预处理程序首先在当前目录中查找文件,若没有找到,最后才去include子目录中查找。(2)一个include命令只能指定一个被包含文件,若有多个文件要包含,则需用多个include命令。(3)文件包含允许嵌套,即在一个被包含的文件中又可以包含另一个文件。例:设有如下直接选择排序函数:voidsel_sort(inta[],intn){inti,j,k,temp;for(i=0;i<n-1;i++){k=i;for(j=i+1;j<n;j++)if(a[k]>a[j])k=j;if(k!=i){temp=a[k];a[k]=a[i];a[i]=temp;}}}现将其以文件名sort.c存放在win-tc\projects(Win-TC环境下)当前工作目录下,要求通过文件包含的方法对一个具有10个元素值的整型数组实现排序。#include<stdio.h>#include"sort.C“/*第3条包含命令包含了编程者自己设计的文件,必须存在于当前工作目录下*/voidmain(void){

inti,a[10]={8,3,7,9,10,-5,7,15,90,76};

sel_sort(a,10);

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

printf("%5d",a[i]);

printf("\n");}80用引号:带路径:按指定路径去寻找被包含文件,

不再从当前目录和指定目录下找。不带路径:先在当前目录下找,找不到再在

系统指定的标准目录下找。#include“c:\tc\include\myfile.h”/*正确*/用尖括号:带路径:按指定路径去寻找被包含文件,

但此时被包含文件不能以“.h”结尾

不带路径:仅从指定标准目录下找。#include<c:\tc\include\stdio.h>/*错误*/#include<c:\test\file.c>/*正确*/81条件编译一般情况下,所有行都参加编译;但有时需要部分内容,只在满足条件时才进行编译,这就是”条件编译”。可以按不同的条件去编译不同的程序部分,因而产生不同的目标代码文件。对于程序的移植和调试是很有用。条件编译有三种形式:

1.

第一种形式:

#ifdef标识符程序段1

#else

程序段2

#endif82它的功能是,如果标识符已被#define命令定义过,则对程序段1进行编译;否则对程序段2进行编译。如果没有程序段2(它为空),本格式中的#else可以没有,即可以写为:

#ifdef标识符程序段

#endif#defineABC/*删除此句,看结果*/main(){

#ifdefABC

printf("ABC\n");

#else

printf("NOTABC\n");

#endif

getch();}832.

第二种形式:

#ifndef标识符程序段1

#else

程序段2

#endif

与第一种形式的区别是将“ifdef”改为“ifndef”。它的功能是,如果标识符未被#define命令定义过则对程序段1进行编译,否则对程序段2进行编译。这与第一种形式的功能正相反。843.

第三种形式:

#if常量表达式程序段1

#else

程序段2

#endif

它的功能是,如常量表达式的值为真(非0),则对程序段1进行编译,否则对程序段2进行编译。因此可以使程序在不同条件下,完成不同的功能。85#defineA1/*改变A值为0,查看结果*/main(){

#ifA

printf("A=True\n");

#else

printf("A=False\n");

#endif

getch();}86#defineUP2#defineDN(2+UP)#defineNIDN/2main(){printf("%d\n",((UP+DN)*NI)/2);getch();}输出?

6((2+(2+2))*(2+2)/2)/26*2/287#defineM3#defineNM+1#defineNNN*N/2main(){printf("%d\n",NN);getch();}输出?

6M+1*M+1/23+1*3+1/23+3+088P2189.3#include<math.h>#defineS(a,b,c)1.0/2*(a+b+c)/*不能用1/2(结果为整形数)*/#defineAREA(a,b,c)sqrt(S(a,b,c)*(S(a,b,c)-a)*(S(a,b,c)-b)*(S(a,b,c)-c))main(){floatx,y,z;printf("inputx,y,z:");scanf("%f,%f,%f",&x,&y,&z);printf("AREA=%8.2f\n",AREA(x,y,z));getch();}89对p54混合运算的解释:

1.自动转换成高级类型运算

2.运算顺序,按优先级从左到右main(){floata=1.0,b=2.0,c=3.0;printf("%d\n",1

温馨提示

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

评论

0/150

提交评论