《C语言程序设计教程(第3版)》课件第08章 函数_第1页
《C语言程序设计教程(第3版)》课件第08章 函数_第2页
《C语言程序设计教程(第3版)》课件第08章 函数_第3页
《C语言程序设计教程(第3版)》课件第08章 函数_第4页
《C语言程序设计教程(第3版)》课件第08章 函数_第5页
已阅读5页,还剩96页未读 继续免费阅读

下载本文档

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

文档简介

第8章函数制作人:sss第8章:函数

学习的意义

语言程序设计教程第三版第八章函数C模块化程序设计方法:人们在求解某个复杂问题时,通常采用逐步分解、分而治之的方法,也就是将一个大问题分解成若干个比较容易求解的小问题,然后分别求解。程序员在设计一个复杂的应用程序时,往往也是把整个程序划分成若干个功能较为单一的程序模块,然后分别予以实现,最后再把所有的程序模块象达积木一样装配起来,这种在程序设计中分而治之的策略,被称为模块化程序设计方法。子模块1子模块2子模块n学习的意义

功能模块1功能模块2功能模块n……………………软件项目C语言程序C语言函数达积木语言程序设计教程第三版第八章函数C学习的意义

使用函数,不仅可以实现程序的模块化,程序设计得简单和直观,提高了程序的易读性和可维护性。编写自定义函数库。把一些常用的或某些特定功能的程序制作成自己的函数库,以供随时调用,这样可以大大减轻日后编写代码的工作量。通过对函数的学习,掌握模块化程序设计的理念,为将来进行团队合作,协同完成大型应用软件奠定一定的基础。

学习目标

正确理解函数在C语言程序设计中的作用和地位;理解函数、形参、实参、作用域、生存期的概念;掌握各种函数的定义、原型声明和调用的方法;理解全局变量、局部变量、静态变量、静态函数的作用域和生存期;掌握递归函数的编写规则;掌握利用工程管理程序的方法;

语言程序设计教程第三版第八章函数C学习内容

函数概述函数的定义与调用无参数无返回值的函数无参数有返回值的函数带参数无返回值的函数带参数有返回值的函数函数参数传递的传递方式变量的作用域和生存期变量的存储类型函数的嵌套和递归调用函数的作用域函数应用综合举例本章小结语言程序设计教程第三版第八章函数C8.1函数概述

1、函数的概念

函数其实就是一段可以重复调用的、功能相对独立完整的程序段。C是函数式语言

必须有且只能有一个名为main的主函数

C程序的执行总是从main函数开始,在main中结束

函数不能嵌套定义,可以嵌套调用2、函数的分类

从用户角度

标准函数(库函数):由系统提供用户自定义函数

从函数形式

无参数无返回值无参数有返回值有参数无返回值有参数有返回值使用库函数应注意:

1、函数功能

2、函数参数的数目和顺序,及各参数意义和类型

3、函数返回值意义和类型

4、需要使用的包含文件语言程序设计教程第三版第八章函数C8.2函数的定义和调用

1、无参数无返回值的函数

定义格式void函数名(void){

变量声明部分执行部分}函数体空类型,表明函数无返回值,不可省!表明无参数,可缺省!必须为合法的标识符

函数用途

此类函数用于完成某项固定的处理任务,执行完成后不向调用者返回函数值。它类似于其它语言的过程。

函数的原型声明void函数名(void);或void函数名();

C语言规定,对函数调用之前必须对其原型加以声明,否则会出现编译错!语言程序设计教程第三版第八章函数C1、无参数无返回值的函数

函数的调用函数名();注意:不能将这种函数调用赋值给任何变量,因为它没有返回值。调用时,()中间不能有void。

实例#include<stdio.h>#include<math.h>voidshowerror();

//声明showerror函数的原型intmain(){inta;scanf("%d",&a);while(a<0){showerror();scanf("%d",&a);}printf("sqrt(a)=%.2f\n",sqrt(a));return0;}voidshowerror()

//函数的定义,无参数无返回值{printf("inputerror!\n");//函数体,没有声明变量}调用showerror函数

返回

注意:对函数调用之前,必须要先声明或先定义,否则编译错!语言程序设计教程第三版第八章函数C

