c语言程序设计-第7章-函数-2完整_第1页
c语言程序设计-第7章-函数-2完整_第2页
c语言程序设计-第7章-函数-2完整_第3页
c语言程序设计-第7章-函数-2完整_第4页
c语言程序设计-第7章-函数-2完整_第5页
已阅读5页,还剩58页未读 继续免费阅读

付费下载

下载本文档

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

文档简介

C语言程序设计第7章函数(2)7.5函数的嵌套调用

C语言中不允许作嵌套的函数定义。因此各函数之间是平行的,不存在上一级函数和下一级函数的问题。

C语言允许在一个函数的定义中出现对另一个函数的调用。这样就出现了函数的嵌套调用。

即在被调函数中又调用其它函数。7.6函数的递归调用1、递归的概念直接递归调用调用函数的过程中又调用该函数本身

间接递归调用调用f1函数的过程中调用f2函数,而f2中又需要调用f1。以上均为无终止递归调用。为此,一般要用if语句来控制使递归过程到某一条件满足时结束。四、函数的递归调用2、递归算法类似于数学证明中的反推法,从后一结果与前一结果的关系中寻找其规律性。归纳法可以分为:

递推法从初值出发,归纳出新值与旧值间直到最后值为止的关系。要求通过分析得到:初值+递推公式编程:通过循环控制结构实现(循环的终值是最后值)

递归法从结果出发,归纳出后一结果与前一结果直到初值为止的关系。要求通过分析得到:初值+递归函数编程:设计一个函数(递归函数),这个函数不断使用下一级值调用自身,直到结果已知处——选择控制结构。四、函数的递归调用2、递归算法main(){f(n)…}f(x){f(x-1)}其一般形式是:在主函数中用终值n调用递归函数,而在递归函数中:递归函数名f(参数x)f(x-1){{f(x-2)if(n==初值)}结果=…;else结果=含f(x-1)的表达式;f(x0){f(x0==…)}f(x-2){f(x-3)}返回结果(return);}【例7.6】有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)递归过程跟踪分析:{age(intn)age(1)intc;if(n==1)c=10;elsec=age(n-1)+2;returnc;c=10returnc;}c=10age(5)age(4)age(3)age(2)c=age(4)+2;c=age(3)+2;c=age(2)+2;c=age(1)+2;returnc;returnc;returnc;returnc;c=18c=16c=14c=12【例7.7】用递归法求n!分析比较:实际上,递归程序分两个阶段执行——①回推(调用):欲求n!→先求(n-1)!→(n-2)!→…→1!若1!已知,回推结束。②递推(回代):知道1!→2!可求出→3!→…→n!阶乘的递推算法:

对于一个非负整数,它的阶乘是以下表达式的结果:

n!=1*2·······*(n-3)*(n-2)*(n-1)*n

n!=n*(n-1)*(n-2)*(n-3)*·······*2*1

递推(或称迭代法)算法

例如5的阶乘:

5!=5*4*3*2*1

for(i=1,result=1;i<=5;i++)

result*=i;阶乘的递推算法示例:1.#defineN102.#include"stdio.h"3.voidmain()4.{5.6.inti,result;printf(printf(%d!"%d!=",N);7.8.9.10.11.12.13.}for(i=1,result=1;i<=N;i++)printf("%d",i);{result*=i;if(i<N)printf("*");}printf("=%d",result);阶乘的递归算法示例:

#include"stdio.h"

longfac(intn){longc;if(n==0||n==1)c=1;elsec=n*fac(n-1);returnc;

}

main(){longn,s;printf("Inputn=");scanf("%d",&n);s=fac(n);printf("%ld!=%.0ld",n,s);}//递推法longfac(intn){longi,c=1;//递归法longfac(intn){longc;if(||)(n==0||n==1)for(i=1;i<=n;i++)c=1;c=c*i;elsec=n*fac(n-1);returnc;returnc;}}7.7数组作为函数参数

