C语言(第7章函数)_第1页
C语言(第7章函数)_第2页
C语言(第7章函数)_第3页
C语言(第7章函数)_第4页
C语言(第7章函数)_第5页
已阅读5页,还剩36页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C语言程序设计信息与计算机学院Email:yixuan0820@163.com第7章函数本章主要内容:函数的定义函数的调用函数的参数和函数返回值递归函数变量的作用域和存储类别7.1函数的定义C函数的概念函数:一段可以重复调用的、功能相对独立完整的程序段。1)库函数:由C语言系统提供,用户无须定义,可直接使用。2)用户自定义函数:由用户按需要编写的函数函数的定义函数定义的一般形式为:类型标识符函数名(类型形式参数,类型形式参数,…){

声明部分执行部分}说明:类型标识符用来定义函数类型,即指定函数返回值的类型。函数类型应根据具体函数的功能确定。默认类型标识符为int类型。函数值通过return语句返回。函数执行时一旦遇到return语句,则结束当前函数的执行,返回到主调函数的调用点。

如果函数执行后没有返回值,则函数类型标识符用“void”,称为“空类型”或“无类型”。

函数名必须符合标识符的命名规则。在函数定义时,函数体中不能再出现与函数名同名的其他对象名(如变量名、数组名等)。函数首部括号内的参数称为形式参数(简称形参),形参的值来自函数调用时所提供的参数(称为实参)值。形参也称形参变量。【例7.4】求一个数的立方。#include<stdio.h>longcub(int

x)/*函数定义*/

{longy;/*函数体中的声明部分*/

y=x*x*x;/*函数体中的执行部分*/

returny;}voidmain(){intnum;longcub_num;

printf("请输入一个整数:\n");

scanf("%d",&num);

cub_num=cub(num);/*函数调用*/

printf("%d的立方值是%1d",num,cub_num);}函数调用的过程:①创建形参变量,为每个形参变量建立相应的存储空间。②值传递,即将实参的值复制到对应的形参变量中。③执行函数体,执行函数体中的语句。④返回(带回函数值、返回调用点、撤消形参变量)。实参形参7.2函数参数和返回值形式参数和实际参数

形参:在定义函数时函数名后面括号中变量名称为形式参数,简称形参。实参:在主调函数中调用一个函数时,函数名后面括号中的参数称为实际参数,简称实参。实参形参(1)传递数值(值传递方式)(2)传递地址(地址传递方式)函数关于参数的几点说明:⑷实参可以是常量、变量或表达式,并且必须有确定的值;⑶对每个形参必须指明其名字和数据类型;⑸实参个数、类型必须与对应的形参一致;⑵形参是函数的内部变量,只在函数内部才有意义;⑹实参对形参的数据传递是值传递,即单向传递,只由实参传递给形参,反之不可。调用结束后,只有形参单元被释放,实参单元中原来的值不变。⑴形参调用前不占内存单元,调用时占用,调用后释放;1、用函数调用完成求一个数组{12,3,2,4,5,8,9,12,2,40}中的最小(大、平均值、总和)元素值

要求:通过函数调用实现(计算方法在子函数中,通过主函数调用实现)

2、求一个数的平方(立方);

3、求两个数的平方和(平方差);

4、用函数调用完成求一个3×3数组主对角线上所有元素的最大值。(注:主对角线是左上角到右下角的对角线)【例7.5】分析以下程序的运行结果。(值传递方式)#include<stdio.h>voidswap(float

x,floaty)/*定义交换变量x,y值的函数*/{floattemp;temp=x;x=y;y=temp;

printf("x=%.2fy=%.2f\n",x,y);}voidmain(){floatx=8.5,y=3.7;swap(x,y);/*调用swap函数*/

printf("x=%.2fy=%.2f\n",x,y);}结论:由于形参与实参各自占用不同的存储空间,因此,在函数体执行中,对形参变量的任何改变都不会改变实参的值。地址传递方式:

函数调用时,将实参数据的存储地址作为参数传递给形参。其特点是:形参与实参占用同样的内存单元,函数中对形参值的改变也会改变实参的值。因此函数参数的地址传递方式可实现调用函数与被调函数之间的双向数据传递。比较典型的地址传递方式就是用数组名作为函数的参数,在用数组名作函数参数时,不是进行值的传送,因为实际上形参数组并不存在,编译系统不为形参数组分配内存。实际上是形参数组和实参数组为同一数组,共同拥有同一段内存空间。【例7.6】一个一维数组score内放10个学生成绩,用一个函数求平均成绩。(地址传递方式)#include<stdio.h>floataverage(float