编写C程序的一般格式文件包括(如include<stdio.h>等,用于标准库库函数原型声明)常量定义(根据需要而定,如#definePI3.1415等)变量定义(根据需要而定)用户自定义函数原型声明main函数用户自定义函数

函数的返回

形式

①return(表达式);//有返回值

return表达式;//有返回值

return;//无返回值

使程序控制从被调用函数返回到调用函数中,如果有返回值,同时把返值带给调用函数。

功能

说明

函数中可以有多个return语句。在无返回值的函数中,return语句的形式只能是第③种形式。

例如:voidshowyes(){charkey;

key=getch();if(toupper(key)!='Y')

return;printf("YES!");}函数showyes的功能是:

如果输入的字符不是'Y'或'y',则什么都不输出,直接返回,否则,输出"YES!"标准库函数,其功能是将小写字符转换成大写字符

语言程序设计教程第三版第八章函数C2、无参数有返回值的函数

定义格式返回值类型符函数名(void){

变量声明部分执行部分}函数体可以为除数组类型外的任何类型表明无参数,可缺省!必须为合法的标识符

函数用途

此类函数用于完成某项固定的处理任务,执行完成后向调用者返回函数值。

函数的原型声明返回值类型符函数名(void);或

返回值类型符函数名();语言程序设计教程第三版第八章函数C

注意:函数返回值类型符在VC6.0下可以缺省,其默认为int型,但在VC2010、CB17.12下不可缺省,必须指定返回值类型,否则编译错。2、无参数有返回值的函数

函数的调用

函数名(void);或变量=函数名();

实例

#include<stdio.h>#include<conio.h>#include<ctype.h>intsum();intmain(){inttot;tot=sum();if(tot==-1)printf("\nnotselect!\n");elseprintf("\ntheresultis:%d\n",tot);return0;}intsum(){inti,tot=0;charkey;key=getche();if(key!='0'&&key!='1')

return(-1);

for(i=(key=='0')?2:1;i<=100;i+=2)tot+=i;

return(tot);}声明sum函数的原型

调用sum函数函数的定义,无参数有返回值

变量声明部分函数sum的功能是:

输入‘0’:计算1~100之间所有偶数之和

输入‘1’:计算1~100之间所有奇数之和语言程序设计教程第三版第八章函数C2、无参数有返回值的函数

函数的返回

表达式的值即是函数的返回值;函数体中一般都包含return(表达式)语句,如果没有,函数也会返回一个值。这个值是不可预知的,将会使程序可能犯有逻辑错;一般情况下,表达式值的类型应与函数返回值类型一致;当return(表达式)语句中的表达式的类型与函数的返回值类型不一致时,编译器将对表达式进行强制类型转换,将表达式的值强制转换成函数返回值类型,然后返回给调用者。

格式return(表达式);或

return表达式;

说明#include<stdio.h>intsum();voidmain(){intx;x=sum();printf(“x=%d\n",x);}intsum(){inti,tot=0;for(i=1;i<=100;i++)tot+=i;}因sum函数无return语句,x的值将是无法预知的!应加上returntot;

语句intfunc(){floatf=5;f=f/2;return(f);}函数将返回2,而不是2.5

注意:如果不将函数调用赋值给任何变量,它的返回值将被丢弃!

语言程序设计教程第三版第八章函数C3、有参数无返回值的函数

定义格式void函数名(类型符1形参名1,类型符2形参名2,…,类型符n形参名n

){

变量声明部分执行部分}函数体

函数用途

此类型的函数主要是根据形参的值来进行某种事务的处理。灵活性上要比无形参的函数强,它更能体现调用函数与被调函数之间的数据联系。

函数的原型声明void函数名(类型符1形参名1,类型符2形参名2,…,类型符n形参名n);或

void函数名(类型符1,类型符2,…,类型符n);形参列表至少要有一项,形参之间要用逗号“,”分开

指明形参类型

不允许对形参赋初值

语言程序设计教程第三版第八章函数C3、有参数无返回值的函数

函数调用函数名(实参1,实参2,……,实参n);

实参可以是常量、变量、表达式、函数等

注意事项:

(1)实参列表中的实参必须与函数定义时的形参数量相同、类型相符。

(2)赋值对应关系:

实参1->形参1

实参2->形参2……

实参n->形参n(3)实参表求值顺序(即实参赋值给形参的顺序)因系统而定。VC6.0、VC2010和CB17.12均是自右向左,也就是说最右边的实参最先赋值给最右边的形参,最左边的实参最后赋值给最左边的形参。但VC6.0与VC2010和CB17.12在具体赋值时稍有不同,注意它们之间的区别。语言程序设计教程第三版第八章函数C3、有参数无返回值的函数#include<stdio.h>voidcompare(inta,intb);intmain(){inti=2;compare(i,i++);printf("i=%d\n",i);return0;}voidcompare(inta,intb){printf("a=%db=%d\n",a,b);if(a>b)printf("a>b\n");elseif(a==b)printf("a=b\n");elseprintf("a<b\n");}i为实参

a、b为形参

原型声明

