1、第八章第八章 函数函数 8.1 8.1 概述概述 8.2 8.2 函数定义函数定义 8.3 8.3 函数参数和函数值函数参数和函数值 8.4 8.4 函数调用函数调用 8.5 8.5 函数嵌套调用函数嵌套调用 8.6 8.6 函数递归调用函数递归调用 8.7 8.7 数组作为函数参数数组作为函数参数 8.8 8.8 局部变量和全局变量局部变量和全局变量 8.9 8.9 变量存放类别变量存放类别第八章第八章 目录目录第1页8.1 8.1 概述概述8.1 8.1 概述概述mainabcdefghhieg第2页8.1 8.1 概述概述#include“stdio.h”void printstar()
2、printf(“*n”);void print_message()printf(“How do you do!n”);void main()printstar();print_message();printstar();例例.简单函数调用。简单函数调用。运行结果运行结果*How do you do!*第3页8.1 8.1 概述概述(1)一个一个C 程序由一个或多个源程序文件组成。程序由一个或多个源程序文件组成。说明说明说明说明(2)一个源程序文件由一个或多个函数组成。一个源程序文件由一个或多个函数组成。(3)C 程序执行从程序执行从 main 函数开始,调用其它函函数开始,调用其它函 数后返回
3、到数后返回到main 函数,在函数,在main函数中结束整函数中结束整 个程序运行。个程序运行。(4)全部函数都是平行,即在定义函数时是相互全部函数都是平行,即在定义函数时是相互 独立,函数不能嵌套定义。函数间能够相互独立,函数不能嵌套定义。函数间能够相互 调用,但不能调用调用,但不能调用main函数。函数。第4页8.1 8.1 概述概述(5)从函数使用角度来看,从函数使用角度来看,C C语言函数能够分语言函数能够分 为两类:标准库函数和用户自定义函数。为两类:标准库函数和用户自定义函数。标准库函数与头文件标准库函数与头文件执行效率高,用户需要时,可在程序中直接进执行效率高,用户需要时,可在程
4、序中直接进行调用。行调用。C C语言库函数所用到常量、外部变量、函数类型语言库函数所用到常量、外部变量、函数类型和参数说明,都在对应头文件和参数说明,都在对应头文件(.h)(.h)中申明,这些中申明,这些文件通常存放在系统目录文件通常存放在系统目录includeinclude。用户自定义函数用户自定义函数 无参函数无参函数 有参函数有参函数第5页8.2 8.2 函数定义函数定义8.2 8.2 函数定义函数定义有参函数定义有参函数定义有参函数定义有参函数定义形式一形式一形式一形式一函数值类型函数值类型 函数名函数名(形式参数类型及参数说明形式参数类型及参数说明)申明部分申明部分 语句语句 函数返
5、回值类型,函数返回值类型,能够是简单类型、能够是简单类型、voidvoid类型或结构类类型或结构类型等。型等。函数名是函数标识符,函数名是函数标识符,遵照遵照C C语言标识符命语言标识符命名规则,区分大小写。名规则,区分大小写。如如:int max(int a,int b)形式参数简称形参。形式参数简称形参。注意:不论函数是否注意:不论函数是否有形式参数,圆括号有形式参数,圆括号不可省。不可省。第6页8.2 8.2 函数定义函数定义有参函数定义有参函数定义有参函数定义有参函数定义形式二形式二形式二形式二函数值类型函数值类型 函数名函数名(形式参数列表形式参数列表)形式参数说明形式参数说明 申明
6、部分申明部分 语句语句 如如:int max(a,b)int a,b;第7页8.2 8.2 函数定义函数定义例例.定义符号函数定义符号函数sign。int sign(int x)int y;y=x0?1:(x=0?0:-1);return y;/*函数返回值类型未说明,默认为函数返回值类型未说明,默认为int,提议给出函数类型说明,提议给出函数类型说明*/*形式参数说明形式参数说明*/*函数局部变量函数局部变量*/*返回函数值返回函数值*/第8页8.3 8.3 函数参数和函数值函数参数和函数值8.3 8.3 函数参数和函数值函数参数和函数值11.形式参数和实际参数形式参数和实际参数形式参数和实
7、际参数形式参数和实际参数实参实参调用函数使用参数调用函数使用参数形参形参定义函数使用参数定义函数使用参数单向值单向值传递传递复制复制单向值传递方式是指在函数调用时,将实参单向值传递方式是指在函数调用时,将实参之值传递给对应形式参数,使形参含有与实之值传递给对应形式参数,使形参含有与实参相同值。参相同值。第9页8.3 8.3 函数参数和函数值函数参数和函数值例例.调用函数时数据传递。调用函数时数据传递。#include“stdio.h”int max(int x,int y)/*定义有参函数定义有参函数*/int z;z=xy?x:y;return(z);运行情况运行情况7,8 Max is 8
8、abxyvoid main()int a,b,c;scanf(“%d,%d”,&a,&b);c=max(a,b);printf(“Max is%dn”,c);第10页8.3 8.3 函数参数和函数值函数参数和函数值相关形参加实参几点说明:相关形参加实参几点说明:相关形参加实参几点说明:相关形参加实参几点说明:实参能够是常量、变量或表示式。不论是何种实参能够是常量、变量或表示式。不论是何种类型,函数调用时,必须有确定值,方便将值类型,函数调用时,必须有确定值,方便将值传递给形参。传递给形参。在函数定义中指定形参,未调用时,它们不在函数定义中指定形参,未调用时,它们不占用存放单元。只有调用该函数时
9、,形参才占用存放单元。只有调用该函数时,形参才被分配空间,函数调用结束后,形参所占存被分配空间,函数调用结束后,形参所占存放单元被释放。放单元被释放。第11页8.3 8.3 函数参数和函数值函数参数和函数值实参加形参数据传递为单向传递,只可由实参实参加形参数据传递为单向传递,只可由实参向形参传递,不能由形参传回实参。实参加形向形参传递,不能由形参传回实参。实参加形参处于不一样函数中,作用区域不一样,即使参处于不一样函数中,作用区域不一样,即使实参加形参同名,也是不一样变量。实参加形参同名,也是不一样变量。定义函数时,必须指定形参类型。调用函数定义函数时,必须指定形参类型。调用函数时,实参类型、
10、个数及排列次序应与形参一时,实参类型、个数及排列次序应与形参一一对应。一对应。第12页8.3 8.3 函数参数和函数值函数参数和函数值22.函数返回值函数返回值函数返回值函数返回值功效功效 用于结束函数执行并返回到调用者。用于结束函数执行并返回到调用者。用来向主调函数传递一个返回值。用来向主调函数传递一个返回值。return语句表示形式语句表示形式 return 表示式表示式;or return(表示式表示式);第13页8.3 8.3 函数参数和函数值函数参数和函数值int sign(int x)int y;return y=x0?1:(x=0?0:-1);if(x0)return(1);el
11、se if(xy?x:y;return(z);void main()float a,b,c;scanf(“%f,%f”,&a,&b);c=max(a,b);printf(“Max is%fn”,c);运行情况运行情况1.5,2.5 Max is 2.000000第16页8.3 8.3 函数参数和函数值函数参数和函数值注意注意:为了明确表示为了明确表示“不带返回值不带返回值”,能够用,能够用“void”定义定义“无类型无类型”。此时函数体内不。此时函数体内不得出现得出现return语句。语句。如:如:void main()第17页8.3 8.3 函数参数和函数值函数参数和函数值例例.写出以下程序
12、运行结果。写出以下程序运行结果。max()/*函数类型缺省,为函数类型缺省,为int型,型,return语句缺省语句缺省*/运行结果运行结果-256,-256 /*/*返回值不确定,返回值不确定,TC2TC2返回值为返回值为0*/0*/min()/*函数类型缺省,函数类型缺省,return语句缺省语句缺省*/main()printf(%d,%dn,max(),min()););第18页8.4 8.4 函数调用函数调用8.4 8.4 函数调用函数调用11.函数调用形式函数调用形式函数调用形式函数调用形式 函数名(实参表列)函数名(实参表列)一个函数一旦被定义,就可在程序一个函数一旦被定义,就可在
13、程序 其它函数中使用它,这个过程称为函其它函数中使用它,这个过程称为函 数调用。数调用。说明:说明:说明:说明:实际参数之间以实际参数之间以“,”分隔。分隔。实参加形参应保持个数、次序及类型一致,实参加形参应保持个数、次序及类型一致,以确保实参加形参之间数据正确传递。以确保实参加形参之间数据正确传递。实参普通为表示式,能够是常量、变量(调实参普通为表示式,能够是常量、变量(调用时必须有确定值或确定地址)。用时必须有确定值或确定地址)。形参必须为变量。形参必须为变量。第19页8.4 8.4 函数调用函数调用函数调用三种形式函数调用三种形式函数调用三种形式函数调用三种形式函数语句函数语句调用调用函
14、数表示式函数表示式调用调用函数参数函数参数调用调用在函数调用后加在函数调用后加“;”“;”,组成一个语句。,组成一个语句。目标是执行一个动作或完成特定功目标是执行一个动作或完成特定功效。效。函数调用作为表示式一部分。函数调用作为表示式一部分。被调用函数执行结果为主调函数提供被调用函数执行结果为主调函数提供一个值。一个值。主调函数经过表示式接收值。主调函数经过表示式接收值。被调函数作为某个函数一个参数。被调函数作为某个函数一个参数。第20页8.4 8.4 函数调用函数调用例例.函数语句调用与函数表示式调用。函数语句调用与函数表示式调用。#include“stdio.h”void main()pr
15、intf(nk1=%d,printf(nk2);运行结果运行结果k2k1=3第21页8.4 8.4 函数调用函数调用例例.函数参数调用形式调用函数函数参数调用形式调用函数max2 。#include“stdio.h”int max2(int x,int y)/*求两个数中较大求两个数中较大*/int z;return(z=xy?x:y);void main()int a,b,c;scanf(“%d,%d,%d”,&a,&b,&c);printf(“Max is%dn”,max2(max2(a,b),c);/*内层函数内层函数max2值作为外层函数值作为外层函数max2实参,整个函数实参,整个函
16、数max2值又作函数值又作函数printf实参实参*/第22页8.4 8.4 函数调用函数调用22.函数申明函数申明函数申明函数申明调用用户自定义函数时,普通在主调函调用用户自定义函数时,普通在主调函数中对被调用函数返回值类型、函数名数中对被调用函数返回值类型、函数名称、函数形参类型进行说明,这种说明称、函数形参类型进行说明,这种说明称为函数申明。称为函数申明。#include“stdio.h”void main()float add(float x,float y);/*对被调用函数申明对被调用函数申明*/float a,b,c;scanf(“%f,%f”,&a,&b);c=add(a,b)
17、;printf(“sum is%fn”,c);float add(float x,float y)/*函数首部函数首部*/return(x+y);/*函数体函数体*/第23页8.4 8.4 函数调用函数调用函数申明普通形式:函数申明普通形式:函数申明普通形式:函数申明普通形式:类型类型 函数名函数名(类型类型1 1 形参形参1,1,类型类型2 2 形参形参2,);2,);注意注意:函数申明是以语句形式出现,所以其后有语句结函数申明是以语句形式出现,所以其后有语句结束标识束标识“;”。类型类型 函数名函数名(类型类型1,1,类型类型2,);2,);第24页8.4 8.4 函数调用函数调用以下两种
18、情况,能够省略对被调用函数申明:以下两种情况,能够省略对被调用函数申明:以下两种情况,能够省略对被调用函数申明:以下两种情况,能够省略对被调用函数申明:若函数定义放在主调函数之前,若函数定义放在主调函数之前,遵照先定义后调用标准遵照先定义后调用标准,函数申函数申明能够省略。明能够省略。第25页8.4 8.4 函数调用函数调用#include“stdio.h”float add(float x,float y)/*函数首部函数首部*/return(x+y);/*函数体函数体*/void main()float a,b,c;scanf(“%f,%f”,&a,&b);c=add(a,b);print
19、f(“sum is%fn”,c);第26页8.4 8.4 函数调用函数调用假如已在全部函数定义之前,在函数外假如已在全部函数定义之前,在函数外部已做了函数申明,则在各个主调函数部已做了函数申明,则在各个主调函数中无须对所调用函数再作申明。中无须对所调用函数再作申明。第27页8.4 8.4 函数调用函数调用比如:比如:char letter(char,char);float f(float,float);void main()char letter(char c1,char c2)float f(float x,float y)第28页8.4 8.4 函数调用函数调用例例.判断两个数大小。判断两
20、个数大小。#include“stdio.h”void main()int f(int,int);int i=2,p;p=f(i,i+);printf(“%dn”,p);f(int a,int b)int c;if(ab)c=1;else if(a=b)c=0;else c=-1;return(c);运行结果:运行结果:1第29页8.4 8.4 函数调用函数调用例例.编程求两个整数阶乘之和。编程求两个整数阶乘之和。void main()int n1,n2;long sum;long fac(int);/*fac函数申明函数申明*/scanf(%d,%d,&n1,&n2);sum=fac(n1)+
21、fac(n2);printf(%d!+%d!=%ldn,n1,n2,sum);/*定义函数定义函数fac,其功,其功效是求效是求n!*/long fac(int n)int i;long r=1;for(i=1;i=n;i+)r=r*i;return r;第30页8.5 8.5 函数嵌套调用函数嵌套调用8.5 8.5 函数嵌套调用函数嵌套调用定义定义定义定义所谓函数嵌套调用是指一个函数调用另一函数过所谓函数嵌套调用是指一个函数调用另一函数过程中又出现对其它函数调用。程中又出现对其它函数调用。这种嵌套调用层次标准上不限制。这种嵌套调用层次标准上不限制。main函数函数1调用函数调用函数12函数函
22、数1调用函数调用函数234函数函数25678结束结束9第31页8.5 8.5 函数嵌套调用函数嵌套调用例例.用弦截法求方程根用弦截法求方程根方法:方法:xy第32页8.5 8.5 函数嵌套调用函数嵌套调用N-S流程图流程图输入输入x1、x2,求求f(x1)、f(x2)直到直到f(x1)和和f(x2)异异号号真真假假x1=xy1=yx2=xy2=y直到直到|y|1e-4|y|0)x1=x;y1=y;else x2=x;while(fab(y)=1e-4);return(x);第35页8.5 8.5 函数嵌套调用函数嵌套调用/*续上续上*/void main()/*主函数主函数*/float x1
23、,x2,f1,f2,x;do printf(input x1,x2:n);scanf(%f,%f,&x1,&x2);f1=f(x1);f2=f(x2);while(f1*f2=0);x=root(x1,x2);printf(x=%.4fn,x);运行情况运行情况input x1,x2:2,6 x=5.0000第36页8.5 8.5 函数嵌套调用函数嵌套调用main函数函数调用调用root函数函数root函数函数调用调用xpoint函数函数xpoint函数函数输出根输出根x结束结束调用调用f函数函数f函数函数第37页8.6 8.6 函数递归调用函数递归调用8.6 8.6 函数递归调用函数递归调用
24、定义定义定义定义在调用一个函数过程中又出现直接或间接地调用在调用一个函数过程中又出现直接或间接地调用该函数本身。该函数本身。直接调用直接调用间接调用间接调用f函数函数调用调用f函数函数f1函数函数调用调用f2函数函数f2函数函数调用调用f1函数函数第38页8.6 8.6 函数递归调用函数递归调用不论是直接还是间接递归,二者都是无终止调用不论是直接还是间接递归,二者都是无终止调用本身。要防止这种情况发生,使用递归处理问题本身。要防止这种情况发生,使用递归处理问题应满足两个基本条件:应满足两个基本条件:问题转化。有些问题不能直接求解或难以求问题转化。有些问题不能直接求解或难以求解,但能够转化为一个
25、新问题,这个新问题解,但能够转化为一个新问题,这个新问题相对较原问题简单或更靠近处理方法。这个相对较原问题简单或更靠近处理方法。这个新问题处理与原问题一样,能够转化为下一新问题处理与原问题一样,能够转化为下一个新问题,个新问题,。转化终止条件。原问题到新问题转化是有条转化终止条件。原问题到新问题转化是有条件、次数是有限,不能无限次数地转化下去。件、次数是有限,不能无限次数地转化下去。这个终止条件也称为边界条件。这个终止条件也称为边界条件。第39页8.6 8.6 函数递归调用函数递归调用分析:分析:例例.有有5个人,问第个人,问第5个人多少岁?他说比第个人多少岁?他说比第4个人大个人大 2岁,第
26、岁,第4个人说比第个人说比第3个人大个人大2岁,第岁,第3个人说比个人说比 第第2个人大个人大2岁,第岁,第2个人说比第个人说比第1个人大个人大2岁,第岁,第 1个人说他个人说他10岁。请问第岁。请问第5个多大。个多大。第40页8.6 8.6 函数递归调用函数递归调用age(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回推回推递推递推第41页8.6 8.6 函数递归调用函数递归调用参考程序:参考程序:int age(int n)/*求年纪
27、递归函数求年纪递归函数*/int c;if(n=1)c=10;else c=age(n-1)+2;return(c);#include“stdio.h”void main()/*主函数主函数*/printf(%dn,age(5);age(5)c=age(4)+2c=age(1)+2c=10输出输出age(5)age函数函数n=5age函数函数n=2age函数函数n=1age(5)=18age(1)=10age(2)=12main第42页8.6 8.6 函数递归调用函数递归调用分析:分析:(1)用用递推法递推法,123n。(2)用用递归法:递归法:例例.用递归法求用递归法求n!。第43页8.6
28、8.6 函数递归调用函数递归调用参考程序:参考程序:float fac(int n)float k;if(n=1)k=1;else k=n*fac(n-1);return(k);void main()int n;float y;scanf(%d,&n);y=fac(n);printf(%d!=%.0fn,n,y);fac(5)k=fac(4)*5k=fac(1)*2k=1输出输出fac(5)fac函数函数n=5fac函数函数n=2fac函数函数n=1fac(5)=120fac(1)=1fac(2)=2main第44页8.6 8.6 函数递归调用函数递归调用例例.汉诺(汉诺(Hanoi)塔问题。
29、)塔问题。这是一个古典数学问题,只能用递归方法处理。问这是一个古典数学问题,只能用递归方法处理。问题是这么:有三个底座,题是这么:有三个底座,A A座上放着座上放着6464个盘子,小个盘子,小在上,大在下,目标是把在上,大在下,目标是把6464个盘子从个盘子从A A座移到座移到C C座上,座上,B B座作为中间过渡。每次只能移动一个盘子,而且座作为中间过渡。每次只能移动一个盘子,而且大盘子不能放在小上面。大盘子不能放在小上面。ABC第45页8.6 8.6 函数递归调用函数递归调用分析:分析:把把3个盘子从个盘子从A座移到座移到C座过程:座过程:(1)将将A上上2个盘子移到个盘子移到B(借助借助
30、C)。(2)将将A上上1个盘子移到个盘子移到C。(3)将将B上上2个盘子移到个盘子移到C(借助借助A)。ACABCBACBBABCAC第46页8.6 8.6 函数递归调用函数递归调用分析:分析:对于把对于把n(n1)个盘子从个盘子从A座移到座移到C座问题能够分座问题能够分解成以下步骤:解成以下步骤:(1)将将n-1个盘子从个盘子从A经过经过C移动到移动到B。(2)将第将第n个个(最底下最底下)盘子移动到盘子移动到C。(3)再将再将n-1个盘子从个盘子从B经过经过A移动到移动到C。这么就把移动这么就把移动n n个个盘子盘子问题转化为移动问题转化为移动n-1n-1个个盘子盘子问题,即移动问题,即移
31、动n n个个盘子盘子问题可用移动问题可用移动n-1n-1个个盘盘子子问题递归描述,以这类推,可转化为移动一个问题递归描述,以这类推,可转化为移动一个盘子盘子问题。显然,一个盘子就能够直接移动。问题。显然,一个盘子就能够直接移动。第47页8.6 8.6 函数递归调用函数递归调用#include“stdio.h”void main()int n;void hanoi(int,char,char,char);void move(char,char);printf(Input n:);scanf(%d,&n);hanoi(n,A,B,C);/*n个盘子从个盘子从A座经过座经过B座移动座移动C座座*/参
32、考程序:参考程序:int i=0;/*i/*i为移动次数,为全局变量为移动次数,为全局变量*/*/void move(char from,char to)i+;printf(%d=%c-%cn,i,from,to);第48页8.6 8.6 函数递归调用函数递归调用void hanoi(int n,char src,char t,char dest)/*将将n个盘子从个盘子从src借助借助t移到移到dest*/if(n=0)return;if(n=1)move(src,dest);else hanoi(n-1,src,dest,t);/*将将n-1个盘子从个盘子从src经经t移到移到dest*/
33、move(src,dest);/*将最底下盘子从将最底下盘子从src移到移到dest*/hanoi(n-1,t,src,dest);/*将将n-1个盘子从个盘子从t经经src移到移到dest*/第49页8.7 8.7 数组作为函数参数数组作为函数参数8.7 8.7 数组作为函数参数数组作为函数参数11.数组元素作函数实参数组元素作函数实参数组元素作函数实参数组元素作函数实参单向值传递单向值传递使用时与普通变量一样。使用时与普通变量一样。在函数调用时将值传递给在函数调用时将值传递给实参实参形参形参第50页8.7 8.7 数组作为函数参数数组作为函数参数例例.数组中有数组中有1010个整型元素,求
34、数组中全部素数之和。个整型元素,求数组中全部素数之和。#include math.h#include stdio.hvoid main()int a10,i,s=0;int prime(int);printf(请输入请输入1010个整数个整数:n);for(i=0;i10;i+)scanf(%d,&ai);if(prime(ai)s+=ai;printf(sum=%dn,s);int prime(int x)int f=1,k;if(x=1)f=0;els for(k=2;k=sqrt(x);k+)if(x%k=0)f=0;break;return(f);第51页8.7 8.7 数组作为函数参
35、数数组作为函数参数22.数组名作函数参数数组名作函数参数数组名作函数参数数组名作函数参数地址传递方式地址传递方式,实参加形参共地址,实参加形参共地址,相当于对同一对象两个不一样名字。相当于对同一对象两个不一样名字。实参加形参都应用数组名实参加形参都应用数组名(或指针或指针变量变量)。在函数调用时将在函数调用时将其其地址值地址值传递给传递给实参实参形参形参第52页8.7 8.7 数组作为函数参数数组作为函数参数例例.分析下面程序运行结果。分析下面程序运行结果。#include“stdio.h”int f(int b,int m,int n)int i,s=0;for(i=m-1;in;i+)s=
36、s+bi;return s;void main()int x,a=1,2,3,4,5,6,7,8,9;x=f(a,3,7);printf(%dn,x);运行结果运行结果253a24a35a46a57a68a79a82a11a0起始起始地址地址1000b2 b3 b4 b5 b6 b7 b8b1b0第53页8.7 8.7 数组作为函数参数数组作为函数参数例例.用选择法对数组中用选择法对数组中1010个整数从小到大排序。个整数从小到大排序。#include“stdio.h”void sort(int b,int n)int i,j,k,t;for(i=0;in-1;i+)min=i;for(j=i
37、+1;jn;j+)if(bjbmin)min=j;t=bi;bi=bmin;bmin=t;void main()int a10,i;printf(请输入请输入10个整数个整数:n);for(i=0;i10;i+)scanf(%d,&ai);sort(a,10);printf(排序后为排序后为:n);for(i=0;i10;i+)printf(%6d,ai);printf(n);第54页8.7 8.7 数组作为函数参数数组作为函数参数说明说明说明说明实参数组与形参数组类型应一致。实参数组与形参数组类型应一致。C C编译对形参数组大小不做检验,所以形参数编译对形参数组大小不做检验,所以形参数组能够
38、不指定大小。组能够不指定大小。数组名作函数参数时,是把实参数组首地址数组名作函数参数时,是把实参数组首地址传递给形参数组,这么两个数组共用一段内传递给形参数组,这么两个数组共用一段内存单元。存单元。在主调函数和被调用函数中要分别定义数组。在主调函数和被调用函数中要分别定义数组。第55页8.7 8.7 数组作为函数参数数组作为函数参数33.多维数组名作函数参数多维数组名作函数参数多维数组名作函数参数多维数组名作函数参数多维数组名能够作为实参和形参,在多维数组名能够作为实参和形参,在被调用函数中对形参数组定义时能够被调用函数中对形参数组定义时能够省略第一维大小。省略第一维大小。多维数组元素能够作为
39、实参,使用多维数组元素能够作为实参,使用时与普通变量一样。时与普通变量一样。在函数调用时将在函数调用时将其地址值传递给其地址值传递给实参实参形参形参第56页8.7 8.7 数组作为函数参数数组作为函数参数例例.求求34矩阵中最大值矩阵中最大值。#include“stdio.h”int max(int array4)int i,j,m=array00;for(i=0;i3;i+)for(j=0;j4;j+)if(mb?a:b;int z;z=a*a;return z;第64页8.9 8.9 变量存放类别变量存放类别随函数调用而存在,随函数返回而消失,随函数调用而存在,随函数返回而消失,它它们在一
40、次调用结束到下一次调用开始之间不们在一次调用结束到下一次调用开始之间不再占有存放空间。再占有存放空间。作用域局限于所定义函数,其生存期就是函作用域局限于所定义函数,其生存期就是函数生存期。数生存期。假如不初始化,其值是不确定;假如初始化,假如不初始化,其值是不确定;假如初始化,则赋值操作是在调用时进行则赋值操作是在调用时进行(不是编译时不是编译时),且,且每次调用都要重新赋一次初值。每次调用都要重新赋一次初值。第65页2.2.静态静态(static)局部局部变量变量8.9 8.9 变量存放类别变量存放类别定义格式:定义格式:static 数据类型数据类型 变量表;变量表;函数内部定义静态变量。
41、函数内部定义静态变量。作用域与自动型变量相同作用域与自动型变量相同。当所在函数执行结束后,静态变量所当所在函数执行结束后,静态变量所占内存单元并不释放,其值依然保留。占内存单元并不释放,其值依然保留。注意注意:把局部变量改变为静态局部变量后,改变了把局部变量改变为静态局部变量后,改变了它生存期。它生存期。第66页8.9 8.9 变量存放类别变量存放类别例例.考查静态局部变量值。考查静态局部变量值。#include“stdio.h”int f(int a)int b=0;static int c=3;b+;c+;printf(%d%d%d,a,b,c);return(a+b+c);void ma
42、in()int a=2,k;for(k=0;k3;k+)printf(%5dn,f(a);运行结果运行结果2 1 4 72 1 5 82 1 6 9结论:结论:局部静态变量只赋初值局部静态变量只赋初值一次,以后每次调用函一次,以后每次调用函数时不再重新赋初值,数时不再重新赋初值,而是保留上次函数调用而是保留上次函数调用结束时值。结束时值。第67页8.9 8.9 变量存放类别变量存放类别例例.考查静态局部变量值。考查静态局部变量值。#include“stdio.h”int fun(int n)static int f=1;f=f*n;return(f);void main()int k;for(
43、k=1;ky?x:y;return(z);void main()extern int A,B;/*申明外部变量申明外部变量*/printf(“%dn”,max(A,B);int A=13,B=-8;/*定义外部变量定义外部变量*/第72页8.9 8.9 变量存放类别变量存放类别(2)(2)在多文件程序中申明外部变量在多文件程序中申明外部变量在多文件程序中申明外部变量在多文件程序中申明外部变量若变量定义与引用处于不一样源文件中,则需若变量定义与引用处于不一样源文件中,则需要在引用该变量源文件中对它进行申明,然后要在引用该变量源文件中对它进行申明,然后源文件或文件中函数才能引用它,即将变量作源文件
44、或文件中函数才能引用它,即将变量作用域延伸到其它源文件。用域延伸到其它源文件。在引用外部变量在引用外部变量 文件中不会为其分配内存空文件中不会为其分配内存空间。间。第73页8.9 8.9 变量存放类别变量存放类别例例.用用extern将外部变量作用域扩展到其它文件。将外部变量作用域扩展到其它文件。#include“stdio.h”int A=1;/在在s.c文件定义了全局变量文件定义了全局变量A*/void fun()/*在函数在函数fun中引用变量中引用变量A无须申明无须申明*/void main()/*在函数在函数main中引用变量中引用变量A无须申明无须申明*/extern A;/*申明
45、变量申明变量A为一个已定义外部变量为一个已定义外部变量*/void fac(int n)A=A*n;/*在函数在函数fac外已申明外已申明A为外部变量,函数为外部变量,函数fac能够引用能够引用A*/*源文件源文件s.c*/*源文件源文件d.c*/第74页8.9 8.9 变量存放类别变量存放类别5.用用static申明外部变量申明外部变量在程序设计中假如希望一些外部变量只限于在程序设计中假如希望一些外部变量只限于被本文件引用,而不能其它文件引用。能够被本文件引用,而不能其它文件引用。能够在定义外部变量时加一个在定义外部变量时加一个static申明。申明。file1.cstatic int A;
46、void main()file2.cextern int A;void fun(int n)A=A*n;第75页8.9 8.9 变量存放类别变量存放类别注意注意:对局部变量用对局部变量用static申明,则改变了该变量申明,则改变了该变量生存期,使它在整个程序执行期间不释放,生存期,使它在整个程序执行期间不释放,为其分配空间一直存在。为其分配空间一直存在。对全局变量用对全局变量用static申明,则改变了该变量申明,则改变了该变量作用域,即只限于本文件模块使用。作用域,即只限于本文件模块使用。静态静态外部变量外部变量函数外部定义静态变量。函数外部定义静态变量。作用域仅限所在源程序文件。作用域仅
47、限所在源程序文件。第76页关于变量申明和定义关于变量申明和定义8.9 8.9 变量存放类别变量存放类别定义:建立存放空间申明定义:建立存放空间申明 申明:不建立存放空间申明申明:不建立存放空间申明注意注意:外部变量定义和申明外部变量定义和申明 外部型变量定义只有一次,它在全部函数之外部型变量定义只有一次,它在全部函数之外,而同一文件中外部变量申明能够有屡次,外,而同一文件中外部变量申明能够有屡次,它能够在函数内也可在函数外。它能够在函数内也可在函数外。比如:比如:void main()extern A;/*申明申明A是一个已定义外部变量是一个已定义外部变量*/int A;/*定义外部变量定义外
48、部变量*/对外部型变量初始化只能在定义时进行,而对外部型变量初始化只能在定义时进行,而不能在申明时进行。不能在申明时进行。第77页存放类别小结存放类别小结8.9 8.9 变量存放类别变量存放类别局部变量局部变量全局变量全局变量自动变量自动变量,即动态局部变量即动态局部变量(离开函数离开函数,值就消失值就消失)静态外部变量静态外部变量(只限本文件引用只限本文件引用)静态局部变量静态局部变量(离开函数,值仍保留离开函数,值仍保留)存放器变量存放器变量(离开函数离开函数,值就消失值就消失)外部变量外部变量(即非即非静态外部变量,允许其它文件引用静态外部变量,允许其它文件引用)(1)从作用域角度分为从
49、作用域角度分为(形式参数能够定义为自动变量或存放器变量形式参数能够定义为自动变量或存放器变量)第78页8.9 8.9 变量存放类别变量存放类别动态存放动态存放静态存放静态存放自动变量自动变量(本函数内有效本函数内有效)静态局部变量静态局部变量(函数内有效函数内有效)存放器变量存放器变量(本函数内有效本函数内有效)静态外部变量静态外部变量(本文件内有效本文件内有效)(2)从生存期角度分为从生存期角度分为形式参数形式参数(本函数内有效本函数内有效)外部变量外部变量(其它文件能够引用其它文件能够引用)第79页8.9 8.9 变量存放类别变量存放类别内存中内存中静态存放区静态存放区内存中内存中动态存取
50、区动态存取区静态局部变量静态局部变量自动变量和形式参数自动变量和形式参数静态外部变量静态外部变量(函数外部静态变量函数外部静态变量)(3)从变量值存放位置分为从变量值存放位置分为外部变量外部变量(其它文件能够引用其它文件能够引用)存放器变量存放器变量CPUCPU中中存放器存放器第80页课堂练习课堂练习 课堂练习课堂练习写出程序运行结果写出程序运行结果:#include“stdio.h”int x=1;void main()int func(int);printf(%dn,x);func(int x)x=3;运行结果:运行结果:1第81页课堂练习课堂练习 课堂练习课堂练习写出程序运行结果写出程序