第4章函数.ppt
大连大学DaLian University第四章第四章 函函 数数第四章 函 数大连大学DaLian University第四章第四章 函函 数数本章主要内容函数概述函数概述应用函数的编程(函数之间的数据传递)应用函数的编程(函数之间的数据传递)值传递值传递地址传递地址传递变量的作用域与变量的存储类型变量的作用域与变量的存储类型auto变量、变量、static 变量变量局部变量、全局变量局部变量、全局变量大连大学DaLian University第四章第四章 函函 数数C程序是由函数组成的(可以多个)程序是由函数组成的(可以多个)有且只有一个有且只有一个main()其它函数其它函数 库函数库函数自定义函数自定义函数函数是结构化程序设计的基本模块。函数是结构化程序设计的基本模块。具有某种功能的代码段具有某种功能的代码段通用性强,可以被重复使用。通用性强,可以被重复使用。易于维护,可以独立设计,单独调试。易于维护,可以独立设计,单独调试。划分函数时,考虑功能单一完整。划分函数时,考虑功能单一完整。4.1 函数概述函数概述大连大学DaLian University第四章第四章 函函 数数结构化程序设计思想结构化程序设计思想复杂问题复杂问题main()abca1a2b1b2c1c2结构化程序设计结构化程序设计:也称为,自顶向下、逐步细化。也称为,自顶向下、逐步细化。将复杂的系统划分为功能相对独立的子系统的组合,将复杂的系统划分为功能相对独立的子系统的组合,对各子系统再进行如此划分对各子系统再进行如此划分每个模块,每个模块,在在C语言中表现为函数。语言中表现为函数。大连大学DaLian University第四章第四章 函函 数数C中函数分类:中函数分类:用户角度分:系统函数和用户函数;用户角度分:系统函数和用户函数;参数角度分:有参函数和无参函数;参数角度分:有参函数和无参函数;返回值角度分:有返回值函数和无返回返回值角度分:有返回值函数和无返回值函数。值函数。标准库函数的调用标准库函数的调用 Turbo CTurbo C中提供了中提供了300300多条标准库函数,多条标准库函数,都放在函数库(都放在函数库(.lib.lib)中,函数的说明按功能)中,函数的说明按功能分类放在标题文件(分类放在标题文件(.h.h,也称头文件)中。,也称头文件)中。添加一行:添加一行:#include#include“头文件名称头文件名称”或者或者#include#include 大连大学DaLian University第四章第四章 函函 数数函数例子:函数例子:#include void PrintStar()printf(*n);void main()PrintStar();printf(Hello Everybody!n);PrintStar();使用函数组装程序好处:代码重用 程序模块化 维护方便大连大学DaLian University第四章第四章 函函 数数4.2 4.2 函数的定义与调用函数的定义与调用 4.2.1 4.2.1 函数的定义函数的定义#includevoidmain(void)inta,b,c;scanf(“%d,%d”,&a,&b);c=max(a,b);printf(“%d”c);intmax(intx,inty)intz;z=x=y?x:y;return(z);主主函函数数函函数数体体函数的类型,返回值的类型。函数的类型,返回值的类型。函数名函数名形式参数说明表。形式参数说明表。定义!定义!调用!调用!函数头函数头大连大学DaLian University第四章第四章 函函 数数函数的定义函数的定义格式:格式:返回值类型返回值类型 函数名函数名(形式参数列表形式参数列表)声明部分声明部分 功能语句功能语句 返回语句返回语句 /*函数头函数头*/*函数体函数体*/(1)函数头)函数头 返回值类型返回值类型 函数名函数名 形参列表:形参列表:0个或多个,逗号分隔,给出参数名称及类型。个或多个,逗号分隔,给出参数名称及类型。(2)函数体)函数体 代码段,实现功能。一对代码段,实现功能。一对 括起来。括起来。返回语句返回语句return:有返回值:有返回值:return(表达式表达式);或;或return 表达式;返回表达式;返回无返回值:可无无返回值:可无return语句,末尾的右语句,末尾的右“”作为函数的返回。作为函数的返回。大连大学DaLian University第四章第四章 函函 数数4.2.24.2.2函数的调用函数的调用1 1、函数调用形式:、函数调用形式:函数名函数名(实参列表实参列表);v单独语句形式:单独语句形式:max(a,b);printf(“fdsa”);v表达式形式:表达式形式:c=max(a,b);v作为函数参数:作为函数参数:printf(“%d”,max(a,b);1 1、函数调用形式:、函数调用形式:函数名函数名(实参列表实参列表);2 2、函数返回值:被调函数执行后返给主调函数的值。、函数返回值:被调函数执行后返给主调函数的值。vreturn(表达式);或(表达式);或return表达式;表达式;v可有多条可有多条return语句,遇到一条语句,遇到一条return时,程序即返回。时,程序即返回。v函数没有返回值,可以没有函数没有返回值,可以没有return语句,利用语句,利用“”返回。返回。3 3、函数的声明:、函数的声明:调用之前,对被调函数要进行声明。如:调用之前,对被调函数要进行声明。如:intmax(intx,inty);大连大学DaLian University第四章第四章 函函 数数#include long Multiply(int,int);void main()int num1,num2;long result;scanf(“%d%d”,&num1,&num2);printf(%ldn,Multiply(num1,num2);result=2*Multiply(2*num1,2*num2);printf(%ldn,result);long Multiply(int x,int y)long z;z=x*y;return z;【例4-2】大连大学DaLian University第四章第四章 函函 数数4.3 函数间的数据传递函数在调用时,主调函数和被调函数之间一般存在着数据的传递。传递有两种方式:值传递和地址传递将值或地址传递给被调函数;将被调函数的结果返回给调用函数。主调函数被调函数向被调函数传递数据(值或地址)。将结果返回给主调用函数。大连大学DaLian University第四章第四章 函函 数数传值调用方式:传值调用方式:形参是普通变量形参是普通变量-值参值参(1)形参是普通变量:必须传同类型的数值 形参及被调函数内的变量只有在被调用时才分配内存单元,此时将实参的值初始化给相应的形参。形参与实参完全脱离了关系,形参的值不影响实参。调用结束时,形参所占据的内存单元被释放。(2)实参必须有确定的值,以便把这些值传递给形参。(3)实参与形参在数量、位序和类型上必须一致。【例例4-5】观察程序运行结果。观察程序运行结果。#includevoidswap(int,int);voidmain(void)inta,b;a=10;b=20;printf(“调用前:调用前:na=%d,b=%dn”,a,b);swap(a,b);printf(“调用后:调用后:na=%d,b=%dn”,a,b);voidswap(intx,inty)intz;z=x;x=y;y=z;大连大学DaLian University第四章第四章 函函 数数指针变量作形参,必须传同类型的地址指针变量作形参,必须传同类型的地址(指针)数据。(指针)数据。此时在主调函数和被调函数之间可以实此时在主调函数和被调函数之间可以实现信息的现信息的“双向传递双向传递”。4.3.2 4.3.2 4.3.2 4.3.2 传地址调用方式传地址调用方式传地址调用方式传地址调用方式例例4-6/*函数参数为指针变量函数参数为指针变量*/voidswap(int*x,int*y);voidmain()inta,b;a=10;b=20;printf(“调用前:调用前:na=%d,b=%dn”,a,b);swap(&a,&b);printf(“调用后:调用后:na=%d,b=%dn”,a,b);voidswap(int*x,int*y)intz;z=*x;*x=*y;*y=z;大连大学DaLian University第四章第四章 函函 数数2.2.2.2.形参为数组类型,实参为数组名形参为数组类型,实参为数组名形参为数组类型,实参为数组名形参为数组类型,实参为数组名#include#include voidvoidfun(intfun(intb);b);main()main()intinta10,i;a10,i;for(ifor(i=0;i10;i+)=0;i10;i+)scanf(“%d”,&aiscanf(“%d”,&ai););fun(afun(a););for(ifor(i=0;i10;i+)=0;i10;i+)printf(“%d”,aiprintf(“%d”,ai););voidfun(voidfun(intintb)b)intint max,k,imax,k,i;max=b0;max=b0;k=0;k=0;for(ifor(i=1;i10;i+)=1;imax)max=max)max=bi;kbi;k=i;=i;max=b0;b0=max=b0;b0=bk;bkbk;bk=max;=max;例例例例:编写函数,将数组中的最大值与第一个数交换。要求在编写函数,将数组中的最大值与第一个数交换。要求在编写函数,将数组中的最大值与第一个数交换。要求在编写函数,将数组中的最大值与第一个数交换。要求在mainmainmainmain()()()()中进行数据的输入输出,中进行数据的输入输出,中进行数据的输入输出,中进行数据的输入输出,大连大学DaLian University第四章第四章 函函 数数【例例4-7】输入输入5个数到数组中,求这个数到数组中,求这5个数的平均个数的平均值。求平均值编写函数实现,并将该值作为返回值。值。求平均值编写函数实现,并将该值作为返回值。#include#defineN5floataver(intdata,int);voidmain(void)inti,arrayN,av;for(i=0;iN;i+)scanf(%d,&arrayi);av=aver(array,N);printf(av=%fn,av);floataver(intdata,intn)inti;floatavg=0;for(i=0;in;i+)avg+=datai;avg/=n;return(avg);大连大学DaLian University第四章第四章 函函 数数【例例4-8】输入输入10个数到数组中,再输入一个数到数组中,再输入一实数,判断该数在数组中是否存在?如果实数,判断该数在数组中是否存在?如果存在,输出该数在数组中下标;如果不存存在,输出该数在数组中下标;如果不存在,输出在,输出-1。查找编写函数实现。查找编写函数实现。#includeintsearch(floata,floatx);voidmain()inti,position;floata10,x;printf(输入输入10个实数:个实数:n);for(i=0;i10;i+)scanf(%f,&ai);printf(输入要找的实数:输入要找的实数:n);scanf(%f,&x);position=search(a,x);if(position=-1)printf(“没找到。没找到。n);elseprintf(“找到了。下标是找到了。下标是%d,position);intsearch(floata,floatx)intxpos=-1,i;for(i=0;i10;i+)if(ai=x)xpos=i;returnxpos;大连大学DaLian University第四章第四章 函函 数数4.4 函数的嵌套调用和递归调用函数的嵌套调用和递归调用 C中不允许作嵌套的函数定义,各函数中不允许作嵌套的函数定义,各函数之间都是平等和独立的。之间都是平等和独立的。C允许在一个函数的定义中出现对另一个允许在一个函数的定义中出现对另一个函数的调用。函数的调用。【例例4-9】函数嵌套调用的例子。函数嵌套调用的例子。#includefloatfun2(floatx);floatfun1(floatx);voidmain()floata;scanf(%f,&a);printf(%f,myfun1(a);floatfun1(floatx)return2*fun2(x);floatfun2(floatx)returnx0?x:-x;大连大学DaLian University第四章第四章 函函 数数【例例4-10】使用函数的嵌套调用编程,计算使用函数的嵌套调用编程,计算S。voidmain()intN,K;scanf(%d%d,&N,&K);printf(n%.0fn,fsum(N,K);分析分析(1)求累加和编一函数)求累加和编一函数fsum();(2)累加的每一项,再编一函数)累加的每一项,再编一函数fexp()(3)循环中,进行累加时,调用)循环中,进行累加时,调用fexp()求出该项求出该项double fsum(int n,int k)double sum=0;int i;for(i=0;in;i+)sum+=fexp(i,k);return sum;double fexp(int n,int k)double power=1;int i;for(i=0;ik;i+)power*=n;return power;大连大学DaLian University第四章第四章 函函 数数4.4.2 4.4.2 函数的递归调用函数的递归调用含义:一个函数在它的函数体内直接或间含义:一个函数在它的函数体内直接或间接地调用它自身称为递归调用。接地调用它自身称为递归调用。用递归法解决的问题,应该符合以下用递归法解决的问题,应该符合以下2个个条件:条件:边界问题(也称基本问题)有直接解。边界问题(也称基本问题)有直接解。原问题能够转化成一个规模较小的新问题,原问题能够转化成一个规模较小的新问题,新问题的求解方法与原问题相同。新问题的求解方法与原问题相同。大连大学DaLian University第四章第四章 函函 数数【例例4-11】计算计算n!。使用递归函数实现。使用递归函数实现。long fac(int n)if(n=1)return(1);else return n*fun(n-1);void main()int n;scanf(“%d”,&n);printf(“%d”,fac(n);大连大学DaLian University第四章第四章 函函 数数【例例5-】汉诺塔问题汉诺塔问题(Hanoi)(Hanoi)问题的提出:问题的提出:相传相传是是在古印度圣庙在古印度圣庙中的一种游戏。中的一种游戏。在一块铜板装置上,有三根杆在一块铜板装置上,有三根杆A A、B B、C C,在,在A A杆自下杆自下而上、由大到而上、由大到。小放置小放置6464个金盘。个金盘。游戏的目标游戏的目标:把把A A杆上的金盘全部移到杆上的金盘全部移到C C杆上,并仍保杆上,并仍保持原有顺序叠好。持原有顺序叠好。操作规则:操作规则:每次只能移动一个盘子每次只能移动一个盘子;移动过程中三根移动过程中三根杆上始终保持大盘在下,小盘在上,操作过程中盘子杆上始终保持大盘在下,小盘在上,操作过程中盘子可以置于可以置于A A、B B、C C任一杆上。任一杆上。大连大学DaLian University第四章第四章 函函 数数4.5变量的作用域与存储类型变量的作用域与存储类型C程序中变量的使用规则是:先定义后使用。定义形式中:类型:表明变量占用的内存空间的大小;位置(函数内与外):表明变量在程序中的作用域。一般,还要说明其存储类型,说明变量的存储方式。不同的存储方式影响变量在内存中存在的时间。大连大学DaLian University第四章第四章 函函 数数4.5.1局部变量与全局变量局部变量与全局变量 局部变量:在函数内部或复合语句内部局部变量:在函数内部或复合语句内部定义的变量(包括函数的定义的变量(包括函数的形参形参)。)。不同函数内的局部变量之间没有关系,同名不同函数内的局部变量之间没有关系,同名也互不影响。也互不影响。局部变量同名时,当前的局部变量有效。局部变量同名时,当前的局部变量有效。大连大学DaLian University第四章第四章 函函 数数【例例4-12】函数的局部变量应用举例。函数的局部变量应用举例。void func1(int a,int b)int x;printf(“func1 x:%x”,&x);void func2()int x;printf(“func2 x:%x”,&x);voidmain()intx,y;func1(3,4);func2();printf(“mainxDS:%x”,&x);大连大学DaLian University第四章第四章 函函 数数【例例4-13】复合语句中的局部变量举例。复合语句中的局部变量举例。void main()int i,j;i=2;j=3;int i;i=5;printf(Inter i=%d,j=%dn,i,j);printf(Outer i=%d,j=%dn,i,j);大连大学DaLian University第四章第四章 函函 数数2.全局变量全局变量在函数体外部定义的变量称为全局变量。在函数体外部定义的变量称为全局变量。局部变量属于所在的函数,而全局变量属于所局部变量属于所在的函数,而全局变量属于所有的函数,可以被当前文件的其他函数使用。有的函数,可以被当前文件的其他函数使用。全局变量和局部变量同名时,全局变量和局部变量同名时,当前的局部变量有效,全局变量被屏蔽。当前的局部变量有效,全局变量被屏蔽。一般来说,在较大的程序中要避免出现全局变一般来说,在较大的程序中要避免出现全局变量和局部变量同名的情况。量和局部变量同名的情况。大连大学DaLian University第四章第四章 函函 数数【例例4-14】全局变量应用举例。全局变量应用举例。int qNum=10;void main()printf(%dn,qNum);func1();printf(%dn,qNum);func2();printf(%dn,qNum);void func1()qNum=1;void func2()qNum=2;大连大学DaLian University第四章第四章 函函 数数全局变量的说明:全局变量的说明:extern 数据类型数据类型 全局变量名;全局变量名;#include void func1()extern int sum;/声明声明 sum=1;int sum=0;void main()func1();printf(%dn,sum);大连大学DaLian University第四章第四章 函函 数数全局变量的优缺点:全局变量的优缺点:使用全局变量的优点使用全局变量的优点 减少实参和形参数据传递带来的时间消耗。减少实参和形参数据传递带来的时间消耗。使用全局变量的缺点:使用全局变量的缺点:全局变量保存在静态存贮区,编译时为其分配全局变量保存在静态存贮区,编译时为其分配空间,整个程序结束才释放该空间。因此全局空间,整个程序结束才释放该空间。因此全局变量的生存期比较长,变量的生存期比较长,过多的全局变量占用较过多的全局变量占用较多的内存单元。多的内存单元。全局变量破坏了函数的封装性能。全局变量破坏了函数的封装性能。全局变量使函数的代码可读性降低。全局变量使函数的代码可读性降低。大连大学DaLian University第四章第四章 函函 数数4.5.2变量的存储类型变量的存储类型 动态存贮区和静态存贮区动态存贮区和静态存贮区 程序运行后,内存中可供程序使用的存贮空程序运行后,内存中可供程序使用的存贮空间分为三个部分。间分为三个部分。代码区存放:代码区存放:程序的二进制代码。程序的二进制代码。静态存贮区和动态存贮区:静态存贮区和动态存贮区:存放程序相关的存放程序相关的数据。数据。静态存贮区里:全局变量、静态变量。静态存贮区里:全局变量、静态变量。动态存贮区里:函数内定义的变量、形动态存贮区里:函数内定义的变量、形参。特点:参。特点:调用时,为变量动态分配内存空间;调用时,为变量动态分配内存空间;调用结束,释放该变量的内存空间。调用结束,释放该变量的内存空间。变量的存贮类别有三种:变量的存贮类别有三种:auto、static、register。大连大学DaLian University第四章第四章 函函 数数 auto auto存储类型(关键字可以省略)存储类型(关键字可以省略)在默认情况下,所有的局部变量(包括形参)都是在默认情况下,所有的局部变量(包括形参)都是autoauto变量变量#includevoidmain(void)autointa,b;scanf(“%d,%d”,&a,&b);if(ba)intt;t=a;a=b;b=t;printf(“Max=%d”,a);ab的的作作用用域域t的的作作用用域。域。生存期:生存期:变量都拥有自己的内存空间。变量都拥有自己的内存空间。从申请从申请-被释放被释放,这段时间称为变量的这段时间称为变量的生存期生存期。register存储类型存储类型其其作用域、生存期与作用域、生存期与auto相同,相同,差别在于,如果差别在于,如果CPU内部的寄存内部的寄存器空闲,器空闲,则使用寄存器作为变量则使用寄存器作为变量的存储单元,以提高速度。的存储单元,以提高速度。主要是循环变量,整形和字符型。主要是循环变量,整形和字符型。大连大学DaLian University第四章第四章 函函 数数static(静态静态)存储类型存储类型作用域:作用域:函数内定义的局部静态变量,在该函数之外不可见。函数内定义的局部静态变量,在该函数之外不可见。生存期生存期:从编译从编译-整个程序结束。整个程序结束。位于静态存贮区,在函数调用结束后,值仍然存在,位于静态存贮区,在函数调用结束后,值仍然存在,并影响到下一次调用的过程。并影响到下一次调用的过程。voidrow();voidmain()inti;for(i=1;i=9;i+)row();voidrow()static inta=1;inti;for(i=1;i=9;i+)printf(“%5d”,a*i);printf(“n”);a+;a的的作作用用域域生生存存期期从从编编译译开开始始到到程程序序结结束束。大连大学DaLian University第四章第四章 函函 数数【例例4-15】static局部变量应用举例。局部变量应用举例。#includeintf(intx)inta=10;staticintstc=1;stc=stc+x+a;returnstc;voidmain()printf(%dn,f(1);printf(%dn,f(1);大连大学DaLian University第四章第四章 函函 数数关于关于static局部变量提出几点注意:局部变量提出几点注意:存放在静态区,生存期比较长,从编译开始它就存在,存放在静态区,生存期比较长,从编译开始它就存在,整个程序结束后才被释放。整个程序结束后才被释放。从作用域来看,它是一种局部变量,属于当前的函数;从作用域来看,它是一种局部变量,属于当前的函数;即,当前函数内可见,其他函数即,当前函数内可见,其他函数 不可见。不可见。对初值的处理的不同。对初值的处理的不同。auto变量定义时如果没有初始化,那么它是一个随机值;变量定义时如果没有初始化,那么它是一个随机值;static局部变量如果没有初始化,编译器自动将其初始化为局部变量如果没有初始化,编译器自动将其初始化为 值值 0 或或 空字符。空字符。在程序中尽量不用或少用在程序中尽量不用或少用static局部变量。原因主要有:局部变量。原因主要有:static局部变量的生存期长,比较浪费内存;局部变量的生存期长,比较浪费内存;使用使用static局部变量会导致函数的多次调用之间发生联系,使代码的局部变量会导致函数的多次调用之间发生联系,使代码的可读性降低。可读性降低。大连大学DaLian University第四章第四章 函函 数数4.static 型全局变量型全局变量 C程序可以由多个源文件组成。程序可以由多个源文件组成。一个文件中定义的全局变量,其他的文件一个文件中定义的全局变量,其他的文件中可以使用(中可以使用(用用extern方式声明后)方式声明后)。如果限制本文件中的全局变量不能被其他如果限制本文件中的全局变量不能被其他文件使用,可以在文件使用,可以在全局变量的定义前加关全局变量的定义前加关键字键字static。static型全局变量作用域:本文件内。型全局变量作用域:本文件内。大连大学DaLian University第四章第四章 函函 数数 【举例举例】static全局变量应用。全局变量应用。/文件文件f1.c里的代码如下:里的代码如下:#include#includestaticintgs=0;voidfunc(intx);voidmain()func(3);printf(%d,gs);/文件文件f2.c里的代码里的代码如下:如下:externintgs;voidfunc(intx)gs+=x;大连大学DaLian University第四章第四章 函函 数数4.6 外部函数和内部函数外部函数和内部函数 当一个程序由多个源文件组成时,当一个程序由多个源文件组成时,可以指定一个文件中的函数能被可以指定一个文件中的函数能被其他文件调用;其他文件调用;也可以指定该函数只能被也可以指定该函数只能被本文件使用本文件使用;从这个意义上,函数可以分为外部函数和内部从这个意义上,函数可以分为外部函数和内部函数。函数。大连大学DaLian University第四章第四章 函函 数数4.6.1 外外 部部 函函 数数 一个函数如果可以被其他源文件调用,称为外部函数。一个函数如果可以被其他源文件调用,称为外部函数。定义外部函数时,在函数头最左面加关键字定义外部函数时,在函数头最左面加关键字externextern,表明该函数是一个外部函数表明该函数是一个外部函数 省略省略externextern关键字,则系统默认为外部函数关键字,则系统默认为外部函数 externintmax(inta,intb)returnab?a:b;文件文件f1.c里的代码如下:里的代码如下:externvoidprintstar();/*extern可以省略不写可以省略不写*/voidmain()printstar();文件文件f2.c里的代码如下:里的代码如下:voidprintstar()printf(*n);这里这里f1.c的的main函数调用了函数调用了f2.c的外部函数的外部函数printstar。大连大学DaLian University第四章第四章 函函 数数4.6.2 内部函数内部函数如果一个函数只能被如果一个函数只能被本文件中的函数调用本文件中的函数调用,该,该函数就称为内部函数,函数就称为内部函数,定义内部函数时,在函数最左面加关键字定义内部函数时,在函数最左面加关键字static staticintmax(inta,intb)returnab?a:b;大连大学DaLian University第四章第四章 函函 数数文件文件f1.c 里的代码:里的代码:void func();static void printstar()printf(printstar in f1.c.n);void main()printstar();func();文件文件f2.c里的代码:里的代码:staticvoidprintstar()printf(printstarinf2.c.n);voidfunc()printstar();大连大学DaLian University第四章第四章 函函 数数4.7.2 在在VC+下多文件程序的运行下多文件程序的运行在在VC+环境下,编译和运行由多个源文件环境下,编译和运行由多个源文件组成的程序操作如下:组成的程序操作如下:方法一,新建一个工程,向其中添加已方法一,新建一个工程,向其中添加已有的源文件。有的源文件。方法二,新建一个工程,在其中创建多方法二,新建一个工程,在其中创建多个源文件个源文件。大连大学DaLian University第四章第四章 函函 数数补充 编译预处理C语言还有一类语言还有一类编译预处理语句编译预处理语句。作用是作用是在编译时对程序作一定的处理在编译时对程序作一定的处理,满足特定的处理要求。,满足特定的处理要求。编译预处理语句的语法形式:编译预处理语句的语法形式:#关键词关键词参数表参数表宏定义预处理宏定义预处理1.1不带参数的宏定义不带参数的宏定义作用:作用:定义常量名,提高程序的可读性,便于修改。定义常量名,提高程序的可读性,便于修改。格式:格式:#define宏名宏名字符串字符串#definePI3.1415926voidmain(void)floatr;scanf(“%f”,&r)printf(“%fn”,PI*r*r);编译时用字符串替代宏名。编译时用字符串替代宏名。3.1415926大连大学DaLian University第四章第四章 函函 数数说明:宏名一般用大写;宏名一般用大写;编译时用字符串无条件替代宏名;编译时用字符串无条件替代宏名;#definePI3.1415926;PI*r*r3.1415926*r*r;宏名的有效范围,从定义到程序尾。也可以通过宏名的有效范围,从定义到程序尾。也可以通过#undef修改修改定义范围。定义范围。#defineG9.8voidmain(void)#undefGG的的范范围围可以在宏定义的字符串中使用已定义的宏名。可以在宏定义的字符串中使用已定义的宏名。”字符串中的宏名不替换。字符串中的宏名不替换。#defineR3.0#definePI3.14159#defineSPI*R*Rprintf(“S=%f”,S);不替换。不替换。大连大学DaLian University第四章第四章 函函 数数1.2 带参数的宏定义格式:格式:#define宏名宏名(参数表参数表)含参数的字符串含参数的字符串#defineS(a,b)a*barea=S(4,3);替换过程:替换过程:将实际参数替换宏定义的参数。将实际参数替换宏定义的参数。替换字符串中的参数。替换字符串中的参数。替换整个宏。替换整个宏。4*3带参的宏与函数的区别:带参的宏与函数的区别:带参宏不分配内存单元,不返回值,只是在编译时按规则替换。带参宏不分配内存单元,不返回值,只是在编译时按规则替换。关于带参宏的说明:关于带参宏的说明:要严格按格式书写,否则会造成错误。要严格按格式书写,否则会造成错误。#defineS(a,b)a*bS(3,4)被替换成:被替换成:(a,b)a*b(3,4)参数有可能用到表达式时,参数字符要加()。参数有可能用到表达式时,参数字符要加()。#defineS(r)PI*r*rS(a+b)替换为:替换为:PI*a+b*a+b#defineS(r)PI*(r)*(r)S(a+b)替换为:替换为:PI*(a+b)*(a+b)大连大学DaLian University第四章第四章 函函 数数 文件包含格式:格式:#include#include”被包含的文件名被包含的文件名”表示编译系统定义路径;表示编译系统定义路径;“”表示用户指明路径。表示用户指明路径。作用:作用:将指定的文件的内容和当前文件一起编译。将指定的文件的内容和当前文件一起编译。说明:说明:(1)一个)一个#include只能包含一个文件。只能包含一个文件。(2)一般将宏定义及函数的原型声明放在包含文件中。)一般将宏定义及函数的原型声明放在包含文件中。(3)被包含的文件一般扩展名为)被包含的文件一般扩展名为.h,称为头文件。,称为头文件。大连大学DaLian University第四章第四章 函函 数数 条件编译C可通过条件控制,让编译系统编译不同的程序段。可通过条件控制,让编译系统编译不同的程序段。条件编译有三种形式:条件编译有三种形式:#ifdef标识符标识符programseg1#elseprogramseg2#endif#ifndef标识符标识符programseg1#elseprogramseg2#endif12条件?条件?满足满足编译程序段编译程序段1不满足不满足编译程序段编译程序段2大连大学DaLian University第四章第四章 函函 数数举例:通过条件编译选择求最大值或最小值#includevoidmain(void)inta,b;scanf(“%d,%d”,&a,&b);#ifdefMAXprintf(“%d”,a=b?a:b);#elseprintf(“%d”,a=b?a:b);#endif#defineMAX#includevoidmain(void)inta,b;scanf(“%d,%d”,&a,&b);printf(“%d”,a=b?a:b);