a=3b=2a>bi=3运行结果(在VC2010或CB17.12下)a=2b=2a=bi=3运行结果(在VC6.0下)①i2i++2ab实参形参2②i+13③3i2i++2ab实参形参①2②2③i+13语言程序设计教程第三版第八章函数C4、有参数有返回值的函数

定义格式返回值类型符函数名(类型符1形参名1,……,类型符n形参名n

){

变量声明部分执行部分}函数体

函数用途

此类型的函数主要是根据形参的值来进行某种事务的处理,同时可将处理后的结果值返回给调用函数

。它最能体现调用函数与被调函数之间的数据联系。

函数的原型声明返回值类型符函数名(类型符1形参名1,……,类型符n形参名n);或

返回值类型符函数名(类型符1,类型符2,……,类型符n);形参列表语言程序设计教程第三版第八章函数C4、有参数有返回值的函数

函数调用函数名(实参1,实参2,……,实参n);

或变量名=函数名(实参1,实参2,……,实参n);#include<stdio.h>intmax(inta,intb);//函数的原型声明intmain(){inta,b,c;scanf("%d%d",&a,&b);

c=max(a,b);

//函数调用(a、b为实参)printf("thebiggestnumberis:%d\n",c);return0;}intmax(inta,intb)//函数定义(a、b为形参){return(a>b?a:b);}运行结果:59↙thebiggestnumberis9语言程序设计教程第三版第八章函数C5、函数调用和函数说明小结

函数调用

函数语句:例:printstar();printf(“Hello,World!\n”);

函数表达式:

例:m=max(a,b)*2;

函数参数:

例:printf(“%d”,max(a,b));m=max(a,max(b,c));语言程序设计教程第三版第八章函数C函数说明

对被调用函数要求:必须是已存在的函数库函数:#include<*.h>用户自定义函数:函数类型说明函数说明一般形式:函数类型函数名(形参类型[形参名],…..);

或函数类型函数名();作用:告诉编译系统函数类型、参数个数及类型,以便检验函数定义与函数说明不同函数说明位置:程序的数据说明部分(函数内或外)下列情况下,可不作函数说明若函数返值是char或int型,某些系统自动按int型处理

被调用函数定义出现在主调函数之前有些系统(如VC、CB)要求函数说明指出函数返值类型和形参类型,并且对void和int型函数也要进行函数说明语言程序设计教程第三版第八章函数C例:函数说明举例intmain(){floatadd(float,float);//函数原型声明

floata,b,c;scanf("%f,%f",&a,&b);c=add(a,b);printf("sumis%f",c);return0;}floatadd(floatx,floaty){floatz;z=x+y;return(z);}语言程序设计教程第三版第八章函数Cfloatadd(floatx,floaty){floatz;z=x+y;return(z);}intmain(){floata,b,c;scanf("%f,%f",&a,&b);c=add(a,b);printf("sumis%f",c);return0;}被调函数出现在主调函数之前,不必函数说明intmain(){floata,b;intc;scanf("%f,%f",&a,&b);c=max(a,b);printf("Maxis%d\n",c);return0;}max(floatx,floaty){floatz;z=x>y?x:y;return(z);}int型函数可不作函数说明(VC、CB下不行)8.3函数参数的传递方式

1、值传递方式

根据实参传递给形参值的不同,通常有值传递方式和地址传递方式两种。

方式:函数调用时,为形参分配单元,并将实参的值复制到形参中;调用结束,形参单元被释放,实参单元仍保留并维持原值。特点:①形参与实参占用不同的内存单元

②单向传递语言程序设计教程第三版第八章函数C7x11y②

调用例:交换两个数(值传递方式)#include<stdio.h>voidswap(inta,intb);intmain(){intx=7,y=11;printf("beforeswapped:");printf("x=%d,y=%d\n",x,y);swap(x,y);

printf("afterswapped:");printf("x=%d,y=%d\n",x,y);return0;}voidswap(inta,intb){inttemp;temp=a;a=b;b=temp;}运行结果:beforeswapped:x=7,y=11afterswapped:x=7,y=117x11y①调用前7a11b③

swap7x11y7a11btemp71177x11y④

调用结束Why?语言程序设计教程第三版第八章函数C2、地址传递方式

方式:函数调用时,将数据的存储地址作为参数传递给形参特点:①形参与实参占用同样的存储单元

②双向传递③实参和形参必须是地址常量或变量用数组名作为函数参数时还应注意以下几点:

形参数组和实参数组的类型必须一致,否则将引起错误。形参数组和实参数组的长度可以不相同,因为在调用时,只传送首地址而不检查形参数组的长度。多维数组也可以作为函数的参数。在函数定义时对形参数组可以指定每一维的长度,也可省去第一维的长度。

