C案例教程教案(word文档)第七章.doc_第1页
C案例教程教案(word文档)第七章.doc_第2页
C案例教程教案(word文档)第七章.doc_第3页
C案例教程教案(word文档)第七章.doc_第4页
C案例教程教案(word文档)第七章.doc_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

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

文档简介

第7章 函数7.1 C语言程序的特点 1 C语言以文件作为一个编译单位。一个程序源文件可以由一个或多个函数组成,而一个C程序可以包含一个或多个源文件,各个程序源文件可以分别编译,然后连接起来,形成一个可执行程序文件。 2 C程序的执行是从main()函数开始,调用其它函数后流程返回到main()函数,并在main函数中结束整个程序的运行。 3 所有的函数在定义时是相互独立平行的,函数之间不能嵌套定义。 4 函数间可以相互调用,main()函数是主函数,可以调用其它函数,其它函数不能调用main函数。调用者称为调用函数,函数还可以自己调用自己,称为递归调用。 5 函数的分类: 从用户使用角度分为为两类: 库函数系统提供的,用户不必自己定义这些函数,可以直接调用。 用户自定义函数用户自己编写的函数,用来完成程序中的某项特定功能。 从函数参数的角度来分类: 无参函数函数定义时无形式参数。 有参函数函数定义时有一个或多个形式参数。在调用函数时,在调用函数和被调用函数之间有参数传递。即调用函数可以将数据传送给被调用函数使用。 7.2 函数定义 1 有参函数定义的一般形式: extern/static类型说明符 函数名 (类型 形参1,类型 形参2,) 说明部分 语句 说明: (1) extern/static只能取其中之一,如无说明,隐含为extern。 (2) 类型说明符是函数返回值的类型。当返回值为int类型时,类型说明符可以省略。 (3) 函数名是由用户定义的标识符。 (4) 形参说明部分用以说明形式参数的类型。 (5) 中的内容称为函数体,在函数体中也有类型说明。 2 无参函数定义的一般形式: extern/static类型说明符 函数名( ) 说明部分 语句 无参函数通常用来完成一项指定的功能,可以返回或不返回函数值,函数没有参数。 3 空函数 C语言允许定义一个空函数,即函数什么也不做。 4 函数的值 函数调用结束后向调用函数返回一个执行结果,该结果称为函数的返回值(也称函数的值)。函数的返回值是通过return语句返回的。return语句将被调用函数中的一个确定值返回到调用函数相应的表达式中去。return语句的一般形式为: return 表达式; 或者 return (表达式); 该语句的功能是计算表达式的值,并返回给调用函数。 说明: (1) 在函数中允许有多个return语句,只能有一个return语句被执行,只能返回一个函数值。 (2) 如果函数有返回值,就必须指定函数的返回值的类型。如果定义函数时没有指定函数的类型,将自动定义为int型。 (3) 如果函数不需返回任何值,函数类型可定义为void类型。 (4) 一般地,定义函数的类型与return语句后表达式的类型保持一致。如果两者不一致,则以函数类型为准,系统自动进行类型转换。即函数的类型将决定函数返回值的类型。 7.3 函数调用 1 函数调用的形式: 函数名(实参列表); 说明: (1) 调用有参函数,就必须给出实参列表。 (2) 实参列表的在类型、顺序、个数上应该与形参严格一致。 (3) 如果是无参函数,就没有实参列表。但调用无参函数时函数名后的圆括号不能省略。 2 对被调用函数的函数声明 (1) 被调用函数必须是已经存在的函数(库函数或自定义函数); (2) 调用库函数时必须在文件开头使用#include命令将其相应的头文件包含进来; (3) 如调用用户自定义函数,在调用之前必须对其进行显式声明; (4) 函数的声明位置:可以声明在调用函数之内,也可声明在程序开始。如果程序中一个函数被多个函数调用,可在程序开始处进行函数声明。 对被调用函数的声明格式为: 类型说明符 被调用函数名(类型1 形参1,类型2 形参2,类型n 形参n); 或者为: 类型说明符 被调用函数名(类型1,类型2,类型); C语言规定在以下几种情况时,可以省略对被调用函数的函数声明: (1) 当被调用函数的函数定义出现在本调用函数之前时,可以不对被调用函数再声明而直接调用。 (2) 因为库函数的函数声明就在其头文件中,所以调用库函数时不需要再声明,只把该函数的头文件用include命令包含在源文件前面即可。 3 函数的调用方式: 和库函数一样,自定义函数通常也有以下三种调用方式: (1) 函数语句:如对例7-2中定义的函数,调用方法为: wellcom(); (2) 函数调用出现在表达式中。如例7-4: m=average(a,b,c); (3) 函数调用还可作为函数参数。例如: printf(“average=%f”,average(a,b,c); 7.4 函数参数以及参数传递 7.4.1 形参和实参的特点 形参和实参的功能是数据传送。函数调用时,调用函数把实参的值传送给形参,实现调用函数向被调用函数的数据传送。函数的形参和实参具有以下特点:1 形参变量只有在函数调用时才分配存储单元,在调用结束后,即刻释放所分配的存储单元。因此,形参只有在函数内部有效。 2 无论实参是何种类型的变量,在进行函数调用时,它必须具有确定的值,以便把这些值传送给形参。 3 实参和形参在数量、类型、顺序上应严格一致,否则会发生“类型不匹配”的错误。 4 函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向传送给实参。 例7-4定义函数,该函数的功能是求 的值。 程序清单: #include int sum(int); /*函数声明*/ void main() int n=10,retun; retun=sum(n); /*调用函数sum(),把实参n的值传递形参n*/ printf(1+2+%d=%dn,n,retun); printf(形参n改变后实参n的值:%dn,n); int sum(int n) /*定义函数sum()*/ int i,s=0; for (i=1;i=n;i+) s+=i; n+=10; printf(形参n加10后的值:%dn,n); return s; 输出结果: 形参n加10后的值:20 1+2+10=55 形参n改变后实参n的值:10 7.4.2 数组作为函数参数 数组可以作为函数的参数使用,进行数据传送。数组用作函数参数有两种形式:种是数组元素作为参数使用;另一种是数组名作为函数的形参和实参使用。 数组元素与普通变量并无区别。在发生函数调用时,把实参数组元素的值传送给形参,实现单向的值传送。 数组名作函数参数时,把实参数组的首地址传递给形参数组。形参数组取得该首地址之后,它和实参数组为同数组,共用一段内存空间。在发生参数传递时,如果形参的值改变了,返回到调用函数时,实参数组的值也发生了改变。 例7-5 数组a中存放了一个学生5门课程的成绩,求平均成绩。 程序清单: #define N 5 #include float aver(float a,int n) /*n表示形参数组要处理的元素个数*/ int i; printf(n形参-输出某学生%d门成绩:n,N); for (i=0;in;i+) printf(“%4.1f ”,ai); float s=0; for (i=0;in;i+) s+=ai; printf(n形参-输出修改之后某学生%d门成绩:n,N); for (i=0;in;i+) ai+=10; printf(“%4.1f ”,ai); return s/n; void main() int i; float scoreN= 34.5,67.8,88,93,78,ave; printf(实参-输出某学生%d门成绩:n,N); for(i=0;iN;i+) printf(%4.1f ,scorei); ave= aver(score,N); printf(n实参-输出函数调用之后某学生%d门成绩:n,N); for(i=0;i中表示了一个函数嵌套调用的过程,在函数main中调用了函数1,而在函数1中又调用了函数2。函数在执行过程中,层层调用,层层返回。 例7-6 编程计算1-1/2+2/3-3/4+4/5-。 #include float add1(int); float get_num(int); void main( ) int n=7; printf(计算结果如下:%5.2fn,add1(n); float add1(int k) float x,sum=0; int i; for(i=0;ik;i+) x=get_num(i+1); sum+=x; return sum; float get_num(int p) if (p=1) return 1; if (p%2) return 1.0*(p-1)/p; else return -1.0*(p-1)/p; 输出结果: 计算结果如下: 1.24 本例中定义了两个函数addl()和get_num()。主函数中调用add1(),并传递参数n给形参k.。函数addl()中又调用get_num()函数k次,得到k个值,并将得到的值相加。这就是典型的嵌套调用。 7.6 函数的递归调用 一个函数直接地或间接地调用它自身称为函数的递归调用,这种函数称为递归函数。C语言允许函数的递归调用,在递归调用中、调用函数又是被调用函数。执行递归函数将反复调用其自身。 例7-7用递归函数来实观求n!=n(n-1) (n-2) (n-3) 21。 程序清单: #include long fac(int k) long f; printf(求%d!-,k); if (k=0|k=1) /递归结束条件 return 1; else return k*fac(k-1); void main( ) int n; printf(请输一个正整数n:); scanf(%d,&n); printf(n计算结果如下:%ldn,fac(n); 程序运行情况如下: 请输一个正整数n:8 求8!-求7!-求6!-求5!-求4!-求3!-求2!-求1!- 计算结果如下:40320 分析程序的执行过程: 递推过程: 欲求8!,知8*7!,求7!;欲求7!,知7*6!,求6!;欲求6!,知6*5!,求5!;欲求5!,知5*4!,求4!;欲求4!,知4*3!,求3!;欲求3!,知3*2!,求2!;欲求2!,知2*1!,求1!。 转入第二阶段回推过程: 1!已知,返回1;2*1!得2!,返回2;3*2!得3!,返回6;4*3!得4!,返回24;5*4!得5!,返回120;6*5!得6!,返回720;7*6!得7!,返回5040;8*7!得8!,返回40320。 通过本例可知:一个递归过程分为“递推”和“回推”两个过程。为了防止递归调用无终止地进行,必须在函数内有终止递归调用的手段。常用的办法是加条件判断,满足某种条件后就不再作递归调用,然后逐层返回。本例中的1!=1就是递归结束条件。 7.7 变量的作用域 函数中的变量按照作用域(即指变量在程序中的有效范围),可以分为局部变量和全局变量。 7.7.1 局部变量 局部变量也称为内部变量,它是在函数内部定义的。其作用域仅限于函数内,离开定义它的函数后再使用这种变量是非法的。 说明: (1) main函数中定义的变量也只能在main函数中使用,不能在其它函数中使用。同时,main函数中也不能使用其它函数中定义的变量。因为main函数也是一个函数,它与其它函数是平行关系。 (2) 形参变量也是局部变量。它只能在定义该变量的函数内有效。 (3) 允许在不同的函数中使用相同的变量名,因为它们代表不同的对象,分配不同的存储单元,互不干扰。 (4) 在复合语句中定义的变量,其作用域只在复合语句范围内有效。 float f1(int a) int b=3,c=9; /*形参变量a,局部变量b,c的作用域*/ char f2(int x1,float x2) int i,j; /*形参变量x1,x2,局部变量i,j作用域*/ void main() int a,b; /*局部变量a,b作用域*/ 例如: 函数f1和函数main中均有局部变量a,b,但它们的作用域不同,只在定义自己数内部有意义,编译时分配不同的存储单元,所以不会相互干扰。 7.7.2 全局变量 全局变量也称为外部变量或全程变量,是在函数外部定义的变量。它不属于某一个函数,而属于一个源程序文件。其作用域是从定义变量的位置开始到源文件结束。 例如: int a,b; /*定义全局变量a,b*/float f1(int a) int b,c; /*局部变量a,b,c的作用域*/ int x,y; /*定义全局变量x,y*/char f2(int x1,float x2) int i,j; /*局部变量x1,x2,i,j的作用域*/ void main() int m,n; /*局部变量m,n的作用域*/ 可以看出a,b,x,y都是在函数外部定义的全局变量。但x,y定义在函数fl之后,所以它们在f1内无效。a,b定义在源程序最前面,因此全程有效,在f2和main函数中也可使用。但f1中的b是局部变量,此时全局变量b无效。 说明: (1) 同一文件中如果全局变量和局部变量同名时,函数内局部变量有效,此时全局变量被屏蔽。函数之外,全局变量有效。 (2)若全局变量定义在文件开头,则全程有效;如果不在文件开头定义,又想在定义点之前使用该全局变量,只要在函数中用extern进行声明,即可对该变量的作用域进行扩充。例: extern int x,y; float f1(int a) int b=3,c=9; 新x,y作用域int x,y;void main() int a,b; 原x,y作用域 局部变量的定义和声明是同一概念,不加区分。全局变量只能定义一次,但可多次声明。声明可出现在函数之外,也可出现在函数内。定义时可赋初值,但声明时不能赋初值,只是表明在该范围内要使用全局变量。 声明的一般格式: extern 类型说明符 变量名表; 例7-8编写程序,输入两个数,调用函数找出最大值。 程序清单: #include int max(int x,int y) int z; if (xy) z=x; else z=y; return z; void main() extern a,b; /*全局变量声明*/ printf(“max=%dn”,max(a,b); int a=2,b=4; /*定义全局变量定义*/ 输出结果: max=4 变量的声明和定义的区别:变量的定义即给变量分配存储单元,变量的声明只是说明变量的性质,并不分配存储空间。 (3) 全局变量可以实现函数之间的数据通信。一般情况下,函数的返回值只有一个,通过全局变量,函数可返回多个值。 7.8 动态存储变量和静态存储变量 根据变量的作用域不同,可以将变量分为全局变量和局部变量。如果从变量的存在时间来区分,可以分为静态存储方式和动态存储方式。 静态存储变量通常是在变量定义时就分配存储单元并一直存在,直至整个程序结束。动态存储变量是在程序执行过程中,临时分配存储单元,使用完毕立即释放所占用存储单元。 在C语言中,每一个变量和函数有两个属性:数据类型和存储类别。所以对一个变量的说明不仅应说明其数据类型,还应说明存储类型。因此变量说明的完整形式如下: 存储类型说明符 数据类型说明符 变量名表 在C语言中,变量的存储类型说明有4种:自动变量(auto)、寄存器变量(register)、外部变量(extern)和静态变量(static)。自动变量和寄存器变量属于动态存储方式,外部变量和静态变量属于静态存储方式。 7.8.1 自动变量(auto) 自动变量为局部变量,说明符为auto。自动变量是C语言程序中使用最广泛的一种类型。C语言规定,自动变量可省去说明符auto,函数内凡未加存储类型说明的变量均为自动变量。 自动变量具有以下特点: 1 自动变量的作用域仅限于定义该变量的区域内。在函数中定义的自动变量,只在该函数内有效。在复合语句中定义的自动变量只在该复合语句中有效。 2 自动变量属于动态存储方式,只有在定义它的函数被调用时,才分配存储单元,开始它的生存期,函数调用结束,释放存储单元,结束生存期。因此函数调用结束之后,自动变量的值不能保留。在复合语句中定义的自动变量,在复合语句外也不能使用。 3 由于自动变量的作用域和生存期都局限于定义它的区域内(函数或复合语句内),因此不同的区域中允许使用同名的变量。即使在函数内定义的自动变量也可与该函数内部的复合语句中定义的自动变量同名。 4 函数的形参属于自动变量。 7.8.2 外部变量(extern) 外部变量用说明符extern来加以说明。外部变量是全局变量,可以直接用变量名来访问。编译时将外部变量分配在静态存储区。外部变量有以下几个特点: 1 外部变量和全局变量是对同一类变量的两种不同角度的提法。全局变量是从它的作用域提出的,外部变量从它的存储方式提出的,表示了它的生存期。 2 当一个源程序由若干个源文件组成时,在一个源文件中定义的外部变量在其它的源文件中也有效。 7.8.3 静态变量(static) 静态变量属于静态存储方式,说明符为static。静态变量的储空间在程序的整个运行期间是固定的,而不像动态变量那样在程序的执行过程中动态建立,动态撤销。 属于静态存储方式的变量不一定就是静态变量。例如,外部变量虽属于静态存储方式,但不一定是静态变量,必须用static加以定义后才能成为静态全局变量,或称全局静态变量。 1 静态局部变量 定义局部变量时,前面加了static说明符,定义的变量就是静态局部变量。静态局部变量属于静态存储方式,它具有以下特点: (1) 静态局部变量在函数内定义,它不像自动变量那样,执行时建立,执行结束就撤销,静态局部变量在程序的执行过程中始终存在,也就是说它的生存期为整个源程序。 (2) 静态局部变量的生存期虽然为整个源程序,但其作用域仍与自动变量相同,即只能在定义该变量的函数内使用该变量。退出该函数后,尽管该变量还继续存在,但不能使用它。 (3) 对基本类型的静态局部变量若在说明时未赋初值,则系统自动赋予0值。而自动变量若不赋初值,其值是不确定的。 (4) 对基本类型的静态局部变量只在第一次调用时初始化,以后调用不再初始化。 例7-10编写程序,调用函数分析动态局部变量与静态局部变量的不同。 程序清单: #include int fun(int a) auto int b=3; /*定义动态局部变量*/ static int c=3; /*定义静态局部变量*/ b=b+1; c=c+1; printf(动态局部变量b的值:%dt,b); printf(静态局部变量c的值:%dt,c); return(a+b+c); void main() int a=2,i; for(i=0;i3;i+) printf(t第%d次调用的值:%dn,i+1,fun(a); 输出结果: 动态局部变量b的值:4 静态局部变量c的值:4 第1次调用的值:10 动态局部变量b的值:4 静态局部变量c的值:5 第2次调用的值:11 动态局部变量b的值:4 静态局部变量c的值:6 第3次调用的值:12 2 静态全局变量 定义全局变量时,前面加了static说明符,定义的变量就是静态全局变量。全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。 两者的区别在于:全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,全局变量在各个源文件中都是有效的,只要在该文件中对它用extern进行声明即可使用。而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。 可以看出,当把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围,因此static这个说明符在不同的地方所起的作用是不同的,应予以注意。 7.8.4 寄存器变量(static) 上述各类变量都存放在内存中,当对一个变量频繁使用时,要花费大量的存取时间。C语言提供了另一种变量,它存放在cpu的寄存器中,即寄存器变量,它的说明符是register。它与自动变量具有完全相同的性质。当一个变量使用频率较高时可定义为寄存器变量,这样可提高效率。对于循环次数较多的循环控制变量及循环体内反复使用的变量均可定义为寄存器变量。 说明: (1) 只有局部自动变量和形式参数才可以定义为寄存器变量。因为寄存器变量属于动态存储方式。凡需要采用静态存储方式的变量不能定义为寄存器变量。 (2) 即使能真正使用寄存器变量的机器,由于cpu中寄存器的个数是有限的,因此使用寄存器变量的个数也是有限的。 (3) 用auto,register,static声明变量时,是在定义这些变量的基础上加上这些关键字,而不能单独使用。 7.9 外部函数和内部函数 根据在一个源文件内的函数能否被其它源文件调用,将函数分为内部函数和外部函数。 7.9.1 内部函数 如果

温馨提示

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

评论

0/150

提交评论