您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > C程序设计教程与实训(第二版)第6章
第6章信息学院计算机基础组函数函数的定义及调用函数间的参数传递数组作为函数的参数函数的递归调用程序的多文件组织作用域和存储类型本章主要内容:6.1引例例6-1编写自定义函数求两个整数的和程序代码如下:#includestdio.hintsumxy(intx,inty)/*自定义函数*/{ints;s=x+y;returns;}main()/*主函数*/{inta=1,b=10,sum;sum=sumxy(a,b);printf(%d,sum);}6.2.1函数的定义6.2函数的定义和调用返回类型名函数名(形参表){语句…}3)函数需要返回值时,用return语句。不需要时则不必使用。return(表达式)或return表达式4)函数中可能有多条return语句,但只能有一条被执行.5)函数不允许嵌套定义,函数之间是平行的。2)函数的返回类型可以省略,默认为int函数的返回类型也可以是void型,表示无返回值1)形参表语法:(类型参数名,类型参数名……)形参表也可为空——无参函数6.2函数的定义和调用6.2.2函数的调用函数名(实参表)说明:1)函数的调用在语法上相当于一个表达式,可构成表达式语句或作为另一个表达式的操作数或作为流程控制语句的组成部分。2)函数调用时的实参个数、类型应与函数定义中的形参个数、类型相吻合;形参是函数定义时的参数,是变量;仅在调用函数时,才为形参分配内存;调用结束后,形参所占内存马上释放实参是函数调用时的参数,可以是常量、变量或表达式——是一个“值”。3)调用的函数必须是已经定义了的函数。4)函数的调用是可以嵌套的;两个名词:主调函数(主函数,子函数)被调函数(子函数)说明:6.2.2函数的调用例6-3:用函数实现求某个整数的阶乘程序代码如下:#includestdio.hintJC(intx){inti,s=1;for(i=1;i=x;i++)s*=i;returns;}main(){intn,res;scanf(%d,&n);res=JC(n);printf(%d,res);}6.2.3函数的声明例6-3也可写成如下的形式:#includestdio.hmain(){intn,res;intJC(intx);/*对JC函数进行函数声明*/scanf(%d,&n);res=JC(n);printf(%d,res);}intJC(intx){inti,s=1;for(i=1;i=x;i++)s*=i;returns;}6.2.3函数的声明基本形式:返回类型函数名(形参表);intJC(intx);也可以写成intJC(int);说明:1)存在性说明也称为函数原型(prototype),系统利用函数原型对函数的合法性进行检查。Error:Function…shouldhaveaprototype!3)常见库函数的原型:见附录C看到函数原型就应该知道函数的调用方法2)库函数的原型在.h文件中6.3函数的递归调用函数的嵌套调用在函数嵌套调用的过程中,有时候会用到函数直接或者间接调用自己的情况,称为递归调用例6-5用递归方法求解n!程序代码如下:intfact(intn){if(n=1)return1;elsereturnn*fact(n-1);}voidmain(){intn,res;scanf(“%d”,&n);res=fact(n);printf(“%d!=%d”,res);}n!递归调用的计算过程递归三要素:–递归形式:fact(n)–递归规则:n*(n-1)!–递归终结条件:n=1递归调用的实质就是将原来的问题分解为新的问题,而解决新问题时又用到了原有问题的解法。按照这一原则分解下去,每次出现的新问题都是原有问题的简化的子问题,而最终分解出来的问题,是一个已知解的问题。这就是有限的递归调用。只有有限的递归调用才是有意义的,无限的递回调用永远得不到解,没有实际意义。递归调用的实质例6-6汉诺塔问题12.16C语言程序设计递归解决步骤:先将A上n-1片搬运到中间B塔上;将A最后一片搬运到目标C塔上;将B上n-1片借助A搬运到目标C塔上;递归终结条件:当n=1时,直接搬运;例如:A上有3个1.A2个B2.A1个C3.B2个C1.1AC1分解1.2AB1.3CB3.1BA3分解3.2BC3.3AC程序代码:#includestdio.hvoidmove(intn,intx,inty,intz){if(n==1)printf(%c--%c\n,x,z);else{move(n-1,x,z,y);printf(%c--%c\n,x,z);move(n-1,y,x,z);}}main(){inth;printf(\ninputnumber:\n);scanf(%d,&h);printf(thesteptomoving%2ddiskes:\n,h);move(h,'a','b','c');}6.4数组作为函数的参数6.4.1一维数组作函数的参数#includestdio.hvoidmain(){inta[10]={4,7,9,1,54,67,88,2,21,3};floatave;floataverage(inta[10]);/*函数声明*/ave=average(a);/*将数组传递给自定义函数average*/printf(%7.2f,ave);}例6-7编写函数求一组已知数据的平均值。接下页floataverage(intm[10])/*数组作函数的参数*/{inti,sum=0;for(i=0;i10;i++)sum+=m[i];returnsum/10.0;}例6-7编写函数求一组已知数据的平均值。6.4.2函数间的参数传递1、值传递:函数形参的数据类型为简单数据类型2、地址传递:函数形参的数据类型为地址类型,如数组类型,如例6-76.4.3二维数组作函数的参数#includestdio.hvoidmain(){inta[3][3]={1,2,3,4,5,6,7,8,9};intmain_max(ints[3][3]);intres;res=main_max(a);printf(主对角线元素最大值为%d\n,res);}例6-10编写函数求已知二维矩阵主对角线上元素的最大值intmain_max(ints[3][3])/*二维数组作函数的参数*/{inti;intm=s[0][0];for(i=1;i3;i++)if(s[i][i]m)m=s[i][i];returnm;}6.4.3二维数组作函数的参数#includestdio.hvoidmain(){inta[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};intm[3];/*用于存放结果*/inti;voidrow_max(ints[3][4],intres[3]);row_max(a,m);for(i=0;i3;i++)printf(第%d行最大值为%d\n,i+1,m[i]);}例6-11编写函数求一个已知二维矩阵中各行元素的最大值.接下页例6-11编写函数求一个已知二维矩阵中各行元素的最大值voidrow_max(ints[3][4],intres[3])/*s用于访问主调函数中二维数组的值,res用于存放结果*/{inti,j;for(i=0;i3;i++){res[i]=s[i][0];for(j=1;j4;j++)if(s[i][j]res[i])res[i]=s[i][j];/*将结果通过res写入主调函数的m中*/}}6.4.4字符数组作函数的参数#includestdio.hvoidmain(){chars[100];intn;intNum(chars[100]);gets(s);n=Num(s);printf(%d,n);}例6-12编写函数求一个字符串中小写字母的个数。intNum(chars[100]){inti=0;intc=0;while(s[i]!='\0'){if(s[i]='a'&&s[i]='z')c++;i++;}returnc;}6.5程序的多文件组织例6-13采用多文件方式将冒泡排序写到自定义的公用函数库中。mtlti.cpp:主函数所在的程序文件,代码如下:#includestdio.h#includedeclare.h/用“”和用的区别在于前者使得编译器会在用户路径中查找相应的文件*/voidmain(){inta[7]={3,2,5,7,4,9,8},i;popo(a,7);for(i=0;i7;i++)printf(%2d,a[i]);}接下页6.5程序的多文件组织funL.cpp:自定义函数库所在的源文件,当前只有一个冒泡排序函数popo,代码如下:voidpopo(inta[],intn){inti,j,t;for(j=1;jn;j++)for(i=0;in-j;i++)if(a[i]a[i+1]){t=a[i];a[i]=a[i+1];a[i+1]=t;}}declare.h:用于声明函数的头文件。voidpopo(inta[],int);6.6作用域和存储类型6.61变量的作用域1、局部作用域:变量在函数内部定义,则变量具有从定义位置开始到函数结束位置为止的局部作用域。例如:voidmain(){intfun(inta);inti,j;/*局部变量i,j的作用域起点*/...}intfun(inta)/*形参a的作用域起点*/{intb,c;/*局部变量b,c的作用域起点*/if(bc){intx,y;/*局部变量x,y的作用域起点*/x=2;...}/*局部变量x,y的作用域终点*/}2、全局作用域:6.61变量的作用域变量在所有函数外部定义,则变量具有全局作用域,例如:f1.cppintx,y=4;/*全局变量x,y的作用域起点*/voidmain(){floatf1(floata)...}floata=8,b;/*全局变量a,b的作用域起点*/floatf1(floata){…}2、全局作用域:6.61变量的作用域全局变量可以被其作用域内的所有函数访问,因此可以作为一种在各函数间传递数据的手段例6-16foaltResult;main(){floatx,y;printf(“Enterxandy:”);scanf(“%f%f”,&x,&y);plus(x,y);printf(“\nx+y=%f”,Result);}plus(floatx,floaty);{Result=x+y;}3、变量同名问题:6.61变量的作用域在C语言中,在同一个作用域内不允许出现同名变量定义。同名变量仅在不同的作用域中才可以合法出现。这时,它们的使用将遵循如下规则:1)如果一个作用域与其所包含的子作用域内都定义了相同的变量,则在子作用域内,子作用域中定义的变量将屏蔽子作用域外部的同名变量。2)相互独立的两个作用域中的同名变量互不干扰。例6-17intx=0,y=0,z=0;other(){intx=100,y=200;printf(other\n);printf(x=%dy=%dz=%d\n,x,y,z);}main(){intx=1,y=2,z=3;printf(\nmain\n);printf(x=%dy=%dz=%d\n,x,y,z);other();}6.6.2变量的存储类型作用域:指从变量的使用范围(空间角度)来考虑:生存期:从变量值存在的时间角度考虑:C语言变量的存储类型决定了该变量的作用域和生存期。在叫法上是这样的,例如:autointx;称x为自动存储类型的变量,简称自动变量staticfloaty;称y为静态存储类型的变量,简称静态变量C语言有四种存储类型,即:auto自动型。extern外部型或全局型。static静态型。register寄存器型。自动型变量的定义格式[auto]数据类型标识符变量名;其中,auto可以省略。性质:1、其作用范围限于函数所在
本文标题:C程序设计教程与实训(第二版)第6章
链接地址:https://www.777doc.com/doc-3174808 .html