除了用数组名作为函数参数来实现参数的地址传递以外,其实还有一种应用更广的地址传递方法,那就是用指针变量来作为函数的形参,其具体使用方法将在第9章作详细讨论。语言程序设计教程第三版第八章函数C

例:将任意两个字符串连接成一个字符串

(数组名作为函数参数实现地址传递方式)#include<stdio.h>voidmergestr(chars1[],chars2[],chars3[]);

intmain(){charstr1[]={"Hello"};charstr2[]={"china!"};charstr3[40];mergestr(str1,str2,str3);printf("%s\n",str3);return0;}voidmergestr(chars1[],chars2[],chars3[]){inti,j;for(i=0;s1[i]!='\0';i++)//将s1复制到s3中

s3[i]=s1[i];for(j=0;s2[j]!='\0';j++)//将s2复制到s3的后边

s3[i+j]=s2[j];s3[i+j]='\0';//置字符串结束标志}运行结果:Hellochina!语言程序设计教程第三版第八章函数Cstr1str2str3'H''e''l''l''o''''\0''c''h''i''n''a''!''\0's1s2s3调用前调用连接'H''e''l''l''o'''for(i=0;s1[i]!='\0';i++)s3[i]=s1[i];'c''h''i''n''a''!'for(j=0;s2[j]!='\0';j++)s3[i+j]=s2[j];'\0'补\0s3[i+j]='\0';调用结束语言程序设计教程第三版第八章函数C8.4变量的作用域和生存期

1、作用域和生存期的基本概念

变量的作用域即变量的作用范围(或有效范围)。表现为变量有的可以在整个程序或其它程序中进行引用,有的则只能在局部范围内引用。按其作用域范围可分为两种:即局部变量和全局变量

变量的生存期变量从被生成到被撤消的这段时间。实际上就是变量占用内存的时间。

按其生存期可分为两种:即动态变量和静态变量

变量只能在其生存期内被引用,变量的作用域直接影响变量的生存期。作用域和生存期是从空间和时间的角度来体现变量的特性。

语言程序设计教程第三版第八章函数C2、局部变量作用域和生存期

定义在函数内作定义说明的变量,也称为内部变量

作用域仅限于函数内,离开函数后不可再引用。

生存期从函数被调用的时刻到函数返回调用处的时刻(静态局部变量除外)。intf1(intx,inty){

intz;z=x>y?x:y;return(z);}voidf2(){printf("%d\n",z);}局部变量

变量x、y、z的作用域引用错误!语言程序设计教程第三版第八章函数C

说明(1)主函数main()中定义的变量也是局部变量,它只能在主函数中使用,其它函数不能使用。同时,主函数中也不能使用其它函数中定义的局部变量。

intf3(intx);intmain(){inta=2,b;b=a+y;printf("%d\n",b);return0;}intf3(intx){inty;y=a+5;return(y);}局部变量

变量a、b的作用域变量x、y的作用域局部变量

错误!错误!语言程序设计教程第三版第八章函数C

说明(2)形参变量属于被调用函数的局部变量;实参变量则属于全局变量或调用函数的局部变量。

(3)允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的单元,互不干扰,也不会发生混淆。#include<stdio.h>voidsubf();intmain(){

inta,b;

a=3,b=4;printf("main:a=%d,b=%d\n",a,b);subf();printf("main:a=%d,b=%d\n",a,b);return0;}voidsubf(){inta,b;a=6,b=7;printf("subf:a=%d,b=%d\n",a,b);}运行结果:main:a=3,b=4subf:a=6,b=7main:a=3,b=4变量名相同

语言程序设计教程第三版第八章函数C

说明(4)在复合语句中定义的变量也是局部变量,其作用域只在复合语句范围内。其生存期是从复合语句被执行的时刻到复合语句执行完毕的时刻。

#include<stdio.h>intmain(){

inta=2,b=4;

{intk,b;k=a+5;b=a*5;printf("k=%d\n",k);printf("b=%d\n",b);}printf("b=%d\n",b);a=k+2;return0;}main中的局部变量

复合语句中的局部变量

mian中变量a、b的作用域

复合语句中变量k、b的作用域输出k=7

输出b=10

输出b=4

错误!语言程序设计教程第三版第八章函数C3、全局变量作用域和生存期

定义在函数外部作定义说明的变量,也称为外部变量

。它不属于哪一个函数,而属于一个源程序文件。

作用域从定义变量的位置开始到本源文件结束,及有extern说明的其它源文件。

生存期与程序相同。即从程序开始执行到程序终止的这段时间内,全局变量都有效。