数组可以作为函数的参数使用,进行数据传送。数组用作函数参数有两种形式,

1.把数组元素(下标变量)作为实参使用;

2.把数组名作为函数的形参和实参使用。

数组元素作函数实参

数组元素就是下标变量,它与普通变量并无区别。因此它作为函数实参使用与普通变量是完全相同的,在发生函数调用时,把作为实参的数组元素的值传送给形参,实现单向的值传送。例:判断整数数组中各元素的值,若大于0则输出该值>0,若小于0则输出<0,若等于0,则输出=0。编程如下:#include"stdio.h"voidfunc(inta){if(a>0)printf("%d>0\n",a);用数组元素作实参时,只要数组类型和elseif(a==0)printf("%d=0\n",a);函数的形参变量的类型一致,那么作为elseprintf(printf(%d"%d<0<0\n",a);}下标变量的数组元素的类型也和函数形voidmain(){inta[5],i;参变量的类型是一致的。printf("input5numbers:\n");for(i=0;i<5;i++)因此,对数组元素的处理是按普通变scanf("%d",&a[i]);for(i=0;i<5;i++){printf("a[%d]=",i);量对待的。func(a[i]);}}数组名作为函数参数

用数组名作函数参数时,要求形参和相对应的实参都必须是类型相同的数组,都必须有明确的数组说明。

当形参和实参二者不一致时,即会发生错误。数组名作为函数参数

在普通变量或下标变量作函数参数时,形参变量和实参变量是由编译系统分配的两个不同的内存单元。

在函数调用时发生的值传送是把实参变量的值赋予形参变量。

在用数组名作函数参数时,不是进行值的传送,即不是把实参数组的每一个元素的值都赋予形参数组的各个元素。

实际上形参数组并不存在,编译系统不为形参数组分配内存。

那么,数据的传送是如何实现的呢?

在我们曾介绍过,数组名就是数组的首地址。

数组名作函数参数时所进行的传送只是地址的传送,也就是说把实参数组的首地址赋予形参数组名。

形参数组名取得该首地址之后,也就等于有了实在的数组。

实际上形参数组和实参数组为同一数组,共同拥有一段内存空间。

上图中设a为整型实参数组。a占有以2000为首地址的一块内存区。

当发生函数调用时,进行地址传送,把实参数组a的首地址传送给形参数组名b,b也取得该地址2000。

于是a,b两数组共同占有以2000为首地址的一段连续内存单元。

从图中还可以看出a和b下标相同的元素也占相同的内存单元。

例如a[0]和b[0]都占用同一内存单元,a[0]等于b[0]。类推则有a[i]等于b[i]。

#defineSIZE3#include"stdio.h"

voidfunc(intb[])//定义func函数,形式参数为数组{inti;for(i=0;i<SIZE;i++){printf("b[%d]的地址:%ld,值为:",i,&b[i]);if(b[i]>0)printf("%d>0\n",b[i]);elseif(b[i]==0)printf("%d=0\n",b[i]);elseprintf("%d<0\n",b[i]);}

}

