1、第第4 4章章 函函 数数 C语语言言是是经经过过函函数数来来实实现现模模块块化化程程序序设设计计。所所以以较较大大C语语言言应应用用程程序序,往往往往是是由由多多个个函函数数组组成成,每每个个函函数数分分别别对对应应各自功效模块。各自功效模块。l 函数定义与调用函数定义与调用l 函数嵌套调用与递归调用函数嵌套调用与递归调用l 内部变量与外部变量内部变量与外部变量l 内部函数与外部函数内部函数与外部函数l 变量动态存放与静态存放变量动态存放与静态存放 第1页函数定义与调用函数定义与调用l函数定义函数定义l函数返回值与函数类型函数返回值与函数类型l对被调用函数说明和函数原型对被调用函数说明和函数
2、原型l函数调用函数调用l函数形参加实参函数形参加实参 第2页函数定义函数定义1任任何何函函数数(包包含含主主函函数数main())都都是是由由函函数数说说明明和和函函数数体体两两部部分分组组成成。依依据据函函数数是是否否需需要要参参数数,可可将函数分为无参函数和有参函数两种。将函数分为无参函数和有参函数两种。(1)无参函数普通形式)无参函数普通形式 函数类型函数类型 函数名函数名(void)说明语句部分;说明语句部分;可执行语句部分;可执行语句部分;如:如:int func()注注意意:在在旧旧标标准准中中,函函数数能能够够缺缺省省参参数数表表。但但在在新新标标准准中中,函函数数不不可可缺缺省
3、省参参数数表表;假假如如不不需需要要参参数数,则则用用“void”表示,主函数表示,主函数main()例外。例外。第3页void func()printf(*n);printf(printed in funcn);printf(*n);main()func();printf(this is printed in mainn);例程func0_b.c第4页(2)有参函数普通形式)有参函数普通形式函函数数类类型型 函函数数名名(数数据据类类型型 参参数数,数数据据类类型型 参参数数2)说明语句部分;说明语句部分;可执行语句部分;可执行语句部分;例:例:int func(int a,int b).有
4、有参参函函数数比比无无参参函函数数多多了了一一个个参参数数表表。调调用用有有参参函函数数时时,调调用函数将赋予这些参数实际值。用函数将赋予这些参数实际值。为为了了与与调调用用函函数数提提供供实实际际参参数数区区分分开开,将将函函数数定定义义中中参参数数表表称为形式参数表,简称形参表。称为形式参数表,简称形参表。第5页int add(int x,int y)int sum;sum=x+y;return sum;main()int a,b,c;scanf(%d,%d,&a,&b);c=add(a,b);printf(%d+%d=%dn,a,b,c);例程func_b.c第6页案例案例 定义一个函数
5、,用于求两个数中较大数。定义一个函数,用于求两个数中较大数。/*功效:定义一个求较大数函数并在主函数中调用功效:定义一个求较大数函数并在主函数中调用*/int max(int n1,int n2)return(n1n2?n1:n2);main()int max(int n1,int n2);/*函数说明函数说明*/int num1,num2;printf(input two numbers:n);scanf(%d,%d,&num1,&num2);printf(max=%dn,max(num1,num2);getchar();/*使程序暂停,按任一键继续使程序暂停,按任一键继续*/例程func.
6、c第7页2说明说明(1)函数定义不允许嵌套函数定义不允许嵌套。在在语语言言中中,全全部部函函数数(包包含含主主函函数数main())都都是是平平行行。一一个个函函数数定定义义,能能够够放放在在程程序序中中任任意意位位置置,主主函函数数main()之之前前或或之之后后。但但在在一一个个函函数数函函数数体体内内,不不能能再再定定义义另另一一个个函函数数,即即不不能能嵌嵌套套定义。定义。(2)空函数)空函数:既无参数、函数体又为空函数。其普通形式为既无参数、函数体又为空函数。其普通形式为:函数类型函数类型 函数名函数名(void)(3)在在老老版版本本C语语言言中中,参参数数类类型型说说明明允允许许
7、放放在在函函数数说说明明部部分分第第2行单独指定。行单独指定。int max(x,y)int x,y;例程func9.c第8页函数形参加实参及程序执行次序l函函数数参参数数分分为为形形参参和和实实参参两两种种,作作用用是是实实现现数数据传送。据传送。l形参出现在函数定义中,只能在该函数体内使形参出现在函数定义中,只能在该函数体内使用。发生函数调用时,调用函数把实参值复制用。发生函数调用时,调用函数把实参值复制1份,传送给被调用函数形参,从而实现调用份,传送给被调用函数形参,从而实现调用函数向被调用函数数据传送。函数向被调用函数数据传送。案例3 实参对形参数据传递。实参对形参数据传递。(注意执行
8、次序注意执行次序)第9页void main()void s(int n);/*说明函数说明函数*/int n=100;/*定义实参定义实参n,并初始化,并初始化*/s(n);/*调用函数调用函数*/*输出调用后实参值,便于进行比较输出调用后实参值,便于进行比较*/printf(n_first=%dn,n);void s(int n)int i;printf(n_begin=%dn,n);/*输出改变前形参值输出改变前形参值*/for(i=n-1;i=1;i-)n=n+i;/*改变形参值改变形参值*/printf(n_end=%dn,n);/*输出改变后形参值输出改变后形参值*/例程func2.
9、c第10页说明:说明:(1)实实参参能能够够是是常常量量、变变量量、表表示示式式、函函数数等等。不不论论实实参参是是何何种种类类型型量量,在在进进行行函函数数调调用用时时,它它们们都都必必须须含含有确定值,方便把这些值传送给形参。有确定值,方便把这些值传送给形参。所所以以,应应预预先先用用赋赋值值、输输入入等等方方法法,使使实实参参取取得得确确定定值。值。(2)形形参参变变量量只只有有在在被被调调用用时时,才才分分配配内内存存单单元元;调调用用结束时,即刻释放所分配内存单元。结束时,即刻释放所分配内存单元。所所以以,形形参参只只有有在在该该函函数数内内有有效效。调调用用结结束束,返返回回调调用
10、函数后,则不能再使用该形参变量。用函数后,则不能再使用该形参变量。(3)实实参参对对形形参参数数据据传传送送是是单单向向,即即只只能能把把实实参参值值传传送送给形参,而不能把形参值反向地传送给实参。给形参,而不能把形参值反向地传送给实参。(4)实实参参和和形形参参占占用用不不一一样样内内存存单单元元,即即使使同同名名也也互互不不影响。影响。第11页函数返回值与函数类型函数返回值与函数类型 语言函数兼有其它语言中函数和过程两种功效,语言函数兼有其它语言中函数和过程两种功效,从这个角度看,又可把函数分为有返回值函数和无返回从这个角度看,又可把函数分为有返回值函数和无返回值函数两种。值函数两种。1函
11、数返回值与函数返回值与return语句语句有参函数返回值,是经过函数中有参函数返回值,是经过函数中return语句来取得。语句来取得。(1)return语句普通格式:语句普通格式:return(返回值表示式返回值表示式);(2)return语句功效:返回调用函数,并将语句功效:返回调用函数,并将“返回值表返回值表示式示式”值带给调用函数。值带给调用函数。注意注意:调用函数中无调用函数中无return语句,并不是不返回一个值,语句,并不是不返回一个值,而是一个不确定值。为了明确表示不返回值,能够用而是一个不确定值。为了明确表示不返回值,能够用“void”定义成定义成“无(空)类型无(空)类型”。
12、第12页2函数类型函数类型在在定定义义函函数数时时,对对函函数数类类型型说说明明,应应与与return语语句句中、返回值表示式类型一致。中、返回值表示式类型一致。假假如如不不一一致致,则则以以函函数数类类型型为为准准。假假如如缺缺省省函函数数类型,则系统一律按类型,则系统一律按整型整型处理。处理。良良好好程程序序设设计计习习惯惯:为为了了使使程程序序含含有有良良好好可可读读性性并并降降低低犯犯错错,凡凡不不要要求求返返回回值值函函数数都都应应定定义义为为空空类类型型;即即使使函函数数类类型型为为整整型型,也也不不使使用用系系统统缺缺省省处理。处理。第13页对被调用函数说明和函数原型对被调用函数
13、说明和函数原型对被调用函数说明和函数原型对被调用函数说明和函数原型 在在ANSI C新新标标准准中中,采采取取函函数数原原型型方方式式,对对被被调调用用函函数数进进行行说明,其普通格式以下:说明,其普通格式以下:函数类型函数类型 函数名函数名(数据类型数据类型 参数名参数名,数据类型数据类型 参数名参数名2);语语言言同同时时又又要要求求,在在以以下下几几个个情情况况下下,能能够够省省去去对对被被调调用用函函数说明:数说明:l (1)当当被被调调用用函函数数函函数数定定义义出出现现在在调调用用函函数数之之前前时时。因因为为在在调调用用之之前前,编编译译系系统统已已经经知知道道了了被被调调用用函
14、函数数函函数数类类型型、参参数数个个数、类型和次序。数、类型和次序。l (2)假假如如在在全全部部函函数数定定义义之之前前,在在函函数数外外部部(比比如如文文件件开开始始处处)预预先先对对各各个个函函数数进进行行了了说说明明,则则在在调调用用函函数数中中可可缺缺省省对对被被调用函数说明。调用函数说明。l (3)假如被调函数返回值是整型或字符型时,假如被调函数返回值是整型或字符型时,能够不对被能够不对被调函数作说明,而直接调用。这时系统将自动对被调函数返回值调函数作说明,而直接调用。这时系统将自动对被调函数返回值按整型处理。按整型处理。l (4)对库函数调用不需要再作说明,对库函数调用不需要再作
15、说明,但必须把该函数头文但必须把该函数头文件用件用include命令包含在源文件前部。命令包含在源文件前部。例程func8.c第14页函数调用函数调用语言中,函数调用普通形式为:语言中,函数调用普通形式为:函数名函数名(实际参数表实际参数表)切切记记:实实参参个个数数、类类型型和和次次序序,应应该该与与被被调调用用函函数数所所要要求求参参数个数、类型和次序一致,才能正确地进行数据传递。数个数、类型和次序一致,才能正确地进行数据传递。在语言中,能够用以下几个方式调用函数:在语言中,能够用以下几个方式调用函数:(1)函函数数表表示示式式:函函数数作作为为表表示示式式一一项项,出出现现在在表表示示式
16、式中中,以以函函数数返返回回值值参参加加表表示示式式运运算算。这这种种方方式式要要求求函函数数是是有有返返回回值。值。(2)函函数数语语句句:C语语言言中中函函数数能能够够只只进进行行一一些些操操作作而而不不返返回函数值,这时函数调用可作为一条独立语句。回函数值,这时函数调用可作为一条独立语句。(3)函函数数实实参参:函函数数作作为为另另一一个个函函数数调调用用实实际际参参数数出出现现。这这种种情情况况是是把把该该函函数数返返回回值值作作为为实实参参进进行行传传送送,所所以以要要求求该该函数必须是有返回值。函数必须是有返回值。第15页说明说明:(1)调调用用函函数数时时,函函数数名名称称必必须
17、须与与含含有有该该功功效效自定义函数名称完全一致。自定义函数名称完全一致。(2)实实参参在在类类型型上上按按次次序序与与形形参参,必必须须一一一一对对应应和和匹匹配配。假假如如类类型型不不匹匹配配,C编编译译程程序序将将按按赋赋值值兼兼容容规规则则进进行行转转换换。假假如如实实参参和和形形参参类类型型不不赋赋值值兼兼容容,通通常常并并不不给给出出犯犯错错信信息息,且且程程序序依然继续执行,只是得不到正确结果。依然继续执行,只是得不到正确结果。(3)假如实参表中包含多个参数,对实参求值)假如实参表中包含多个参数,对实参求值次序随系统而异。有系统按自左向右次序求实次序随系统而异。有系统按自左向右次
18、序求实参值,有系统则相反。参值,有系统则相反。Turbo C和和MS C是是按自按自右向左右向左次序进行次序进行。第16页main()int i=0;printf(%d,%d,%d n,i,i+,+i);TC中,函数实参是从右向左求。中,函数实参是从右向左求。例程func1.c第17页函数嵌套调用和递归调用函数嵌套调用和递归调用函数嵌套调用是指,在执行被调用函数时,被调用函函数嵌套调用是指,在执行被调用函数时,被调用函数又调用了其它函数。这与其它语言子程序嵌套调用情形数又调用了其它函数。这与其它语言子程序嵌套调用情形是类似,其关系可表示如图是类似,其关系可表示如图4-2。第18页 例例例例 计
19、算计算计算计算s=1s=1k k+2+2k k+3+3k k+N+N k k /*/*功效:函数嵌套调用功效:函数嵌套调用功效:函数嵌套调用功效:函数嵌套调用*/*/#define K 4#define K 4#define N 5#define N 5long f1(int n,int k)long f1(int n,int k)/*/*计算计算计算计算nknk次方次方次方次方*/*/long power=n;long power=n;int i;int i;for(i=1;ik;i+)power*=n;for(i=1;ik;i+)power*=n;return power;return p
20、ower;第19页long f2(int n,int k)/*计算计算1到到nk次方之累加和次方之累加和*/long sum=0;int i;for(i=1;i1)f=power(n-1)*n;else f=1;return(f);第23页main()int n;long y;printf(input a inteager number:n);scanf(%d,&n);y=power(n);printf(%d!=%ldn,n,y);例程func4.c第24页递归执行过程递归执行过程main()y=power(3);printf(y);第一次调用第一次调用power(3)if(n1)f=powe
21、r(n-1)*n;elsef=1;return(f);/*n=3*/第二次调用第二次调用power(2)if(n1)f=power(n-1)*n;elsef=1;return(f);/*n=2*/第二次调用第二次调用power(1)if(n1)f=power(n-1)*n;elsef=1;return(f);/*n=1*/第25页变量作用域(局部变量与全局变量)变量作用域(局部变量与全局变量)语言中全部变量都有自己作用域。语言中全部变量都有自己作用域。变量说变量说明位置不一样,其作用域也不一样明位置不一样,其作用域也不一样,据此将,据此将语言中变量分为语言中变量分为局部变量局部变量和和全局变量
22、全局变量。在一个在一个函数内部定义变量,只在本函数范函数内部定义变量,只在本函数范围内有效围内有效,这么变量称为本函数,这么变量称为本函数局部变量局部变量。定定义在函数外部变量,该变量不属于任何一个函义在函数外部变量,该变量不属于任何一个函数,但可被本程序中其它函数所共用,它有效数,但可被本程序中其它函数所共用,它有效范围是从定义开始到根源程序结束范围是从定义开始到根源程序结束,该类变量,该类变量称为称为全局变量全局变量。第26页说出下面程序中变量类型及其作用域说出下面程序中变量类型及其作用域int p=1,q=5;int f1(int a)int i=2;a=a*i;printf(i=%d,
23、a=%d,p=%d,q=%d in f1n,i,a,p,q);float x=2.5,y=3;int f2(char a)char b=B;p=p+a;q=q+b;printf(“b=%c,a=%c,p=%d,q=%d in f2n”,b,a,p,q);printf(”x=%6.2f,y=%6.2f in f2n“,x,y);main()int k=6;f1(k);f2(A);printf(“p=%d,q=%d,x=%6.2f,y=%6.2f in mainn”,p,q,x,y);例程func6.c第27页关于局部变量作用域还要说明以下几点:关于局部变量作用域还要说明以下几点:l1主主函函数数
24、main()中中定定义义内内部部变变量量,也也只只能能在在主主函函数数中中使使用用,其其它它函函数数不不能能使使用用。同同时时,主主函函数数中中也也不不能能使使用用其其它它函函数数中中定定义义内内部部变变量量。因因为为主主函函数数也也是是一一个个函函数数,与与其其它它函函数数是平行关系。这一点是与其它语言不一样,应给予注意。是平行关系。这一点是与其它语言不一样,应给予注意。l2形形参参变变量量也也是是内内部部变变量量,属属于于被被调调用用函函数数;实实参参变变量量,则是调用函数内部变量。则是调用函数内部变量。l3允允许许在在不不一一样样函函数数中中使使用用相相同同变变量量名名,它它们们代代表表
25、不不一一样样对象,分配不一样单元,互不干扰,也不会发生混同对象,分配不一样单元,互不干扰,也不会发生混同。l4在复合语句中也可定义变量,其作用域只在复合语句范在复合语句中也可定义变量,其作用域只在复合语句范围内。围内。(例程func6.c)第28页变量存放类型变量存放类型 在语言中,对变量存放类型说明有以下四在语言中,对变量存放类型说明有以下四种:种:自动变量自动变量(auto)、存放器变量、存放器变量(register)、外部变量外部变量(extern)、静态变量、静态变量(static)。这四种。这四种类型变量在程序运行期间依据所分配地址改变是类型变量在程序运行期间依据所分配地址改变是否,
26、又可分为否,又可分为动态变量动态变量(自动变量和存放器变量自动变量和存放器变量)和和静态变量静态变量(外部变量和静态内部变量外部变量和静态内部变量)。动态存。动态存放变量是指在程序运行中依据需要动态分配存放放变量是指在程序运行中依据需要动态分配存放空间变量;静态存放变量指在程序运行中所分配空间变量;静态存放变量指在程序运行中所分配存放空间固定变量。存放空间固定变量。第29页变量存放类型说明变量存放类型说明局部变量存放方式局部变量存放方式(1 1)不做专门说明时默认为)不做专门说明时默认为auto auto 型:该类型变型:该类型变量位于动态存放区,离开函数其值就消失。量位于动态存放区,离开函数
27、其值就消失。(2 2)用用staticstatic说说明明局局部部静静态态变变量量:该该类类型型变变量量位位于于静静态态存存放放区区,默默认认初初始始值值为为0 0,该该类类变变量量,离开函数它们值仍保留,直到程序结束。离开函数它们值仍保留,直到程序结束。(3 3)用)用registerregister说明变量:位于说明变量:位于cpucpu存放器中,存放器中,能够提升执行效率,离开函数其值就消失。能够提升执行效率,离开函数其值就消失。第30页内部变量存放方式内部变量存放方式1静态存放静态存放静态内部变量静态内部变量(1)定义格式:)定义格式:static 数据类型数据类型 内部变量表;内部变
28、量表;(2)存放特点)存放特点1)静静态态内内部部变变量量属属于于静静态态存存放放。在在程程序序执执行行过过程程中中,即即使使所所在在函函数数调调用用结结束束也也不不释释放放。换换句句话话说说,在在程程序序执执行行期期间间,静静态态内内部部变变量量一一直直存存在在,但但其其它它函函数数是是不不能能引用它们。引用它们。2)定定义义但但不不初初始始化化,则则自自动动赋赋以以(整整型型和和实实型型)或或0(字字符符型型);且且每每次次调调用用它它们们所所在在函函数数时时,不不再再重新赋初值,只是保留上次调用结束时值!重新赋初值,只是保留上次调用结束时值!(3)何时使用静态内部变量)何时使用静态内部变
29、量1)需要保留函数上一次调用结束时值。)需要保留函数上一次调用结束时值。2)变量只被引用而不改变其值。)变量只被引用而不改变其值。第31页2动态存放动态存放自动局部变量(又称自动变量)(1)定义格式:)定义格式:auto 数据类型数据类型 变量表;变量表;(2)存放特点)存放特点1)自自动动变变量量属属于于动动态态存存放放方方式式。在在函函数数中中定定义义自自动动变变量量,只只在在该该函函数数内内有有效效;函函数数被被调调用用时时分分配配存存放放空空间间,调调用用结束就释放。结束就释放。在在复复合合语语句句中中定定义义自自动动变变量量,只只在在该该复复合合语语句句中中有有效效;退退出复合语句后
30、,也不能再使用,不然将引发错误。出复合语句后,也不能再使用,不然将引发错误。2)定义而不初始化,则其值是不确定。)定义而不初始化,则其值是不确定。3)因因为为自自动动变变量量作作用用域域和和生生存存期期,都都局局限限于于定定义义它它个个体体内内(函函数数或或复复合合语语句句),所所以以不不一一样样个个体体中中允允许许使使用用同同名名变变量量而而不不会会混混同同。即即使使在在函函数数内内定定义义自自动动变变量量,也也可可与该函数内部复合语句中定义自动变量同名。与该函数内部复合语句中定义自动变量同名。提议:提议:系统不会混同,并不意味着人也不会混同,所以尽系统不会混同,并不意味着人也不会混同,所以
31、尽可能少用同名自动变量!可能少用同名自动变量!第32页3存放器存放存放器存放存放器变量存放器变量普普通通情情况况下下,变变量量值值都都是是存存放放在在内内存存中中。为为提提升升执执行行效效率率,语语言言允允许许将将局局部部变变量量值值存存放放到到存存放放器器中中,这这种种变量就称为存放器变量。定义格式以下:变量就称为存放器变量。定义格式以下:register 数据类型数据类型 变量表;变量表;(1)只只有有局局部部变变量量才才能能定定义义成成存存放放器器变变量量,即即全全局局变变量量不行。不行。(2)对对存存放放器器变变量量实实际际处处理理,随随系系统统而而异异。比比如如,微微机机上上MSC和
32、和TC 将存放器变量实际看成自动变量处理。将存放器变量实际看成自动变量处理。(3)允允许许使使用用存存放放器器数数目目是是有有限限,不不能能定定义义任任意意多多个个存存放器变量。放器变量。第33页试写出程序执行结果试写出程序执行结果main()auto int a=2;register int b=2;static int c=2;printf(“*a=%d,b=%d,c=%d n”,a,b,c);f(a);f(b);f(c);printf(“*a=%d,b=%d,c=%d n”,a,b,c);int f(int x)auto int a=10;register int b=20;static
33、 int c;a=a+x;b=b-x;c=c+x*x;printf(“a=%d,b=%d,c=%d n”,a,b,c);*a=2,b=2,c=2a=12,b=18,c=4a=12,b=18,c=8a=12,b=18,c=12*a=2,b=2,c=2例程func7.c第34页全局(外部)变量全局(外部)变量 全局变量定义在函数之外,能被其它函数所共享。其作用域全局变量定义在函数之外,能被其它函数所共享。其作用域是从定义点到本文件结束。假如定义点之前函数需要引用这些外是从定义点到本文件结束。假如定义点之前函数需要引用这些外部变量时,需要在函数内对被引用外部变量进行说明。外部变量部变量时,需要在函数
34、内对被引用外部变量进行说明。外部变量说明普通形式为:说明普通形式为:extern 数据类型数据类型 外部变量外部变量,外部变量,外部变量2;当当一一个个程程序序由由多多个个源源文文件件组组成成时时,而而这这多多个个源源文文件件需需要要公公用用一一个个变变量量(全全局局)时时,则则可可在在一一个个源源文文件件中中定定义义,然然后后可可用用上上述述说明方法(说明方法(extern)在其它需要使用变量源文件中申明。如:)在其它需要使用变量源文件中申明。如:P1.c文件中文件中#include“p2.c”int a;main()P2.c文件中文件中extern int a;Power(int n)例程
35、func10.c func101.c第35页对于全局变量及存放方式还有以下几点说明:对于全局变量及存放方式还有以下几点说明:对于全局变量及存放方式还有以下几点说明:对于全局变量及存放方式还有以下几点说明:(1)外外部部变变量量可可加加强强函函数数模模块块之之间间数数据据联联络络,但但又又使使这这些些函函数数依依赖赖这些外部变量,因而使得这些函数独立性降低。这些外部变量,因而使得这些函数独立性降低。从从模模块块化化程程序序设设计计观观点点来来看看这这是是不不利利,所所以以不不是是非非用用不不可可时时,不不要要使用外部变量。使用外部变量。(2)在在同同一一源源文文件件中中,允允许许外外部部变变量量
36、和和内内部部变变量量同同名名。在在内内部部变变量量作用域内,外部变量将被屏蔽而不起作用作用域内,外部变量将被屏蔽而不起作用。(3)全全局局变变量量都都是是静静态态保保留留,用用static定定义义全全局局变变量量时时,此此变变量量将将只只能能被被在在本本文文件件中中函函数数使使用用,而而不不能能在在别别文文件件中中使使用用。即即有有利利于于限制变量作用域。限制变量作用域。注意注意:外部变量定义和外部变量说明是两回事外部变量定义和外部变量说明是两回事。外部变量定义,必。外部变量定义,必须在全部函数之外,且只能定义一次。而外部变量说明,出现在须在全部函数之外,且只能定义一次。而外部变量说明,出现在
37、要使用该外部变量函数内,而且能够出现屡次。在函数内要使用该外部变量函数内,而且能够出现屡次。在函数内extern变量说明,表示引用根源文件中外部变量!而函数外(通常在文变量说明,表示引用根源文件中外部变量!而函数外(通常在文件开头)件开头)extern变量说明,表示引用其它文件中外部变量。变量说明,表示引用其它文件中外部变量。第36页静静态态局局部部变变量量和和静静态态外外部部变变量量同同属属静静态态存存放放方方式式,但但二二者区分较大:者区分较大:(1)定定义义位位置置不不一一样样。静静态态局局部部变变量量在在函函数数内内定定义义,静静态外部变量在函数外定义。态外部变量在函数外定义。(2)作
38、作用用域域不不一一样样。静静态态局局部部变变量量属属于于内内部部变变量量,其其作作用用域域仅仅限限于于定定义义它它函函数数内内;即即使使生生存存期期为为整整个个源源程程序序,但其它函数是不能使用它。但其它函数是不能使用它。静静态态外外部部变变量量在在函函数数外外定定义义,其其作作用用域域为为定定义义它它源源文文件件内内;生生存存期期为为整整个个源源程程序序,但但其其它它源源文文件件中中函函数数也也是是不能使用它。不能使用它。(3)初始化处理不一样初始化处理不一样。静态局部变量,仅在第。静态局部变量,仅在第1次次调用它所在函数时被初始化,当再次调用定义它函数调用它所在函数时被初始化,当再次调用定
39、义它函数时,不再初始化,而是保留上时,不再初始化,而是保留上1次调用结束时值。而静次调用结束时值。而静态外部变量是在函数外定义,不存在静态内部变量态外部变量是在函数外定义,不存在静态内部变量“重复重复”初始化问题,其当前值由最近初始化问题,其当前值由最近1次给它赋值操作次给它赋值操作决定。决定。第37页务必切记务必切记:把局部变量改变为静态内部变量后,把局部变量改变为静态内部变量后,改变了它存放方式,即改变了它生存期。把外改变了它存放方式,即改变了它生存期。把外部变量改变为静态外部变量后,改变了它作用部变量改变为静态外部变量后,改变了它作用域,限制了它使用范围。所以,关键字域,限制了它使用范围
40、。所以,关键字“static”在不一样地方所起作用是不一样。在不一样地方所起作用是不一样。第38页C语言程序普通结构语言程序普通结构 C C程序可由多个源文件组成,每个源文件程序可由多个源文件组成,每个源文件由予编译命令、函数组成,每个函数由函数首由予编译命令、函数组成,每个函数由函数首部和函数体组成,每个函数体由说明部分和执部和函数体组成,每个函数体由说明部分和执行部分(语句)组成。以下:行部分(语句)组成。以下:P1.c文件文件#include“p2.c”#include“stdio.h”#defin price 30int a;main()int x,y;P2.c文件文件#include
41、“stdio.h”extern int a;Power(int n)int y;return y;第39页编译预处理编译预处理 C语言提供编译预处理功效,允许在程序语言提供编译预处理功效,允许在程序中使用几个特殊命令,以供编译预处理,然后中使用几个特殊命令,以供编译预处理,然后将预处理结果和源程序一起再进行通常编译处将预处理结果和源程序一起再进行通常编译处理。理。C提供三种提供三种编译预处理编译预处理处理功效处理功效:l1:宏定义:宏定义 l2:文件包含:文件包含 l3:条件编译:条件编译第40页宏定义宏定义l不带参数宏定义不带参数宏定义l带参数宏定义带参数宏定义l带参数宏定义和函数区分带参数
42、宏定义和函数区分l宏定义优点宏定义优点第41页 不带参数宏定义不带参数宏定义 格式格式:#define 标示符标示符 字符串字符串 功效功效:用宏名用宏名(标示符标示符)代替字符串代替字符串 例例:#define PI 3.14 说明说明:1:宏名普通用大写字母宏名普通用大写字母.如如:#define PI 3.14 2:宏定义不是宏定义不是C语句语句,行末不加分号行末不加分号,若加分号若加分号,则连分号则连分号一起置换一起置换.如如:#define PI 3.14;3:define命令出现在程序中函数外面命令出现在程序中函数外面,宏名有效范围是宏名有效范围是:定定义命令之后到根源文件结束义命
43、令之后到根源文件结束,通常写在文件开头通常写在文件开头.能够能够用用#undef命令终止宏定义作用域命令终止宏定义作用域.如如:#define PI 3.14 main().#undef PI .第42页4:能够引用已定义宏名能够引用已定义宏名,如如:#define PI 3.14#define R 3.0#define AREA PI*R*R main()printf(The area is%dn,AREA);5:双引号中双引号中area不置换不置换第43页带参数宏定义带参数宏定义格式格式:#define 宏名(参数表)宏名(参数表)字符串字符串功效功效:用宏名代替字符串,而且进行参数替换用
44、宏名代替字符串,而且进行参数替换#define PI 3.14#define S(r)PI*r*rmain()float a,area;scanf(%f,&a);area=S(a);/*等价:等价:area=PI*a*a */printf(r=%f,area=%fn,a,area);.第44页带参数宏定义说明带参数宏定义说明:对:对area=S(a+b)之类之类,带入结果带入结果:area=PI*a+b*a+b 改为改为:#define S(r)PI*(r)*(r)则则 area=PI*(a+b)*(a+b)2:宏定义时宏名和括号之间不能有空格:宏定义时宏名和括号之间不能有空格 如如:defi
45、ne s (r)PI*r*r,系统认为系统认为 用用s 代替代替 (r)Pi*r*r.第45页带参数宏定义和函数区分带参数宏定义和函数区分函数函数先求出实参表示式值然后先求出实参表示式值然后带入形参带入形参在程序运行时处理在程序运行时处理分配暂时工作单元分配暂时工作单元形参和实参都要定义类型,形参和实参都要定义类型,而且类型要求一致而且类型要求一致占运行时间占运行时间较复杂模块用函数很好较复杂模块用函数很好不使源程序变长不使源程序变长宏宏只是进行简单字符替换只是进行简单字符替换编译时进行,不分配内存编译时进行,不分配内存单元,不进行值传递处理,单元,不进行值传递处理,也没返回值概念也没返回值概
46、念宏名无类型,参数无类型,宏名无类型,参数无类型,只是一个符号代表只是一个符号代表占编译时间,不占运行时占编译时间,不占运行时间间用宏来代表简短表示式比用宏来代表简短表示式比较适当较适当展开后使源程序变长展开后使源程序变长第46页带参数宏定义和函数区分举例带参数宏定义和函数区分举例函数函数main()int a,b,c,d,t;a=2;b=3;c=1;d=5;t=max(a+b,c+d);printf(%d,t);max(x,y)int x,y;return(xy?x:y);宏宏#define MAX(x,y)(x)(y)?(x):(y)main()int a,b,c,d,t;a=2;b=3;
47、c=1;d=5;t=MAX(a+b,c+d);printf(%d,t);.例程func11.c func12.c第47页宏定义优点宏定义优点能够简化程序能够简化程序,方便修改等。方便修改等。#define PRINT(v)printf(v=%dt,v)main()int a,b,c,d;a=1;b=2;c=3;d=4;PRINT(a);PRINT(b);PRINT(c);PRINT(d);.第48页文件包含处理文件包含处理l文件包含概念文件包含概念l头文件概念头文件概念l头文件使用举例头文件使用举例l头文件使用说明头文件使用说明第49页文件包含概念文件包含概念含义:一个源文件能够将另一个源文件
48、全部内容含义:一个源文件能够将另一个源文件全部内容包含进来包含进来实现方法:实现方法:#include 文件名文件名比如:程序比如:程序file1.c#include file2.cAAfile2.c第50页头文件头文件使用场所使用场所:#include 头文件头文件h优点:能够降低程序员重复劳动。优点:能够降低程序员重复劳动。.第51页头文件使用举例头文件使用举例主程序:主程序:#include p.hmain()float r,area,l;r=3;area=S(r);l=2*PI*r;PRINT(r);PRINT(area);PRINT(l);.头文件:头文件:p.h#include#d
49、efine PI 3.14#define S(a)PI*(a)*(a)#define PRINT(v)printf(v=%ft,v)例程func13.c第52页头文件说明头文件说明1:一个:一个include命令只能指定一个被包含文件,若要包命令只能指定一个被包含文件,若要包 含含n个,则要用个,则要用n个个include2:文件包含格式有两种:文件包含格式有两种:include file3.h在标准路径下找在标准路径下找#include file2.h能够指定路径能够指定路径3:在一个包含文件中又能够包含另一个被包含文件,:在一个包含文件中又能够包含另一个被包含文件,即文件包含能够嵌套即文件
50、包含能够嵌套 4:若在:若在file1.c中中 include file3.h#include file2.h 则则file1.c和和file2.h都可用都可用file3.h中内容中内容第53页头文件说明举例头文件说明举例func14.c文件:文件:/*#include“func14_2.c“*/#include“func14_1.cmain()extern f1();f1();func14_1.h文件:文件:#include“func14_2.hf1()printf(In f1()n);f2();func14_2.h文件:文件:f2()printf(In f2()n);例程func14.c