#include<stdio.h>#include<math.h>intsign();//计算数n的平方根floatsqr(){if(n>0)return(sqrt(n));elsereturn(-1);}floatn=0;intmain(){ints;floatt;scanf("%f",&n);s=sign();//取符号

t=sqr();//取平方根

printf("s=%dt=%f",s,t);return0;}//取数n的符号intsign(){intr=0;if(n>0)r=1;if(n<0)r=-1;return(r);}定义全局变量,并赋初值局部变量全局变量n的作用域

局部变量s、t的作用域局部变量局部变量r的作用域错误!语言程序设计教程第三版第八章函数C

说明(1)应尽量少使用全局变量。

全局变量在程序全部执行过程中始终占用存储单元降低了函数的独立性、通用性、可靠性及可移植性降低程序清晰性,容易出错(2)若外部变量与局部变量同名,则外部变量被屏蔽。要引用全局变量,则必须在变量名前家上两个冒号“::”

#include<stdio.h>inta=10;

//全局变量intmain(){

inta=100;

//局部变量(与全局变量同名)

printf("locala=%d\n",a);printf("globala=%d\n",::a);return0;}运行结果:locala=100globala=10

注意:局部变量与全局变量同名极易导致程序员犯逻辑错误。语言程序设计教程第三版第八章函数C

说明(3)全局变量定义必须在所有的函数之外,且只能定义一次,并可赋初始值。全局变量定义的一般形式为:

[extern]类型说明符全局变量名1[=初始值1],……,全局变量名n[=初始值n];可缺省!charch='Y';voidmain(){……}charch;voidfunc(){……}定义全局变量ch错误!ch只能定义一次例:inta=2,b=4;externinta=2,b=4;语言程序设计教程第三版第八章函数C

说明(4)对全局变量进行说明,可扩展全局变量的作用域。全局变量说明的一般形式为:extern

类型说明符全局变量名1,…,全局变量名n;不可缺省!不可赋初值!voidgx(),gy();voidmain(){

externintx,y;printf("1:x=%d\ty=%d\n",x,y);y=246;gx();gy();}externintx,y;voidgx(){x=135;printf("2:x=%d\ty=%d\n",x,y);}intx=0,y=0;voidgy(){printf("3:x=%d\ty=%d\n",x,y);}全局变量定义未说明前的作用域全局变量说明说明后的作用域全局变量说明说明后的作用域运行结果:

1:x=0y=02:x=135y=2463:x=135y=246语言程序设计教程第三版第八章函数C

说明(5)全局变量定义与全局变量的说明的区分

externinta;

