中央电大C语言A课程辅导6.docx
- 文档编号:2639789
- 上传时间:2023-05-04
- 格式:DOCX
- 页数:17
- 大小:24.58KB
中央电大C语言A课程辅导6.docx
《中央电大C语言A课程辅导6.docx》由会员分享,可在线阅读,更多相关《中央电大C语言A课程辅导6.docx(17页珍藏版)》请在冰点文库上搜索。
中央电大C语言A课程辅导6
C语言程序设计A课程辅导(6)
---第6章函数
主要内容:
一、函数的定义
二、函数的调用
三、变量的作用域
四、递归函数
五、函数指针
六、函数应用举例
一、函数的定义
●函数定义格式
[<有效范围>]<类型名><函数名>(<参数表>)<函数体>
有效范围:
由所使用的保留字extern或static决定,若使用extern则称为全局函数或外部函数;若使用static则称为局部函数或静态函数。
若<有效范围>选项被省略,则默认为是全局函数。
对于全局函数,能够在一个程序的其他每个程序文件中被声明和调用;对于局部函数,则只能被所在的程序文件声明和调用。
类型名:
给出函数通过return语句返回的值的类型,当使用保留字void作为类型名时,则不需要返回值。
函数名:
是用户为函数所起的名字,它是一个符合C语言命名规定的标识符。
通常用函数名反映该函数的功能。
如用SUM表示求和。
参数表:
又称形式参数表,它包含有任意多个参数说明,当多于一个时其前后两个参数说明项之间必须用逗号分开。
每个参数说明包括类型名和参数名两项内容。
函数体:
是一条复合语句,它以左花括号开始,到右花括号结束,中间为一条或若干条C语句。
函数头:
在函数定义中,函数体之前的部分构成函数头,又称为函数原型。
取出函数头再加上分号就构成该函数的原型声明语句。
●函数定义格式举例
(1)voidf1(){...}//返回无类型,无须返回值,函数名为f1
//参数表为空,即不带有任何参数。
(2)staticvoidf2(intx){...}//文件域函数,无返回类型,函数名
//为f2,带有一个int型参数x
(3)intf3(intx,int*p){...}//全局域函数,返回值类型为int,
//函数名为f3,带有2个参数,一个为整型x,另一个为整型指针p
(4)char*f4(chara[]){...}//返回类型为字符指针,函数名为f4,
//带有一个一维字符数组参数a,标记为后跟一对中括号
(5)voidf5(floatc[][N],intm){...}//无类型,函数名f5,第
//1个为二维单精度型数组参数c,第2个为整型参数m。
//标记是后跟两对中括号,并在第2个内给出常量(列数)。
●函数定义和使用的几点说明
函数定义位置:
可以出现在整个程序的任一个程序文件内的任何位置。
函数原型声明语句:
在利用函数调用表达式调用一个函数之前,必须出现有该函数的原型声明语句或函数定义。
函数的常量形参:
即在一般的形参说明项前加上const修饰。
如:
voidf6(constfloatx,floaty){...}//x常量形参,y一般形参
voidf7(constchar*a,char*b){...}//a常量形参,b一般形参
在f6函数体中只能读取x的值,不能改变它的值,对y可任意操作。
在f7函数体中只能读取a所指的字符或字符串,不能改变它,对b任意。
一维数组参数说明项的格式:
<数据类型><数组名>[]
等价于指针参数说明:
<数据类型>*<指针变量名>
指针变量名就是数组参数说明中的数组名。
如一个函数定义中的数组参数说明
inta[]//数组参数说明,指向int类型元素的指针
int*a//等价于指针参数说明
当调用它们时,对应的实参为同类型的数组名,访问它们既可以是指针方式也可以是下标方式。
二维数组参数说明项格式:
<数据类型><数组参数名>[][<列数>]
等价的指针参数说明:
<数据类型>(*<指针参数名>)[<列数>]
如假定一个函数定义中的:
二维数组参数说明:
floatc[][N]//指向N个float类型元素的指针
等价的指针参数说明:
float(*c)[N]
当调用它们时,与c对应的实参为具有相同列数N的二维数组名,访问它们既可以是指针方式也可以是下标方式。
●编写具体函数定义举例
例1:
编写一个函数定义,求3个整数中的最大值。
intMaxValue(intx,inty,intz)//用x,y,z分别表示3个整数形参
{
intw;//w作为临时变量,存放大者
if(x>=y)w=x;elsew=y;//x和y中的大者赋给w保存
if(w>=z)returnw;elsereturnz;//返回w和z中的大者
}
例2:
编写一个函数定义,求n个整数中的最大值。
分析:
n个整数用一个一维数组a来表示,n也是一个整型参数,采用顺序比较的方法查找出数组a[n]中的最大值。
intMaxArray(inta[],intn)//数组参数和表示数组长度的参数
{//inta[]可改为int*a
intx,i;//用x保存当前比较中的大者,i为循环变量
x=a[0];//把a中第1个元素值赋给x
for(i=1;i if(a[i]>x)x=a[i]; returnx;//返回最大值 } 二、函数的调用 ●函数调用格式 <函数名>(<实际参数表>) 函数调用: 又称为函数调用表达式。 函数名: 在前面已经声明或定义了的函数名称,否则在编译时将报错。 实参表: 可含0、1或多个用逗号分开的实参,每个实参可以为任何表达式。 每个实参同函数定义或声明中的形参相对应。 ●格式举例 (1)fd1();//实参表为空 (2)fd2(bx,10);//实参表有2个参数,一个为变量,一个为常量 (3)fd3(2*a-3);//实参表只有一个参数,它是一个算术表达式 (4)doubley=fd4(5,sin(x),b[3]);//常数、函数、下标变量 ●调用过程 第一步: 参数传递。 把实参的值传送给函数定义中对应的形参。 第二步: 执行函数体。 执行函数定义中的函数体。 第三步: 返回。 当执行到函数体中的任一条return语句或最后的花括号则返回。 ●参数传递 就是在函数调用时,自动把实参表中的每个实际参数的值向形参表中每个对应的形式参数传递的过程。 此过程首先计算出每个实参值,接着为每个形参变量分配相应的存储空间,然后把每个实参值对应赋给每个形参变量中。 举例1: intf1(intx,inty,intz)//参数为一般变量 { intw; if(x>=y)w=x;elsew=y; if(w>=z)returnw;returnz; } ints=f1(25,38,30);//调用f1函数,返回值为38 inta=15,b=23,c=36,d;d=f1(a,b,c);//实参值不变,返回值36 举例2: voidf4(int*x,int*y)//参数为指针变量 {//交换x和y所指向对象的内容,作用于实参变量 intw; w=*x;*x=*y;*y=w; } inta=25,b=18;f4(&a,&b);//把a和b的地址赋给x和y,实参值被交换 得到结果: a=18,b=25 举例3: voidf5(inta[],intn)//int*a,参数为数组(指针)变量 {//按相反次序排列数组a[n]的n个数据,作用于实参数组 inti,w; for(i=0;i w=a[i];a[i]=a[n-1-i];a[n-1-i]=w;//对称值对调 } } intb[5]={12,35,56,62,78}; f5(b,5);//把b的值传送给a,a也指向b,修改了数组b 得到结果: b[5]={78,62,56,35,12} 举例4: intf6(constint*a,intn)//a[],参数a所指对象不能被修改 {//返回数组a[n]中的n个整数之和 inti,sum=0; for(i=0;i returnsum;//若a[i]=5则编译出错 } intb[5]={5,8,4,10,20}; intx=f6(b,5);//把b的值传送给a,a也指向b //返回值47 举例5: #include #defineCol10 voidf7(char(*a)[Col],intm); voidmain(){ charb[3][Col]={"one","two","three"}; f7(b,3);//把b的值传送给a,输出b中3个字符串 } voidf7(char(*a)[Col],intm)//二维数组参数a[][Col] { inti; for(i=0;i printf("%s\n",a[i]); } 三、变量的作用域 ●变量作用域的概念 程序中使用的每个变量都有它的作用域(有效区域),离开它的作用域该变量就不起任何作用了。 变量的作用域从定义它的位置开始,到所在的程序模块结束。 ●作用域分类: 全局、文件、函数、块 Ø全局域变量: 在所有函数定义之外定义的变量,通常是在主程序文件的开始或头文件中定义,在该程序的所有文件里都有效,但在其他程序文件中使用时必须加以声明。 全局变量若没有被初始化,则自动被赋值0。 Ø文件作用域变量: 在所有函数定义之外定义的变量,通常是在每个程序文件的开始定义,此变量定义语句的开始必须使用static保留字。 文件域变量的作用域属于所在的文件,若它没有被初始化,则也自动被赋值0。 例如: #include #defineNN15//相当于文件域常量 intx=3,y;//全局变量,x值3,y值0 staticdoublea,b;//文件域变量,初值均为0.0 constintMM=20;//全局域常量 voidmain(){…}//可以使用以上定义的任何常量和变量 //在同一程序的其他程序文件中,经声明后只能使用上面的全局量 //声明格式为: externintx,y;externconstintMM; Ø函数作用域: 专指语句标号,供goto语句用。 Goto语句只能转移到本函数定义中的一个带有语句标号的位置。 Ø块作用域变量: 又称为局部变量。 一种情况: 在一条复合语句内定义,作用域从定义点开始到复合语句结束。 另一种情况: 函数定义中的形参变量,作用域为整个函数体。 ●函数定义体内的自动变量和静态变量 函数定义体内的变量都属于块作用域变量,即局部变量,但根据变量性质又分为2种: 一种叫自动变量,另一种叫静态变量。 如: voidff() { intz=0;//自动变量,不赋初值,值不确定 staticintk;//静态变量,第1次自动赋初值0 k+=5;//每次调用此函数在k的原值上加5 z+=5;//每次都在0上加5 } inti;for(i=1;i<=5;i++)ff(); ●分析变量作用域的程序举例 程序1: #include #defineNN8//文件域符号常量 intNum[NN]={12,10,8,3,5,0,7,2};//全局域数组 intSum(){//求全局数组Num[NN]中的所有元素之和 inti,s=0;//i,s为局部变量,作用域为此函数体 for(i=0;i returns;//返回所求元素之和 } intMax(){//求全局数组Num[NN]中的所有元素的最大值 inti,m=Num[0];//i,m为局部变量,作用域为此函数体 for(i=1;i returnm;//返回所有元素的最大值 } voidmain(){ intc;//局部变量,从此处到主函数结束 c=Sum()+2*Max();//47+2*12=71 printf("c=%d\n",c);//输出结果: c=71 } 程序2: #include intMul(inta[],intn);//函数原型声明语句 voidmain() { intb[5]={1,2,3,4,5};//只作用于主函数的数组 intr1,r2;//只作用于主函数的局部变量 r1=Mul(b,5);//所有元素乘积,值120 r2=Mul(b+2,3);//b[2]*b[3]*b[4],值60 printf("r1=%d,r2=%d\n",r1,r2);//输出: r1=120,r2=60 } intMul(inta[],intn){//a和n的作用域为该函数 inti,p=1;//局部变量,作用域到复合语句结束 for(i=0;i returnp;//返回p的值 } 程序3: #include intx=10;//全局变量 voidmain() { inty=20;//局部于整个主函数的变量 printf("x=%d,y=%d\n",x,y);//输出: x=10,y=20 { intx=30;//局部于此复合语句内的变量,优先于外部同名变量 y=y+x;//y为外部的,x为内部的 printf("x=%d,y=%d\n",x,y);//输出: x=30,y=50 }//内部的x的作用域就此结束 printf("x=%d,y=%d\n",x,y);//输出: x=10,y=50 }//y作用域就此结束 //全局变量x的作用域到整个程序运行结束 程序4: #include intCdiv(intm,intn)//求出m和n的最大公约数 {//m和n只作用于此函数 intr;//局部变量 if(m while(r=m%n){m=n;n=r;}//循环结束时n的值为最大公约数 returnn;//返回n值 } voidmain() { intm,n;//此处的m和n只作用于主函数 printf("输入两个正整数求其最大公约数: "); scanf("%d%d",&m,&n); printf("%d和%d的最大公约数为: %d\n",m,n,Cdiv(m,n)); //进行Cdiv(m,n)调用时,m和n的值分别对应传送, //在Cdiv(m,n)的函数体中对m和n的修改,与此处的m和n无关 }//允许不同作用域的变量同名 运行结果: 输入两个正整数求其最大公约数: 2540 25和40的最大公约数为: 5 程序5: #include voidxk2(); voidmain() { inti; for(i=1;i<=4;i++)xk2(); } voidxk2() { inta=0;//每次调用此函数时都要重新建立a并被初始化 staticintb=0;//只在第1次调用时建立和初始化,以后继续使用 a++;b++; printf("a=%d,b=%d\n",a,b);//每次a的值为1,b的值被增1 } 运行结果: a=1,b=1 a=1,b=2 a=1,b=3 a=1,b=4 四、递归函数 ●定义: 在函数执行中又直接地调用自己,若函数体中含有调用自身的函数调用表达式则称为直接调用,此函数称为递归函数。 ●递归函数举例 如: intf(intn){ if(n==0||n==1)return1;//直接返回 elsereturnn*f(n-1);//进行递归调用 } intx=f(5);//f(5)->5*f(4)->5*4*f(3)->5*4*3*f (2)->5*4*3*2*f (1) ->5*4*3*2*1->5*4*3*2->5*4*6->5*24->120//x=120 又如: intf7(inta[],intn){ if(n==1)returna[0];//结束递归并返回 elsereturna[n-1]+f7(a,n-1);//递归调用 } inta[5]={2,5,4,8,6}; intz=f7(a,5);//6+f7(a,4)->6+8+f7(3)->6+8+4+f7 (2)->6+8+4+5+f7 (1) ->6+8+4+5+2->6+8+4+7->6+8+11->6+19->25//z=25 *五、函数指针 ●函数名是指向该函数执行代码的指针 intfa(intx,inty){returnx+y;}int(*)(int,int) ●定义函数指针变量并赋予同类型函数的函数名(指针)后,可以同函数名一样使用 int(*fp)(int,int)=fa; fa(a,b);fp(a,b); ●函数的形参表中也可以使用函数参数 voidfc(char*p,inthf(int,int));//hf为函数形参 //fc(”abcd”,fa);fc(str,fp);//fa和fp为函数实参 ●使用函数参数的程序举例 #include intLength(char*p){inti=0;while(*p++)i++;returni;}//返长度 voidOut(char*s,int(*pp)(char*))// { printf("%d: %s\n",pp(s),s);//输出s串的长度和串值 }//pp(s)的调用就是Length(s)的调用 voidmain() { char*x1="123456"; char*x2="asderoiu"; Out(x1,Length);//输出: 6: 123456 Out(x2,Length);//输出: 9: asderoiu } 六、利用函数编写程序举例 通常用一个函数,完成一个程序设计中相对独立的功能,而一个程序通常有若干个函数所组成,整个程序的功能通过函数的调用来实现。 例1: 编写一个程序,判断从键盘上输入的任一个整数是否为素数。 分析: 判断一个整数是否为素数的功能相对独立,可以单独编写成一个函数,该函数带有一个整数参数,假定用x表示,函数名假定用Prime表示,该函数应该把判断结果返回,所以返回类型应定义为int,当返回1时表明x是一个素数,返回0时则表明不是一个素数。 若一个整数是素数,则它不能被除1和本身之外的任何数整除,也就是说,若一个整数x能够分解为两个整数a和b的乘积,则它就不是素数,在这两个整数a和b中,一个若小于等于 ,则另一个必然大于等于 。 所以判断一个整数x是否为素数,只要判断是否能够被2~ 中的任一数整除即可,若能够被其中的任一个数整除,则它不是素数,若不能被其中的所有数整除,则才是一个素数。 根据以上分析,编写出函数如下: intPrime(intx){ inty=(int)sqrt(x); inti; for(i=2;i<=y;i++) if(x%i==0)break; if(i>y)return1;elsereturn0; } 在该程序的主函数中,应定义一个整型变量,假定仍用x表示,用来接收从键盘上输入的整数,接着应把x作为实参去调用求素数的函数,判断x是否为素数,然后再根据不同的判断结果输出相应的信息。 带主函数的程序如下: #include #include intPrime(intx); voidmain(void) { intx,yn; printf("从键盘输入一个正整数: "); scanf("%d",&x); yn=Prime(x); if(yn)printf("%d是一个素数! \n",x); elseprintf("%d不是一个素数! \n",x); } 若程序要求输出自然数100以内的所有素数,只要修改一下主程序即可得到。 voidmain(void) { intx,yn; printf("%d",2); for(x=3;x<=99;x+=2){ yn=Prime(x); if(yn)printf("%d",x); } printf("\n"); } //2357111317192329313741434753596167717379838997 例2: 编写一个函数,对一维数组a[n]中的n个整数进行排列,排列的条件是: 使得数组的前面部分保存小于60的元素值,数组的后面部分保存大于和等于60的元素值。 分析: 在数组的两端各设置一个位置指针i和j,开始分别指向下标0和n-1的位置,接着使前面指针i依次向后移动,直到a[i]>=60则停止,再接着使后面指针j依次向前移动,直到a[j]<60则停止,此时交换a[i]和a[j]元素的值,并分别使i和j指针向中间方向移动一个位置,然后再重复上述过程,直到i>=j为止。 例如: a[8]={23,67,52,83,75,28,44,70} i↑j↑ a[8]={23,67,52,83,75,28,44,70} i↑j↑ a[8]={23,44,52,83,75,28,67,70} i↑j↑ a[8]={23,44,52,83,75,28,67,70} i↑j↑ a[8]={23,44,52,83,75,28,67,70} i↑j↑ a[8]={23,44,52,28,75,83,67,70} i,j↑ 函数定义: voidTwoPart(inta[],intn) { inti=0,j=n-1; intx; while(i while(a[i]<60&&i while(a[j]>=60&&j>=0)j--;//条件满足时指针前移 if(i
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 中央电大 语言 课程 辅导