voidmain(){inta[SIZE],i;printf("input%dnumbers:\n",SIZE);for(i=0;i<SIZE;i++)scanf("%d",&a[i]);for(i=0;i<SIZE;i++)printf("a[%d]的地址:%ld,值为:%d\n",i,&a[i],a[i]);printf("\n");func(a);//调用func函数,实际参数为数组名}

例:编写一个delstr()函数用来删除指定字符。

算法:可将字符串中的字符除了指定字符外,全部赋给另一个字符串,

delstr()中要有两个形参数组,要知道需要删除第几位,必须要一个iitnt整型的形参。

输出新串时没有必要从子函数中传递数值回主函数,只要打印新串就可以了。

子函数定义:voiddelstr(chara[],charb[],intn)#include"stdio.h"#defineLEN40voidmain(){voiddelstr(chara[],charb[],intn);voiddelstr(chara[],charb[],intn)charstr1[LEN],str2[LEN];intn;p(puts("请输入一个字符串");=0;{inti,j=0;j<LEN;i++)for(iif(iif(i!!n)=n)gets(str1);printf("请问要删除第几位的字符:");scanf("%d",&n);{=a[i];b[j]j++;}(str1,str2,n-1);delstr"printf(删除第%d位后,新字符串是%s",}}n,str2);变量的存储类型

变量两大属性:·数据类型·存储类别2、存储类别规定了变量在计算机内部的存放位置→决定变量的“寿命”(何时“生”,何时“灭”)C程序的存储类别有:■regiitster型(寄存器型)■auto型(自动变量型)■static型(静态变量型)■extern型(外部变量型)一个完整的变量说明格式如下:存储类别数据类型变量名如autointx,y;C程序的变量存储位置变量的生存期静态存储区中的变量:与程序“共存亡”动态存储区中的变量:与函数“共存亡”寄存器中的变量:与动态存储区相同存储在动态存储区的变量:■register型(寄存器型)变量值存放在运算器的寄存器中——存取速度快,一般只允许2~3个,且限于char型和int型,早期通常用于循环变量。■auto型(自动变量型)(变量的默认类型)只有需要它们时才占用内存,即定义变量的函数被调用时,auto型变量才被创建,函数结束时,变量立刻被删除。优点——节约内存同一内存区可被不同变量反复使用。以上两种变量均属于“动态存储型”,即调用函数时才为这些变量分配单元,函数调用结束其值自动消失。【例1】求程序运行结果#include"stdio.h"voidmain(){intf(a);int=a2,i;)++(i<0;i=for3;ip(printf("%4d",());,f(a));}a)f(int{intb=2;2;=intcb++;c=a+bc;c;return}存储在静态存储区的变量:未说明存储类别时,函数内定义的变量默认为auto型■static型(静态变量型)函数外定义的变量默认为extern型。变量值存放在主存储器的静态存储区程序执行开始至结束,始终占用该存储空间■extern型(外部变量型)同上,其值可供其他源文件使用以上两种均属于“静态存储”性质,即从变量定义处开始,在整个程序执行期间其值都存在(≠都可用!!)静态变量

静态变量是静态存储类型的变量,即在程序运行期间分配固定的存储单元,从被调用开始,它在程序执行期间始终存在,不随函数的退出调用而释放。

在所有函数之外定义的静态变量是静态外部变量。

未初始化的静态外部变量在编译时自动初始化为零值。【例2】求程序运行结果#include"stdio.h"voidmain(){intf(a);int=a2,i;)++(i<0;i=for3;ip(printf("%4d",());,f(a));}a)f(int{staticintb=2;2;=intcb++;c=a+bc;c;return}外部变量在所有函数之外定义而没有指定其存储类别的变量称为外部变量,即全局变量。连接在一起的各目标文件的源程序文件中的所有函数均可以访问外部变量。外部变量⒉外部变量是静态存储类型的变量,在程序运行期间分配固定的存储空间,因此其生存期是整个程序的运行期,就是说它的值不随函数的退出调用而消失。⒊外部变量可在定义时作初始化;没有初始化的外部变量,由编译程序自动初始化为零值。【例3】求程序运行结果#include"stdio.h"intb=5;//b在所有函数外,是外部变量main()void{f(a);intint2=a,;,i;3;i)++<0;i=(iforprintf("%4d",f(a));}intf(a){2;=intcb++;c=a+bc;c;return}在一个文件内声明外部变量如果外部变量不在文件的开头定义,其有效的作用范围只限于定义处到文件终结处。如果在定义点之前的函数想引用该外部变量,则应该在引用前用关键字extern对该变量作“外部变量声明”。表明该变量是一个已经定义的外部变量。【例4】求程序运行结果#include"stdio.h"intmain(){intf(a);int=a2,i;)++(i<0;i=for3;iprintf("%4d",f(a));}0;returnintf(a){intc=2;b++;c;b+=careturnc;}//bintb=5;在所有函数外,是外部变量【例5】求程序运行结果#include"stdio.h"main()int{intf(a);inta=2,i;)++3;i=(ifor<0;iprintf("%4d",f(a));return0;}intf(a){2;=cintb++;c;b+c=areturnc;}//bintb=5;在所有函数外,是外部变量【例6】求程序运行结果#include"stdio.h"//externb;main()int{对外部变量b进行声明intf(a);a=int2,i;for(i=0;i<3;i++)p(printf("%4d",());,f(a));return0;}intf(a){=2;intcb++;c;+b=careturnc;}//bintb=5;在所有函数外,是外部变量局部变量与全局变量1、局部变量——函数内部或复合语句内定义的变量auto(默认)所在函数调用结束时,其值自动消失局部变量register如不赋初值,取不确定值为初值所有函数调用结束,其值仍保留static如不赋初值,取初值为0所有形参都是局部变量;局部变量只在本函数或本复合语句内才能使用,在此之外不能使用(视为不存在)——main函数也不例外。局部变量与全局变量2、全局变量——在函数之外定义的变量extern(默认)允许本源文件中其他函数及其他源文件使用全局变量static只限本源文件中使用所有全局变量加不加static,都属于静态存储,如不赋初值,取初值为0(数值型)或空格(字符型)(注意与函数内部定义的static型局部变量的区别)2、全局变量——在函数之外定义的变量去掉第一行试试……

有效作用范围:从定义变量位置开始直到本源文件结束

如果需要将全局变量的作用【例】求程序运行结果externintx,y;main(){范围扩展至整个源文件——方法1全部在源文件全部在源文件头处定义开头处定义printf(%%f("x=%d,y=%d\n",x,y);方法2在引用函数内,用extern}intx=100,y=200;说明变量方法3在源文件开头处,用结果:x=100,y=200extern说明变量【例7】求程序运行结果#include"stdio.h"intx=1;intmain(){intx=5;printf("主函数中x=%d\n",x);{intx=7;printf("主函数中的复合语句中的x=%d\n",x);}printf("主函数中的复合语句外的x=%d\n\n",x);0;return}【例8】求程序运行结果#include"stdio.h"intx=1;{local()voidx=25;intprintf("local()x++;"local()printf(中x的初值为,x);=%d\n"中x在调用结束前的值},x);=%d\n\n"intmain(){5;intx=printf("调用函数前,主函数中的,x);x=%d\n\n"local();printf("调用函数后,主函数中的x=%d\n",x);0;return}【例9】求程序运行结果#include"stdio.h"xint=1;voidstatic_local(){staticintx=50;printf("static_local()+=x2;"static_local()printf(函数中x的初值为=%d\n",x);中x在调用结束前的值=%d\n\n",x);}{main()intintx=5;printf("调用函数前,主函数中的x=%d\n\n",x);static_local();"printf(调用函数后,主函数中的,x);x=%d\n"static_local();printf("调用函数后,主函数中的x=%d\n",x);0;return}【例10】求程序运行结果#include"stdio.h"int=x1;voiduse_global(){printf("use_global()函数中x的初值为=%d\n",x);10;x*=printf("use_global()中x在调用结束前的值=%d\n\n",x);}{intmain()intx=5;printf("调用函数前,主函数中的x=%d\n\n",x);use_global();"printf(调用函数后,主函数中的,x);x=%d\n\n"use_global();printf("调用函数后,主函数中的x=%d\n\n",x);0;return}【例11】求程序运行结果main(){变量跟踪inta=2,i;for(i=0;i<3;i++)main()f函数aib200→147cf(a)printf("%4d",f(a));}10→15820→169f(inta){【结果】789intb=0;staticintc=3;b++;c++;returna+b+c;如果去掉static呢?【结果】777}【例12】求程序运行结果main(){main(){intk=4,m=1,p;p=func(k,m);printf("%d,",p);p=func(k,m);printf("%d"printf("%d"p),p);intk=4,m=1,p;p=func(k,m);printf("%d,",p);p=func(k,m);printf("%d"printf("%d"p),p);}func(inta,intb){staticintm=0,i=2;}func(inta,intb){intm=0,i=2;i+=m+1;m=i+a+b;returnm;i+=m+1;m=i+a+b;returnm;}}【例13】求程序运行结果main(){变量跟踪intk=4,m=1,p;p=func(k,m);printf("%d,",p);p=func(k,m);printf("%d"p)printf("%d",p);main()func函数abmikm41410→82→341418→173→12}func(inta,intb){staticintm=0,i=2;【结果】8,17i+=m+1;m=i+a+b;returnm;如果去掉static【结果】8,8}【例14】求程序运行结果inta=3,b=5;max(inta,intb){【结果】8intc;c=a>b?a:b;returnc;如果主函数中没有inta=8,结果?}【结果】5main()如果让主函数中inta=4或a=-1,结果?{inta=8;printf("%d\n",max(a,b));【结果】均为5}【例16】求程序运行结果voidnum(){externintx,y;inta=15,b=10;x=a-b;y=a+b;【结果】5,25}itintx,y;main(){inta=7,b=5;如果第二行不加上externx=a+b;y=a-b;num();printf("%d,%d\n",x,y);【结果】12,2}课堂练习

猴子吃桃问题。猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第二天早上又将剩下的桃子吃掉一半,又多吃了个吃了一个。以后每天早上都吃了前天剩下以后每天早上都吃了前一天剩下的一半零一个。到第十天早上在想吃时,就只剩一个桃子了。求第一天共摘了多少个桃子?分别用递推和递归法编程计算。

算法

总天数10天

最后一天是1个

每一天吃前一天的一半,又多吃了一个

(倒数第二天有4个,吃一半(2个)+1个=3个,余1个)

循环公式:day2=(day1+1)*2

循环的次数?用递推法编程计算11.#include"stdio.h"#defineDAY10voidmain(){intn,day1,day2;2.3.4.5.n=1;day1=1;6.7.while(n++<=DAY)8.{printf("倒数第%d天的桃子数为:%d\n",n,day1);9./*day2=(day1+1)*2;day1=day2;第1天的桃子数是第2天桃子数加1后的2倍*/10.11.}12.printf("倒数第%d天的桃子数为:%d\n",DAY,day2);13.}用递推法编程计算2

#include"stdio.h"voidmain(){intn,day1,day2;

n=9;

day2=1;

while(n>0)

{

printf("第%d天的桃子数为:%d\n",n+1,day2);day1=(day2+1)*2;//day2=day1;n--;

第一天的桃子数是第2天桃子数加1后的2倍

}

printf("第1天的桃子数为%d\n",day1);}

用递归法编程计算#include"stdio.h"voidmain(){intpeach(inti);inti=10;printf("thefirstday,monkeypick%dpeach",peach(10));}intintpeach(inti)peach(inti){intm;if(i==1)m=1;elsem=(peach(i-1)+1)*2;returnm;}P219练习17题

用递归法将一个整数n转换成字符串.

例如,输入483,应输出字符串"483".

n的位数不确定,可以是任意的整数用数组实现#include"stdio.h"#defineSIZE20intmain(){;}0{=str[SIZE]charintnum,i;printf("inputanumber:");num);&scanf("%d",for(i=0;num;i++){str[i]=num%10+'0';num/=10;}puts("\n正序输出);:")for(i--;i>=0;i,str[i]);printf("%c"puts("\n\n=for(i0;str[i]!=0;i++)逆序输出:");"%c",str[i]);printf(}用递归实现正序输出#include"stdio.h"intmain(){voidfun(intn);intnum;);printf("inputanumber:"scanf("%d",&num);fun(num);return0;}/*for(i=0;for(i=0;num;i++){num;i++){str[i]=num%10+'0';num/=10;}*/v

温馨提示

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

评论

0/150

提交评论