voidfunc1(){……//引用变量a}externinta=2;

voidfunc2(){……//引用变量a}谁是定义?谁是说明?全局变量定义(因为赋了初值)全局变量说明

注意:两者中有且只能有一个对变量a赋初始值,不能都对变量a赋初始值或都不赋值,否则编译错!

语言程序设计教程第三版第八章函数C8.5变量的存储类型

概述

变量是对程序中数据的存储空间的抽象变量的属性①数据类型:变量所持有的数据的性质(操作属性)。规定了它们的取值范围和可参与的运算。②存储类型:

规定了变量占用内存空间的方式,也称为存储方式。分为静态存储和动态存储两种。

静态存储类型的变量是指在程序运行期间由系统分配固定的内存单元,并一直保持不变,直至整个程序结束,内存空间才被释放。前面所介绍的全局变量即属于此类存储方式。

动态存储类型的变量是在程序运行期间根据需要进行动态分配内存单元,使用完毕立即释放。典型的例子是函数的形式参数即属于此类存储方式。语言程序设计教程第三版第八章函数C一个C语言程序在执行时内存被分为两大块:一块是系统区,用于存放操作系统等内容,另一块是用户区,用来存放被执行的用户程序及数据

语言程序设计教程第三版第八章函数C程序区静态存储区动态存储区操作系统等系统区用户区用来存放C语言程序运行代码。用来存放变量,在这个区域中存储的变量被称作静态变量。在程序开始执行时全局变量全部放在静态存储区中,程序执行完毕就释放。在程序执行过程中它们占据固定的存储单元,而不是动态地进行分配和释放。用来存放变量以及进行函数调用时的现场信息和函数返回地址等,在这个区域存储的变量称之为动态变量,如形参变量、函数体内部定义的动态局部变量。对于存放于动态存储区的变量,是在函数调用开始时才分配动态存储空间,函数运行结束时释放这些空间。

在C语言中,对变量的存储类型说明有以下四种:auto---------自动型register-----寄存器型static-------静态型extern-------外部型[存储类型]数据类型变量名1,变量名2,…,变量名n;变量定义的完整形式应为:

例如:

autocharc1,c2;//c1,c2为自动字符变量

registeri;//i为寄存器型变量

staticinta,b;//a,b为静态整型变量

externintx,y;//x,y为外部整型变量语言程序设计教程第三版第八章函数C1、自动变量(auto型变量)[auto]数据类型说明符变量名1,变量名2,…,变量名n;

定义格式

说明

存储类型说明符auto可以省略。自动变量只能在函数内或复合语句中定义,它属于局部变量。voidfunc(){

inti,j,k;

……}等价于autointi,j,k;autointk;

voidfunc(){……}错误!自动变量不可定义在函数外

注意:在函数外部定义的没有带存储类型说明符的全局变量是外部变量,属于静态存储类型。如:intk;//k为外部变量,属静态存储类型

voidfunc(){……}语言程序设计教程第三版第八章函数C2、外部变量(extern型变量)

外部变量和全局变量是对同一类变量的两种不同角度的提法。全局变是是从它的作用域提出的,外部变量从它的存储方式提出的,表示了它的生存期。它属于静态存储类型。例:引用其它文件中的外部变量原文件prg1.cppinta,b;

//外部变量定义intmax();//外部函数声明intmain(){intc;

a=4,b=5;c=max();printf("max=%d\n",c);return0;}原文件prg2.cppexterninta,b;

//外部变量说明intmax(){return(a>b?a:b);}编译、链接、运行运行结果:

max=5语言程序设计教程第三版第八章函数C3、静态变量(static型变量)

静态变量与静态存储类型静态变量的类型说明符是static。静态变量属于静态存储类型。静态存储类型的变量不一定就是静态变量。例如外部变量虽属于静态存储类型但不一定是静态变量,必须由static加以定义后才能成为静态外部变量,或称静态全局变量。自动变量可以用static定义它为静态自动变量,或称静态局部变量,从而成为静态存储方式。

静态局部变量

在局部变量的说明前加上static就构成静态局部变量

例如:

staticinta,b;staticfloatarray[5]={1,2,3,4,5};语言程序设计教程第三版第八章函数C

静态局部变量与自动变量之比较

静态局部变量与自动变量均属于局部变量

静态局部变量生存期长,为整个源程序。自动变量生存期短。静态局部变量的生存期虽然为整个源程序,但是其作用域仍与自动变量相同voidfunc();intmain()

{inta;a=s+5;……}voidfunc(){staticints;……}定义静态局部变量s错误!s的作用域语言程序设计教程第三版第八章函数C

静态局部变量与自动变量之比较

静态局部变量若在定义时未赋初值,则系统自动赋初值0

静态局部变量赋初值只一次,而自动变量赋初值可能多次#include<stdio.h>intmain(){inti;voidfunc();//函数说明

for(i=1;i<=5;i++)func();//函数调用return0;}voidfunc()//函数定义{

autointj=0;++j;printf("%d",j);}#include<stdio.h>intmain(){inti;voidfunc();//函数说明

for(i=1;i<=5;i++)func();//函数调用return0;}voidfunc()//函数定义{

staticintj=0;++j;printf("%d",j);}自动变量静态变量运行结果:11111

运行结果:12345

语言程序设计教程第三版第八章函数C

静态全局变量

全局变量(外部变量)的说明之前再冠以static就构成了静态全局变量。全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。当一个源程序由多个源文件组成时,非静态的全局变量可通过外部变量说明使其在整个源程序中都有效。而静态全局变量只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能通过外部变量说明来使用它。

prg1.cpp

inta,b;staticcharch;

intmain(){……}

prg2.cpp

externinta,b;externcharch;

intfunc(intx,inty){……}

外部(全局)变量定义静态全局变量定义错误!语言程序设计教程第三版第八章函数C4、寄存器变量(register型变量)

这种变量存放在CPU的寄存器中,使用时,不需要访问内存,而直接从寄存器中读写,这样可提高效率。寄存器变量的说明符是register,属于动态存储类型。

intmain(){

registeri,s=0;for(i=1;i<=100;i++)s=s+i;printf("s=%d\n",s);return0;}几点说明:只有局部自动变量和形式参数才可以定义为寄存器变量。register修饰符是过时的修饰。语言程序设计教程第三版第八章函数C8.6函数的嵌套与递归调用C规定:函数定义不可嵌套,

1、函数的嵌套调用但可以嵌套调用函数main()调用函数a结束a函数b函数调用函数b

——函数嵌套调用的示意图

语言程序设计教程第三版第八章函数C过程的嵌套调用r主程序srrrs子过程1rst子过程2rst子过程3语言程序设计教程第三版第八章函数C【例】计算三个数中最大数与最小数的差。#include<stdio.h>intdif(intx,inty,intz);intmax(intx,inty,intz);intmin(intx,inty,intz);intmain(){inta,b,c,d;scanf("%d%d%d",&a,&b,&c);d=dif(a,b,c);printf("Max-Min=%d\n",d);return0;}intdif(intx,inty,intz)