array[10]){inti;floataver,sum=array[0];

for(i=1;i<10;i++)sum=sum+array[i];aver=sum/10;

return(aver);voidmain(){floatscore[10],aver;

inti;

printf("请输入10个学生的成绩:\n");

for(i=0;i<10;i++)

scanf("%f",&score[i]);

printf("\n");aver=average(score);

printf("平均成绩是%5.2f\n",aver);}

程序说明:①用数组名作函数参数,应在主调函数和被调用函数分别定义数组,其中score是实参数组名,array是形参数组名。②在被调用函数average中声明了形参数组的大小是10,其实指定其大小不起作用,形参数组可以不指定大小,在定义数组时可以只在数组名后跟一个空的方括号。因为C语言编译系统对形参数组大小不做检查,只是将实参数组的首地址传给形参数组,因此形参数组名获得了实参数组的首元素的地址。7.2.2函数的返回值return语句的一般形式:①return;②return表达式;或return(表达式);例如:下面是3个函数的首行:intmax(floata,floatb)/*函数值为整型*/charletter(charc1,charc2)/*函数值为字符型*/doublemin(inty,inty)/*函数值为双精度型*/【例7.8】调用函数返回两个数中的较大者。#include<stdio.h>intmax(floatx,floaty){floatz;

z=x>y?x:y;

return(z);

}voidmain()

{floata,b;

intc;

scanf("%f,%f",&a,&b);

c=max(a,b);

printf("较大的是%d\n”,c);

}7.3函数的调用调用有参函数的一般形式:

函数名(实参表列)

如果是调用无参函数,则没有实参表列,但括号不能省略。形式如下:

函数名()

函数调用可以有三种方式。①表达式方式:c=2*max(a,b);②参数方式:d=max(a,max(b,c))③语句方式:不要求函数带回返回值的情况下。7.3.2函数声明函数声明的目的是通知编译系统有关被调用函数的一些特性,便于在函数调用时,检查调用是否正确。

函数声明的一般形式如下:

类型标识符函数名(类型参数名,类型参数名,…);或

类型标识符函数名(类型,类型,…);

说明:如果被调函数定义的位置在主调函数之前,主调函数中可以省略对被调函数的声明。int

max(int

x,inty){ruturn((x>y)?x:y);}voidmain(){…c=max(a,b);…}voidmain(){…

intmax(intx,inty);c=max(a,b);…}

int

max(int

x,inty){ruturn((x>y)?x:y);}函数声明一、嵌套调用:在调用一个函数的过程中又调用另一个函数。

例如:int

fb(){……}int

fa(){…fb(“…”);…}voidmain(){……x=fa();……}调用fb函数调用fa函数7.4.1函数的嵌套调用函数的嵌套调用执行过程main函数调用fa函数结束fa函数调用fb函数fb函数fa函数结束fb函数结束递归调用:一个函数直接或间接地调用此函数本身。

7.4.2函数的递归调用用递归求解问题的过程分为两个阶段:1.递推阶段:将原问题不断地转化成子问题。逐渐从未知向已知推进,最终到达已知解的问题,递推阶段结束。2.回归阶段:从已知解的问题出发,按照递推的逆过程,逐一求值回归,最后到达递归的开始处,结束回归阶段,获得问题的解。递归调用对应的一般算法:f(x)=终了公式递归公式递归调用函数的一般形式为:类型标识符

函数名(形参列表){……

if(递归调用的终止条件)语句1;

else

语句2;……return返回值}【例7.11】用递归方法计算n!longjc(intn){longt;if(n<0)

printf(“n<0,输入数据错!”);elseif(n==0||n==1)return1;elsereturnn*jc(n-1);}计算n阶乘的数学递归定义式:#include<stdio.h>voidmain(){longjc(intn);

intn;

printf("请输入n:\n");

scanf("%d",&n);

printf("%d!=%ld\n",n,jc(n));}longjc(intn){longt;if(n<0)

printf(“n<0,输入数据错!”);elseif(n==0||n==1)t=1;elset=n*jc(n-1);returnt;}对jc函数的声明调用jc函数程序执行顺序图例(假设n=3)main函数调用jc(3)结束jc(3)函数3*jc(2)jc(3)结束jc(2)函数2*jc(1)jc(2)结束jc(1)函数返回1jc(1)结束递推递推递推回归回归回归返回值1返回值2返回值6例:有5个人做在一起,问第5个人多大岁数?他说比第4个人大3岁。问第4个人多大岁数?他说比第3个人大3岁。问第3个人多大岁数?他说比第2个人大3岁。问第2个人多大岁数?他说比第1个人大3岁。最后问第1个人,他说自已是20岁。请问第5个人多大?age(x)=20x=1age(x-1)+3x>1#include<stdio.h>int

