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