{return(max(x,y,z)–min(x,y,z));}intmax(intx,inty,intz){intr;r=x>y?x:y;return(r>z?r:z);}intmin(intx,inty,intz)

{intr;r=x<y?x:y;return(r<z?r:z);}main()调用函数dif输出结束dif函数max函数调用函数max调用函数minmin函数语言程序设计教程第三版第八章函数C2、函数递归调用定义:函数直接或间接的调用自身叫函数的递归调用f()调f调f2调f1f1()f2()intf(intx){inty,z;……

z=f(y);…….return(2*z);}intf1(intx){inty,z;……

z=f2(y);…….return(2*z);}intf2(intt){inta,c;……

c=f1(a);…….return(3+c);}直接递归间接递归语言程序设计教程第三版第八章函数C说明语言程序设计教程第三版第八章函数C递归函数主要用于解决具有递归性质的问题,即无论问题规模的大小,所处理的方法和步骤都是一样的。C语言编译系统对递归函数的自调用次数没有限制。编写递归函数时不应出现无终止的递归调用,而应当在递归次数或递归调用条件上加以限制,这就是递归结束条件的问题。每调用函数一次,在内存堆栈区都要分配空间,用于存放函数变量、返回值等信息,所以应避免递归次数过多,以防止可能引起的堆栈溢出问题。【例1】递归的执行情况分析

递归过程及其实现递归:函数直接或间接的调用自身叫递归实现:建立递归工作栈运行结果:1,2,2,3,3,3,#include<stdio.h>voidprint(intw);intmain(){print(3);}voidprint(intw)

//递归函数{inti;if(w!=0)//递归结束条件

{

print(w-1);for(i=1;i<=w;++i)printf("%d",w);printf("\n");}return0;}语言程序设计教程第三版第八章函数C递归调用执行情况如下:主程序(1)print(w)w=3;3print(2);(1)w=3top(2)输出:3,3,3w2print(1);(2)w=2(1)w=3top(3)输出:2,2w1print(0);(3)w=1(2)w=2(1)w=3top(4)输出:1w0(4)w=0(3)w=1(2)w=2(1)w=3topw(3)输出:2,2(2)2(1)3top(4)输出:1(3)1(2)2(1)3top(2)输出:3,3,3(1)3top返回(3)1(2)2(1)3top(4)0结束(1)语言程序设计教程第三版第八章函数C【例2】求n的阶乘n!

longfactn(intn){longL=1;inti;for(i=1;i<=n;i++)L*=i;return(L);}

方法一:利用循环因为n!=n*(n-1)*(n-2)*…*2*1,我们完全可以用循环语句来编写这个非递归函数factn:方法二:利用递归n!=1当n=1时n*(n-1)!当n>1时longfactn(intn)

{longL;if(n==1)return(1);L=n*fact(n-1);return(L);}语言程序设计教程第三版第八章函数Cintmain(){…L=factn(4);…}递归调用执行情况如下:longfactn(4){longL;…L=4*factn(3);return(L);}longfactn(3){longL;…L=3*factn(2);return(L);}longfactn(2){longL;…L=2*factn(1);return(L);}longfactn(1){longL;…return(1);}返回1返回2返回6返回24语言程序设计教程第三版第八章函数C【例3】TowerofHanoi问题问题描述:有A,B,C三个塔座,A上套有n个直径不同的圆盘,按直径从小到大叠放,形如宝塔,编号1,2,3……n。要求将n个圆盘从A移到C,叠放顺序不变,移动过程中遵循下列原则:每次只能移一个圆盘圆盘可在三个塔座上任意移动任何时刻,每个塔座上不能将大盘压到小盘上解决方法:n=1时,直接把圆盘从A移到Cn>1时,先把上面n-1个圆盘从A移到B,然后将n号盘从A移到C,再将n-1个盘从B移到C。即把求解n个圆盘的Hanoi问题转化为求解n-1个圆盘的Hanoi问题,依次类推,直至转化成只有一个圆盘的Hanoi问题算法:nxyz返回地址

执行情况:递归工作栈保存内容:形参n,x,y,z和返回地址返回地址用行编号表示语言程序设计教程第三版第八章函数CBCAhanio(n,x,y,z)=