age(intx){

if(x==1)retunr20;elsereturnage(x-1)+3;}voidmain(){

intz;z=age(5);

printf(“第5个人是:%d岁”,z;);}使用递归调用,最关键的是要确定以下两点:1)确定递归的终止条件;2)确定递归的形式---即求解的规律;7.5变量的作用域变量定义的位置不同,使得其作用范围也不同。全局变量:在函数外面定义的变量,其作用域从变量定义的位置开始到文件结束。局部变量::在函数内部定义的变量,其作用域是所定义的函数。变量inta;

/*定义全局变量,可在main和fun函数中引用*/voidmain()

{

intfun(intz);函数声明;int

x,y;

/*x、y为局部变量,只能在main函数中引用*/

…}intb;

/*b为全局变量,可在fun中引用*/fun(intz)

/*形参z为局部变量,可在fun函数中引用*/{

intc;

/*c为局部变量,可在fun函数中引用*/…}变量的作用域a变量的作用域b【例7.13】编写一个函数,求两个数的和与差。#include<stdio.h>

floatadd,diff;

/*全局变量*/voidfun(float

x,floaty){add=x+y;diff=x-y;}voidmain(){floata,b;

scanf("%f%f",&a,&b);

fun(a,b);printf("%.2f%.2f\n",add,diff);}注意:因为函数值只能有一个,所以当需要通过函数得到两个或多个值时,就要定义全局变量。voidnum()

{extern

int

x,y;

inta=7,b=5;

x=a-b;

y=a+b;

}int

x,y;void

main()

{

inta=7,b=5;x=a-b;y=a+b;num();}x,y的原作用域

x,y新的作用域如果在全局变量定义位置之前或其他文件中的函数要引用该全局变量,应该在引用之前用关键字extern对该变量做声明,表示该变量是一个已经定义的全局变量。当全局变量与局部变量同名时,在局部变量的作用范围内全局变量不起作用。【例7.15】全局变量与局部变量同名#include<stdio.h>floatadd=1,diff=1;/*全局变量*/voidfun(float

x,floaty){floatadd,diff;/*局部变量*/add=x+y;diff=x-y;}voidmain(){floata,b;scanf("%f%f",&a,&b);fun(a,b);printf("%.2f%.2f\n",add,diff);}7.6变量的存储类别程序存储区静态存储区动态存储区用户存储空间分配示意图存储程序代码全局变量函数的形参,auto变量,函数调用时的现场保护和返回地址等1.静态存储方式:在程序运行期间由系统分配固定的存储空间的方式,在静态存储区分配内存的变量,直到整个程序运行结束时才释放内存。

2.动态存储方式:指在程序运行期间根据需要由系统动态分配存储空间的方式,在动态存储区分配内存的变量,当函数调用结束或复合语句结束时,立即释放内存空间。

变量的存储类别:变量的存储类别有:auto自动型:(缺省的都是auto型)

static静态型register寄存器型extern外部型:一、auto变量(自动变量)分配内存位置:动态存储区生存期:需要时分配空间,不需要时被撤销;二、static变量(静态变量)静态型变量可分为静态局部变量和静态全局变量

静态局部变量:分配内存位置:静态存储区;生存期:在程序运行期间一直存在,直到程序结束被撤消。初始化:对静态局部变量在编译时赋初值,若没有赋初值,则系统自动赋初值0(对数值型变量)或空字符(对字符变量)。使用:只初始化一次,以后每次调用函数时不再重新赋初值,都是保留上一次函数调用结束时的值。例7.16】考察static(静态)局部变量与auto(自动)变量的区别。

#include"stdio.h"intfunc1(){staticints=5;/*静态局部变量*/s+=1;return(s);}intfunc2(){ints=5;/*局部变量*/s+=1;return(s);}voidmain(){

inti;

for(i=0;i<3;i++)printf("%3d",func1());

printf("\n");

for(i=0;i<3;i++)printf("%3d",func2());}

静态全局变量:如果在程序设计时希望某些全局变量只限于被本文件中的函数引用,而不能被其他文件中的函数引用,就可以在定义全局变量时加上static进行声明。3.register寄存器型在CPU的寄存器中分配存储空间,访问速度快,并不是在内存中分配存储空间。4.extern外部型用于扩展全局变量的作用域。课后练习和习题课后习题:函数调用的例子#include<stdio.h>voidmain(){voidprintstar();/*对printstar函数进行声明*/voidprint_message();/*对print_message函数进行声明*/

printstar();/*调用printstar函数

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论