《C语言89学习教程.pptx》由会员分享,可在线阅读,更多相关《C语言89学习教程.pptx(92页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、1第八章 函数intsquare(int);floatsqrt1(int);main()intk;for(k=1;k=10;k+)printf(”%d的平方%d:”,k,square(k);printf(”%d的平方根%f:”,k,sqrt1(k);intsquare(inty)returny*y;floatsqrt1(inty)returnsqrt(y);第1页/共92页2第八章 函数说明一个源程序文件由一个或多个函数组成,一个源程序文件是一个编译单位。一个C程序由一个或多个源程序文件组成C程序的执行从main函数开始,调用其他函数后返回到main函数所有函数都是平行的,不能嵌套,但可以互相
2、调用(不能调用main函数)函数分标准函数和用户自定义函数第2页/共92页3库函数简介系统自带的标标准库函数根据不同的功能作用放在不同的头文件中。使用时只需在程序的开头加上一条语句:#include根据使用的函数来确定根据使用的函数来确定第3页/共92页4如:如:stdio.hstdio.h用于标准输入用于标准输入/输出输出math.hmath.h用于数学计算用于数学计算ctype.hctype.h用于字符处理用于字符处理string.hstring.h用于字串处理用于字串处理time.htime.h用于时间用于时间/日期的处理日期的处理dir.hdir.h用于控制目录和路径用于控制目录和路径
3、graphics.hgraphics.h用于图形操作用于图形操作dos.hdos.hbios.hbios.h用于接口处理用于接口处理 第4页/共92页5函数调用的执行过程函数的声明与使用main()调fun()结束fun()返回保存:返回地址当前现场恢复:主调程序现场返回地址第5页/共92页6第八章 函数函数定义形式无参函数类型标识符函数名()声明部分语句例如p143,printstar()和print_message()函数有参函数类型标识符函数名(形式参数表列)声明部分语句第6页/共92页7第八章 函数有参函数举例intmul(intx,inty)intz;z=x*y;return(z);
4、形参说明的传统方式intmul(x,y)intx,y;intz;z=x*y;return(z);第7页/共92页8第八章 函数空函数类型标识符函数名(形式参数表列)例如:dummy()第8页/共92页9函数参数和函数值形式参数和实际参数(简称形参和实参)在定义函数中指定的形参,在未出现函数调用时,它们不占内存中的存储单元。只有在发生函数调用时,形参才被分配内存单元。在调用结束后,形参所占的内存单元被释放。实参可以是常量、变量或表达式,在调用时实参要有确定的值。例:a=5;b=7;mul(10,a+b);实参与形参的类型应相同或赋值兼容当实参变量为简单类型时,实参变量对形参变量的数据传递是“值传
5、递”,其特点是形参值的变化不会改变实参值的变化。第9页/共92页10第八章 函数main()inta,b;a=5;b=8;swap(a,b);printf(“a=%d,b=%dn”,a,b);swap(intx,inty)intt;t=x;x=y;y=t;考虑:a与b的值是多少?第10页/共92页11第八章 函数函数的返回值三种类型:单纯计算,专门对一系列参数作运算,并将结果返回。像sqtr(x)、sin(x)、pow(y,x)等。返回操作信息,并返回一个表明操作是否成功的简单值。无明确的返回值,此函数是一个单纯的过程,产生的结果不会令人感兴趣。像printf()函数返回所写入的字符个数。如果
6、想要从被调函数中得到明确的值,则函数中一定包含return语句。第11页/共92页12第八章 函数一个函数中可以有一个以上的return语句,只要遇到return语句就返回到主调函数中。如果一个函数明确表示没有返回值,可用void定义函数类型为无类型,例:voidprintstar()voidprint_message()注:如果函数已用void声明,则在主调函数中不能出现下面的用法:a=printstar();b=print_message();第12页/共92页13第八章 函数函数的调用函数语句printstar();只要求函数完成一个操作过程函数表达式m=100+mul(a,b);要求此
7、函数有返回值函数参数m=max(a,mul(b,c);或printf(”%d”,max(a,b);第13页/共92页14第八章 函数被调函数的声明使用库函数时,应在程序头部用#include命令将调用有关库函数所需的信息包含到文本中来使用用户自定义函数使用在前,定义在后,则在主调函数中要声明被调函数第14页/共92页15第八章 函数main()floatadd(float,float);floata,b,c;scanf(”%f,%f”,&a,&b);c=add(a,b);printf(”sumis%f”,c);floatadd(floatx,floaty)floatz;z=x+y;return
8、(z);第15页/共92页16floatadd(floatx,floaty)floatz;z=x+y;return(z);main()floata,b,c;scanf(”%f,%f”,&a,&b);c=add(a,b);printf(”sumis%f”,c);定义在前,使用在后,则在主调函数中不必声明被调函数第16页/共92页17在所有函数定义之前,在函数的外部做了声明,则在各主调函数中不必再声明要调用的函数floatadd(floatx,floaty);main()floata,b,c;scanf(”%f,%f”,&a,&b);c=add(a,b);printf(”sumis%f”,c);f
9、loatadd(floatx,floaty)floatz;z=x+y;return(z);第17页/共92页18第八章 函数函数的嵌套调用函数定义是相互平行的、独立的,不能嵌套定义,但函数之间可以相互调用,下面是错的f1(intx,inty)intz;if(xy).f2(floatu,floatv)intk,j;.第18页/共92页19第八章 函数下面使用是正确的f1(intx,inty)intw,u,v;if(xy).w=f2(u,v);f2(ints,intt).第19页/共92页20第八章 函数函数的递归调用定义:在调用一个函数的过程中又出现直接或间接地调用该函数本身。调用方式直接调用间
10、接调用第20页/共92页21第八章 函数间接调用F1(intx,inty)F2(inta,intb)intu,v;intr,s;.F2(u,v);F1(r,s);.出现的机会很少,编程时防止出现死循环调用第21页/共92页22第八章 函数直接调用F1(intx,inty)intu,v;.F1(u,v);.出现的机会多出现的机会多第22页/共92页23递归的特点递归的特点一个问题能够成为递归必须具备的条件是:后一部分与原始问题类似后一部分是原始问题的简化第23页/共92页24编程时一般将直接递归调用认为递归调用。函数递归调用编程时也有一定的次数,否则会变成死循环调用。一般情况下递归调用须能写出如
11、下函数形式:An=0or1(A,B为常数)f(n)=Bf(n-1)n0orn1注:Bf(n-1)表示与f(n)有某种特定关系,非数学函数中的定义式。第24页/共92页25它写成程序后包含两个过程:回推和递推回推:从函数自变量n=N不定值推到函数自变量n=1时的确定值递推:从函数自变量n=1时的确定值依次推到函数自变量n=N时的函数值例:P160例8.8第25页/共92页265 5!的执行过程!的执行过程:设设:输入输入 5 5 (n n=5)=5)第第1 1次调用:次调用:y=fac(5)y=fac(5)返回:返回:y=5fac(4)y=5fac(4)第第2 2次调用:次调用:y=5*4fac
12、(3)y=5*4fac(3)第第3 3次调用:次调用:y=5*4*3fac(2)y=5*4*3fac(2)第第4 4次调用:次调用:y=5*4*3*2fac(1)y=5*4*3*2fac(1)第第5 5次调用:次调用:y=5*4*3*2*1*fac(0)y=5*4*3*2*1*fac(0)第26页/共92页27例:用递归法将一个整数n拆成一位一位的输出。如输入483,拆成3位4、8、3,按位输出4、8、3,位数任意。nn=10第27页/共92页28#include“stdio.hvoid convert(long n)long i;if(n10)printf(“%ld“,n);return;e
13、lse printf(“%ld“,n%10);i=n/10;convert(i);返返回回convert(438)convert(438)打印打印8 8convert(43)convert(43)打印打印3 3convert(4)convert(4)打印打印4 4返返回回在在convert(i)convert(i)后加一条语句:后加一条语句:printf(printf(“n#n#”);观察打印几观察打印几次次“#”第28页/共92页29 main()long x;scanf(“%ld”,&x);convert(x);输入:1234 输出:4321 考虑:如何打印出 1234 的顺序?第29页/
14、共92页30void convert(long n)long i;if(n0)fun(k-1);printf(“%d”,k);0 1 2 3 4 5第32页/共92页33设计函数int ArrayMin(int d,int n);其中d为数组,n为数组元素个数,ArrayMin返回d中最小元素。dn-1 当n=1 f(d,n)=dn-11 第33页/共92页34#include stdio.h int ArrayMin(int d,int n)if(n=1)return dn-1;else if(dn-1 02.求杨辉三角形中第n行(n0)的第k个系数(0kn)。1k=0ork=nC(n,k)
15、=C(n-1,k-1)+C(n-1,k)0kn3.编写程序实现十进制转换为S进制(2S9)。第35页/共92页36第八章 函数数组作为函数参数数组元素作函数参数与用简单变量作实参一样,是单项传递,即“值传递”举例第36页/共92页37第八章 函数main()int mul(int,int);int a=2,2,2,2,b=4,4,4,4,c4,k;for(k=0;k 4;k+)ck=mul(ak,bk);for(k=0;k 4;k+)printf(“%d,%d,%d n”,ak,bk,ck);int mul(int x,int y)x=x+2;y=y+2;return(x*y);第37页/共9
16、2页38第八章 函数数组名作函数参数在主调函数和被调函数中都要定义数组实参数组和形参数组类型须一致实参数组和形参数组大小可一致或不一致形参数组可不指定大小传递方式是地址传递,即把实参数组的起始地址串地传递给形参数组,实参数组与形参数组共同占用同一段内存单元(p166图8.14)形参数组中各元素值的变化将引起实参数组中各元素值同时变化举例第38页/共92页39 main()int mul(int,int,int,int);int a=2,2,2,2,b=4,4,4,4,c4,k;mul(a,b,c,4);for(k=0;k4;k+)printf(“%d,%d,%d n”,ak,bk,ck);in
17、t mul(int x,int y,int z,int n)int j;for(j=0;j n;j+)x j=x j+2;y j=y j+2;c j=x j*y j;第39页/共92页40第八章 函数值传递时最多只能返回一个值,而地址传递隐含地可返回多个值多维数组名作函数参数与前面数组名作参数一样,但在被调函数中对数组的定义可指定每一维的大小,也可省略第一维的大小说明。例如:intarray320;或intarray20;但不能写成:intarray;或intarray3;第40页/共92页41例:有以下数组定义和f函数调用语句,则在f函数的说明中,对形参数组array的错误定义方式为_int
18、a34;f(a);A)f(intarray6)B)f(intarray3)C)f(intarray4)D)f(intarray25)B例:假设有子串“ould”,任意输入一个句子,并在句子中寻找给出的匹配子串,若找到,打印整个句子,找不到,继续输入句子直到输入一个空句子。第41页/共92页42举例:模拟投骰子n次,观察1到6的每个数值出现的次数#includestdio.h#includestdlib.hvoidp_rand(intn,intA)inti,x;for(i=1;i=n;i+)x=1+rand()%6;Ax+;第42页/共92页43main()voidp_rand(int,intA
19、);inti,k;intnum7=0;printf(请输入投骰子的次数:);scanf(%d,&k);p_rand(k,num);for(i=1;i=6;i+)printf(n%d:%d,i,numi);第43页/共92页44注意:重复调用rand函数可产生一系列伪随机数,但每次执行程序时,这组数值是重复的。为了调整为在每次执行程序时产生不同的随机数系列,用一个函数srand()取不同的种子,即可在每次执行程序时产生不同的随机数系列。上面的主程序可改成:第44页/共92页45#include“stdlib.h”main()voidp_rand(int,intA);inti,k,seed;int
20、num7=0;printf(“请输入投骰子的次数:”);scanf(%d,&k);printf(“请输入一个随机正整数:”);scanf(%d,&seed);srand(seed);p_rand(k,num);for(i=1;i=6;i+)printf(n%d:%d,i,numi);第45页/共92页46第八章 函数例1:P166的例8.13、P168的例8.14例2:编制折半检索函数,其功能是判断在递增排序的数组v中,是否出现值为x的元素。如果在v中有元素值为x,则函数返回该元素的位置(数组元素下标的序号);否则返回-1。第46页/共92页47第八章 函数1.置数组v的下界low为0,上界h
21、igh为n-1(n为数组元素个数)2.当lowhigh,函数返回-1值,表示在数组中找不到其值为x的元素3.置mid为low与high的中间值4.若vmid的值等于x,返回函数值mid5.若vmid的值x,置high=mid-1第47页/共92页48 注:一般来说,线性查找方法适用于小数组或未排序数组。但对于大数组,线性查找是低效的。如果是排序数组,则高速折半查找效率最高第48页/共92页49下面add函数的功能是求两个参数的和,并将和值返回调用函数。函数中错误的部分是_;改正后为_voidadd(floata,floatb)floatc;c=a+b;returnc;错误:错误:void vo
22、id 改正:改正:float add(float a,float b)float add(float a,float b)第49页/共92页50下面是一个计算阶乘的程序。程序中的错误语句是_,应改为_doublefactorial(int);main()intn;printf(“Enteraninteger:”);scanf(“%d”,&n);printf(“nn%d!=%lgn”,n,factorial(n);doublefactorial(intn)doubleresult=1.01;while(n1|n1|n1|n1&n1&n170)result*=(double)n-;第50页/共92
23、页51下面程序的运行结果是_main()inti=2,x=5,j=7;fun(j,6);printf(“i=%d;j=%d;x=%dn”,i,j,x);fun(inti,intj)intx=7;printf(“i=%d;j=%d;x=%dn”,i,j,x”);i=7;j=6;x=7 i=7;j=6;x=7 i=2;j=7;x=5i=2;j=7;x=5第51页/共92页52第八章 函数局部变量和全局变量局部变量一个函数内部定义的变量是局部变量,它只在本函数范围内有效不同函数中可使用同名的变量,但它们代表不同的对象,各占有不同的内存单元,互不干扰形参是局部变量在函数内部,可以在复合语句中定义变量,
24、这些变量只在复合语句中有效举例第52页/共92页53例:以下正确的说法是_如果在一个函数中的复合语句中定义了一个变量,则该变量A)只在该复合语句中有效B)在该函数中有效C)在本程序范围内均有效D)为非法变量A第53页/共92页54第八章 函数main()void f1(int,int);int a,b;a=5;b=10;f1(a,b);printf(”a=%d,b=%d n”,a,b);void f1(int x,int y)int a,b;a=x+10;b=y+10;printf(”a=%d,b=%d n”,a,b);a=15,b=20a=15,b=20a=5,b=10a=5,b=10第54
25、页/共92页55第八章 函数全局变量在所有函数之外定义的变量是全局变量,即外部变量,它有效范围为从定义变量的位置开始到源文件结束举例第55页/共92页56例:以下程序的正确运行的结果是_void num()extern int x,y;int a=15,b=10;x=a-b;y=a+b;int x,y;main()int a=7,b=5;x=a+b;y=a-b;num();printf(“%d,%dn”,x,y);A)12,2B)不确定C)5,25D)1,12C第56页/共92页57第八章 函数intx1=30,x2=40;main()voidsub(int,int);intx3=10,x4=
26、20;sub(x3,x4);sub(x2,x1);printf(”%d,%d,%d,%d n”,x3,x4,x1,x2);voidsub(intx,inty)x1=x;x=y;y=x1;1010,2020,4040,4040例例1 1:第57页/共92页58第八章 函数inta=5,b=7;main()intplus(int,int);inta=4,b=5,c;c=plus(a,b);printf(”A+B=%d,a=%d,b=%dn”,c,a,b);intplus(intx,inty)intz;z=x+y;a+;b+;printf(”a=%d,b=%dn”,a,b);return(z);9,
27、4,56,8例例2 2:第58页/共92页59第八章 函数intk=1;main()voidfun(int);intj=4;fun(j);printf(”(1)%d,%dn”,j,k);voidfun(intm)m+=k;k+=m;chark=B;printf(”(2)%dn”,k-A);printf(”(3)%d,%dn”,m,k);(1)4,6(2)1(3)5,6例例3 3:第59页/共92页60第八章 函数在同一个源文件中,全局变量与局部变量同名时,则在局部变量的作用范围内,全局变量不起作用一个函数中改变了全局变量的值,会影响到其它函数利用全局变量的性质,可以从函数中得到一个以上的返回值
28、全局变量在程序的整个执行过程中都占用存储单元使用全局变量会使函数的通用性降低全局变量使用过多,会降低程序的清晰度第60页/共92页61第八章 函数变量的存储类别动态存储方式与静态存储方式静态存储方式在程序运行期间分配固定的存储空间的方式动态存储方式在程序运行期间根据需要进行动态的分配存储空间的方式内存中供用户使用的存储空间分三部分:程序区静态存储区动态存储区第61页/共92页62第八章 函数w静态存储区存放全局变量和静态变量,直到整个程序结束才被释放w动态存储区存放形参、自动变量、现场保护和返回信息存储类别种类自动的(auto)静态的(static)寄存器的(register)外部的(exte
29、rn)第62页/共92页63第八章 函数auto变量函数中的局部变量,前面没有声明为static,它们都是动态地分配存储空间。例如:main()intx,y;charc1,c26;floatu,v;.intf(inta)intc,d=5;.第63页/共92页64第八章 函数register变量与auto相似,但变量的值保存在CPU的寄存器中,速度快。注意局部静态变量不能定义为registerintfac(intn)registerinti,f=1;for(i=1;i=n;i+)f=f*i;return(f);如n的值大,则能节省许多执行时间。第64页/共92页65第八章 函数static局部变
30、量在函数体内用static说明的变量称为静态局部变量,它的值在函数调用结束后不消失而保留原值,例1:main()intfunc(int,int);intk=4,m=1,p;p=func(k,m);printf(“%d,”,p);p=func(k,m);printf(“%dn”,p);第65页/共92页66第八章 函数intfunc(inta,intb)staticintm=0,i=2;i=i+m+1;m=i+a+b;return(m);结果:结果:8,178,17第66页/共92页67第八章 函数例2:i=1 j=1i=1 j=1next(i)=1next(i)=1last(i)=10last
31、(i)=10new(i+j)=12new(i+j)=12i=1 j=2i=1 j=2next(i)=2next(i)=2last(i)=9last(i)=9new(i+j)=13new(i+j)=13i=1 j=3i=1 j=3next(i)=3next(i)=3last(i)=8last(i)=8new(i+j)=14new(i+j)=14第67页/共92页68例3:main()inta=2,i;for(i=0;i=0;k-)for(k=strlen(num)-1;k=0;k-)printf(%c,numk);printf(%c,numk);第79页/共92页80convert(long s
32、,char num,int base)convert(long s,char num,int base)int i=0,j;int i=0,j;do do j=s%base;j=s%base;numi+=(j=9)?j+0:j+a-10;numi+=(j=9)?j+0:j+a-10;s=s/base;s=s/base;while(s!=0);while(s!=0);numi=0;numi=0;第80页/共92页81例8.14书上作业(p186)分析:要编制的函数input_stu(intsNM):输入N个学生的成绩aver_stu(int sNM),float a_sN):计算每个学生的平均成
33、绩aver_cor(intsNM),floata_cM):计算每门课的平均成绩highest(intsNM):找出最高分数所对应的学生和课程s_diff(floata_sN):计算方差并显示计算结果main()函数中有局部变量:intscoreNM:存放N个学生M门课的成绩floatavr_sN:存放N个学生的平均成绩floatavr_cM:存放M门课程的平均成绩第81页/共92页82第八章 函数例8.15书上作业(p186)分析:要编制的函数input_worker(intnumN,charnameN8)输入N个职工的工号和姓名sort(intnumN,charnameN8)按职工号升序排序
34、search(intnumber,intnumN,charnameN8)根据输入的职工号查找职工的姓名,用折半法第82页/共92页83第九章 预处理命令C语言提供三种预处理功能宏定义文件包含条件编译宏定义不带参数的宏定义#define标识符字符串例:#definePI3.14159#defineN10宏定义是用宏名代替一个字符串,只是作简单的置换,不作正确性检查。第83页/共92页84第九章 预处理命令宏定义不必在行末加分号宏名的有效范围为定义命令之后到本源文件结束,可以用#undef命令终止宏定义的作用域例:#defineA10main().#undefAf1()第84页/共92页85第九章
35、 预处理命令程序中用“”括起来的字符串内的字符,即使与宏名相同,也不进行置换宏定义与定义变量不同,它只作字符替换,不分配内存空间带参数的宏定义#define宏名(参数)字符串例:#defineS(a,b)a*barea=S(4,5);注意宏展开时的括弧问题(二义性问题)宏定义时,宏名与带参数的括弧之间不能有空格#defineS(r)PI*r*r第85页/共92页86第九章 预处理命令函数调用时,先求出实参表达式的值,然后代入形参。而带参的宏只进行字符替换函数调用是运行时处理的,分配临时内存单元。而宏展开则是在编译时进行的,在展开时不分配内存单元,不进行值的传递处理,也没有“返回值”的概念函数中
36、的实参和形参都要定义类型,二者类型要一致。而宏不存在类型问题宏替换只占编译时间,而函数调用则占运行时间第86页/共92页87已知#defineN3;的宏定义,执行语句i=N*3后,i的值是A.3B.6C.9D.A、B、C答案都不对答案:答案:D D,注意是宏定义后的分注意是宏定义后的分号引起的错号引起的错第87页/共92页88第九章 预处理命令例:写出结果#include#defineBOT(-2)#defineTOP(BOT+5)#definePRI(arg)printf(“%dn”,arg)#defineFOR(arg)for(;(arg);(arg)-)main()inti=BOT,j=
37、TOP;FOR(j)switch(j)case1:PRI(i+);case2:PRI(j);break;default:PRI(i);-2 2-2 1第88页/共92页89第九章 预处理命令“文件包含”处理形式(P194图9.2)#include“文件名”#include举例:P195例9.6第89页/共92页90第九章 预处理命令条件编译形式1:#ifdef标识符程序段1#else程序段2#endif形式2:#ifdef标识符程序段1#endif第90页/共92页91第九章 预处理命令举例:#defineDEBUGmain()inta=20,b=10,c;c=a/b;#ifdefDEBUGprintf(“a=%o,b=%o”,a,b);#endifprintf(“c=%d”,c);c=2c=2见P198 例9.7第91页/共92页92感谢您的欣赏!第92页/共92页