move(x,z)当n=1hanio(n-1,x,z,y)move(x,z)当n>1hanio(n-1,y,x,z)Hanoi问题voidmove(chargetone,charputone){printf("%c--->%c\n",getone,putone);}voidhanoi(intn,charone,chartwo,charthree){if(n==1)move(one,three);else{hanoi(n-1,one,three,two);move(one,three);

hanoi(n-1,two,one,three);}}intmain(){intm;printf("Inputthenumberofdisks:");scanf("%d",&m);printf("Thestepstomoving%3ddisks:\n",m);hanoi(m,'A','B','C');return0;}BCA语言程序设计教程第三版第八章函数Cvoidmain(){intm;printf("Inputnumberofdisks”);scanf("%d",&m);printf(”Steps:%3ddisks”,m);hanoi(m,'A','B','C');(0)}voidhanoi(intn,charx,chary,charz)(1){(2)if(n==1)(3)move(1,x,z);(4)else{(5)hanoi(n-1,x,z,y);(6)move(n,x,z);(7)hanoi(n-1,y,x,z);(8)}(9)}ABC1233ABC03ABC02ACB63ABC02ACB61ABC6ABC3ABC02ACB6语言程序设计教程第三版第八章函数Cvoidmain(){intm;printf("Inputthenumberofdisksscanf("%d",&m);printf("Thestepstomoving%3dhanoi(m,'A','B','C');(0)}voidhanoi(intn,charx,chary,charz)(1){(2)if(n==1)(3)move(1,x,z);(4)else{(5)hanoi(n-1,x,z,y);(6)move(n,x,z);(7)hanoi(n-1,y,x,z);(8)}(9)}ABC3ABC02ACB61CAB8ABC3ABC02ACB63ABC03ABC02ACB6语言程序设计教程第三版第八章函数Cvoidmain(){intm;printf("Inputthenumberofdisksscanf("%d",&m);printf("Thestepstomoving%3dhanoi(m,'A','B','C');(0)}voidhanoi(intn,charx,chary,charz)(1){(2)if(n==1)(3)move(1,x,z);(4)else{(5)hanoi(n-1,x,z,y);(6)move(n,x,z);(7)hanoi(n-1,y,x,z);(8)}(9)}ABC3ABC02BAC83ABC02BAC81BCA6ABC3ABC02BAC83ABC0语言程序设计教程第三版第八章函数Cvoidmain(){intm;printf("Inputthenumberofdisksscanf("%d",&m);printf("Thestepstomoving%3dhanoi(m,'A','B','C');(0)}voidhanoi(intn,charx,chary,charz)(1){(2)if(n==1)(3)move(1,x,z);(4)else{(5)hanoi(n-1,x,z,y);(6)move(n,x,z);(7)hanoi(n-1,y,x,z);(8)}(9)}ABC3ABC02BAC81ABC8ABC3ABC02BAC83ABC0栈空3ABC02BAC8语言程序设计教程第三版第八章函数C【例4】分书问题有编号分别为0,1,2,3,4的5本书,准备分给5个人A,B,C,D,E,每个人阅读兴趣用一个二维数组加以描述,公式如下:Like[i][j]=

1i喜欢j书0i不喜欢j书

写一个程序,输出所有分书方案,让人人皆大欢喜。假定5个人对5本书的阅读兴趣如下图所示。

人01234A00110B11001C01101D00010E01001语言程序设计教程第三版第八章函数C语言程序设计教程第三版第八章函数C

解题思路:

(1)定义一个整型的二维数组,将表中的阅读喜好用初始化方法赋给这个二维数组。可定义:

intlike[5][5]={{0,0,1,1,0},{1,1,0,0,1},{0,1,1,0,1},{0,0,0,1,0},{0,1,0,0,1}};

(2)定义一个整型一维数组book[5],用来记录书是否已被选用。用下标作为5本书的编号,被选过元素值为1,未被选过元素值为0,初始化皆为0。

intbook[5]={0,0,0,0,0};

(3)画出思路图。

①定义试着给第i人分书的函数Try(i),i=0,1,2,3,4。②试着给第i个人分书,先试分0号书,再分1号书,分2号书,……,因此有一个与结点,让j表示书,j=0,1,2,3,4。③LP为循环结构的循环体,如下图所示。Try(i)j=01234LPLPLPLPLP条件:c=(like[i][j]>0&&book[j]=0)LPc!=1c==1什么也不做sh1take[i]=j;sh2sh3book[j]=1;i==4i!=4n=n+1;输出方案nTry(i+1)book[j]=0;④条件c是由两部分“与”起来的,“第i个人喜欢j书,且j书尚未被分走”。满足这个条件是i人能够得到j书的条件。⑤如果不满足c条件,则什么也不做,这是直接可解结点。⑥满足c条件,做三件事:第一件事:将j书分给i,用一个数组take[i]=j,记住书

温馨提示

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

评论

0/150

提交评论