C语言程序设计(第二版)学习笔记——第七章

第七章 函数

C 语言程序的基本组成单位是函数。

利用 C 语言中的函数来实现这些功能模块,整个程序由多个函数和一个主函数组成,函数之间通过调用,执行各个函数的代码,从而实现整个程序的整体功能。

7.1 函数的概念

一个稍复杂一些的 C 程序通常由一个主函数和多个子函数组成,每个函数完成某种操作或运算功能。函数之间通过调用,执行各个函数中的程序。

main ()函数是程序执行的开始点,子函数中的代码只有被调用时才会执行。

一般由 main ()函数调用其他子函数,子函数还可以调用其他子函数,但是子函数不能调用 main ()函数。

调用其他函数的函数,称为主调函数,被调用的函数称为被调函数。

C 函数分为标准库函数和用户自定义函数两种。

7.1.1 标准库函数

标准库函数是 C 系统定义好的函数,存放在标准函数库中,可以供用户直接使用。

使用库函数时,要用预编译命令# include ,将有关的头文件包含到用户的源程序文件中,头文件中包含了与所调用的库函数相关的信息。

1.输入输出函数

输入输出函数: printf ()、 scanf ()、 putchar ()和 getchar ()等。

调用输入输出库函数时,需要包含的头文件为 stdio . h ,即应在源程序文件中使用编译预处理命令# include < stdio . h >,将该头文件包含进来。

2.数学函数

调用数学函数时,要包含头文件 math . h ,即使用编译预处理命令# include < math . h >.

常用的数学库函数如下。

abs ( int x ):功能为求整数 x 的绝对值。

fabs ( double x ):功能为求实数 x 的绝对值。

sqrt ( double x ):功能为求 x 的平方根(要求 x ≥0)。

pow ( double x , double y ):功能为求 x 。

sin ( double x ):功能为计算 x 的正弦值,要求角度 x 以弧度表示。

cos ( double x ):功能为计算 x 的余弦值,要求角度 x 以弧度表示。

3.字符和字符串处理函数

调用字符串处理函数时,要包含头文件 string . h ;而调用字符处理函数时,要包含头文件 ctype . h 。

常用的字符串函数如下。

strcpy (x1,x2):功能为将字符串x2复制到x1中。

strlen ( x ):功能为统计字符串 x 中字符的个数(不包括\0)。

strcat (x1,x2):功能为将字符串x2连接到x1的后边,结果在x1中。

stromp :比较两个字符串的大小

4.动态存储分配函数

调用动态存储分配函数时,要包含头文件 stdlib . h 。

常用的函数如下。

calloc ( n , size ):功能是分配 n 个 size 大小的内存连续空间。

malloc ():功能是分配 size 字节的存储区。

free ():功能是释放动态分配的内存区。

7.1.2 用户自定义函数

用户自定义函数是用户为解决自己的专门问题而编写的。在程序开发中,常将一些经常用到的功能模块编写成函数,或放在公共函数库中供大家使用,从而尽量减少重复书写相同的程序段。

7.2 函数的定义

函数定义的一般格式如下:

类型名函数名(形参列表) /*函数的头部*/
{  定义变量
   语句序列
}/*函数体*/

说明如下:

(1)格式中第一行为函数的首部,其中函数名由用户自己定义,要符合 C 标识符的命名规则。

(2)形式参数(简称形参),是函数被调用时用来接受传来的实际参数的。形参列表中的每个形参都要声明其类型。

(3)根据是否有形参,可以将函数分为有参函数和无参函数。有参函数的形参可以有一个或多个。若有两个以上的形参,则各参数之间要以逗号分隔。若没有形参,则称该函数为无参函数。

(4)函数头部下边的()部分,称为函数体,是函数要执行的程序,用于实现函数的功能。

(5)函数名前面的类型名是指函数值的数据类型。函数值的类型名若省略,则默认函数值为int型。

(6)函数的返回值。函数一般有返回值。函数返回值由return语句得到,并传递给主调函数。

返回语句的格式为:

return(表达式);
或
return 表达式;

return后面的值可以是常量、变量,有没有括号都可。

return后面的值也可以是个表达式。

函数首部的类型定义与 return 后边表达式的类型要一致。

当函数的返回值与定义的函数值类型不一致时,就以函数值类型为准,对数值型数据可以自动进行类型转换。

如果函数不带回值,只完成某种操作,则函数结尾可以用不带表达式的 return 语句。或省略 return 语句。

7.3 函数的调用

7.3.1 调用函数

调用函数的一般格式:

函数名(实参列表)

说明如下:

(1)当调用无形参函数时,不应有实参。

(2)若有多个实参,要用逗号分隔。且实参要与形参类型匹配,一一对应。

(3)实参可以是常量、变量或表达式。

一般函数的调用有以下几种方式。

(1)函数语句。如 pstar ();,这种方式适用于无返回值( void )函数的调用。

(2)函数表达式。如 v = funv ( a , b , c )*10+2;,这种方式适用于有返回值的函数调用。

(3)函数值作为参数。如 printf (" V =8d\ n ", funv (1,3,9));/*运行结果输出 V =27*/该语句执行结果是输出函数值 funv (1,3,9)。这种方式适用于有函数返回值的调用。

7.3.2 声明函数

在 C 语言中,变量需要先声明后使用,与此相似,如果要调用自定义的函数,一般也要在主调函数中先对被调函数进行声明,然后调用该函数。

在声明函数时也可以不写形参变量名,只写形参类型。例如: float funv ( float , float , float );称为函数原型。

如果自定义函数放在主调函数之前,则在主调函数之中可以省略函数声明语句。也可以在所有函数之前声明函数原型,则在主调函数中就不必再声明函数。

7.4 函数的参数

传递定义函数时所带的参数称为形式参数(简称形参),调用函数时所带的参数称为实队参数(简称实参)。当调用函数时,实参的值要传递给对应的形参,传递方向是单向的。只能是实参向形参传递。

实参与形参的传递方式有两种:传值方式和传地址方式。

7.4.1 传值方式

传值方式有以下特点:

(1)实参和形参各占有不同的存储单元。所以在被调函数中若改变了形参的值,并不会影响实参的值。实参与形参允许同名,不会混淆。

(2)实参的值传递给形参,称为值传递,且是单向传递,即只能由实参传值给形参。

(3)形参和实参数目要相同、类型要匹配。

(4)实参的求值顺序是自右到左。

由于形参变量与实参变量各有自己的存储单元,故形参值的交换不会影响到实参的值,

7.4.2 传地址方式

传地址方式是指实参传递给形参的是变量的地址,即指针。

由于数组名代表数组的首地址,所以这里以数组为例,介绍传地址方式的参数传递的特点。调用函数时,若以数组名作为函数的实参,则要求形参也应是数组名(或指针变量)。由于传递的是数组的首地址,则实参和形参都是实参数组的首地址,即实参和形参指同一个数组。因此在函数中若改变了形参数组的值,实际上也等于改变了实参数组的值。

将数组名作为参数时,实参数组与形参数组类型要一致。

多维数组作为函数参数,形参数组定义时第一维下标可以省略。

7.5 函数的嵌套调用与递归调用

7.5.1 函数的嵌套调用

函数的嵌套调用,即在被调用的函数中又调用其他函数。

在 C 语言中,函数的定义是平行的、独立的,即一个函数内部不能包含另一个函数的定义。所以函数的定义不允许嵌套定义,但函数的调用是允许嵌套的。

7.5.2 函数的递归调用

1.函数递归调用的概念

当一个函数在执行的过程中,出现直接或间接调用该函数本身,称为函数的递归调用。

在函数中直接调用该函数本身的形式,称为直接递归调用。直

如果是通过调用另外一个函数来调用本函数,则称为间接递归调用。

递归过程分为回推和递推两个阶段。

函数的递归调用可以理解为嵌套调用的特殊形式,只不过是函数自己调用自己。在理解函数递归调用时,可以认为,每当递归调用一次函数本身,就相当于产生了该函数的一个副本,直到最后一次递归调用结束,程序的流程返回二次函数调用点处,依次类推,直到返回到最初一次的函数调用点处。

2.递归调用的条件

定义递归函数时,应考虑以下条件。

(1)必须有完成函数任务的语句。

(2)有一个测试条件,决定是否继续递归调用。

(3)每次递归调用函数的实参应逐渐逼近测试条件,才能最终结束递归调用。

(4)在递归函数定义中,要先测试条件,后递归调用。即递归是有条件的,只有在一定条件下才可以递归调用。

7.6 变量的作用域

C 程序是由 main ()函数和若干函数组成的,在不同的地方定义的变量,其作用域(有效范围)是不同的。从变量作用域的角度看,可将变量分为局部变量和全局变量。

7.6.1 局部变量

在函数内部定义的变量,称为局部变量。以前介绍过的各种类型的变量大多是在函数内定义的变量,所以都是局部变量。

局部变量的有效范围(作用域)只在本函数内。在某复合语句的()内定义的局部变量,只在本{ }内有效。离开有效范围,变量的值将丢失。所以不同的函数,可以有同名的局部变量,它们各有自己的作用域,互不干扰。

局部变量的生存期,也就是变量的存在时间,是指变量被分配存储单元开始到变量的存储单元被释放,即变量消失这段时间。

只有当程序执行函数时,才给函数内的局部变量分配存储单元,当执行完函数体代码,离开本函数时,这些局部变量所占的存储单元就被释放,即变量不存在了。

函数的形参也属于局部变量。当程序调用函数时,才给函数的形参分配存储单元,程序执行完函数体代码离开本函数时,形参变量因存储单元被释放,而使形参的值丢失。

7.6.2 全局变量

在函数之外定义的变量称为全局变量。全局变量可以为各函数所共用。全局变量的作用域是从定义的位置开始,到本文件的结束。

可见因为形参和实参都是局部变量,作用域仅限于各自的函数体,即使形参和实参同名,二者也互不干扰。所以形参的交换,并没有影响实参。

在 C 语言中,可以通过 return 语句,将被调函数的值,带回主调函数,但只能返回一个值,而通过定义全局变量的方法,可以在函数之间传递多个值。

 C 语言规定如果在同一程序中,全局变量与局部变量同名,则在二者的作用域重叠的区间,局部变量有效,全局变量不起作用。

全局变量在整个程序的执行过程中,都占用存储单元,其中的值不丢失。利用全局变量可以实现各函数之间的参数传递。

除非十分必要,一般不提倡使用全局变量,其原因有以下几点:

(1)由于全局变量属于程序中的所有函数,因此在程序执行过程中,一直占用存储空间,即使正在执行的函数根本不用这些全局变量,全局变量也要占用存储空间。

(2)在某函数中若用到了全局变量,则所有调用该函数的主调函数都要使用这些全局变量,从而降低了函数的通用性。

(3)函数中使用了全局变量,各函数之间的相互影响较大,从而使函数的独立性变差。如果在某函数中改变了全局变量,则所有使用该全局变量的函数都会受到影响。

(4)在函数中使用了全局变量后,会降低程序的清晰性,使程序的可读性变差。

7.7变量的存储属性

7.7.1 变量的存储类型

一般来说,计算机内存中供用户使用的存储空间分为程序区、静态存储区和动态存储区三部分。其中程序区是用来存放程序的,静态存储区和动态存储区是用来存放数据的。

静态存储区是在程序开始执行时就分配的固定存储空间,存放在该区域的变量称为静态存储变量。如全局变量就存放在静态存储区,在程序开始执行时,系统就为全局变量分配存储空间,程序结束时才释放变量。

动态存储区是在程序运行期间,根据需要动态分配和释放的存储空间。该区域一般存放函数的形参变量、局部的自动变量、函数调用时的现场保护和返回地址等。

变量从作用域的角度可分为局部变量和全局变量;从存在的时间角度分为动态存储变量和静态存储变量。

静态存储变量,在整个程序执行过程中,始终占据固定的存储单元,其值一直不丢失,直到程序结束,才释放变量。

动态存储变量,只有在要使用时才被分配存储单元,程序执行离开其有效范围时就释放存储单元,变量的值也就丢失了。

在 C 语言中,变量和函数有以下两个基本属性。

(1)数据类型:如整型、实型和字符型等。

(2)存储类型:分为自动变量( auto )、静态变量( static )、寄存器变量( register )和外部变量( extern )。

7.7.2 动态变量

动态变量,也称自动变量,属于动态存储变量,可关键字 auto 声明动态变量。

对于局部变量,若不加以任何说明,默认是动态变量。

动态变量的赋初值是在调用函数时进行的,在函数执行结束时,释放其存储单元,变量的数据丢失。再次调用函数时,又重新为动态变量赋初值,若没有为动态变量赋初值,则动态变量的初值是随机的。

7.7.3 局部静态变量

静态变量属于静态存储变量,可用关键字 static 声明局部静态变量。

局部静态变量赋初值是在编译时进行的,若没有为静态变量赋初值的语句,则自动初始化为0。

静态变量的值在函数调用结束时仍保留,下次再调用该函数时,静态变量的值是上次调用结束时的值,而不再重新赋初值。

7.7.4 外部变量

用 extern 声明的变量,称为外部变量。

利用外部变量可以扩展全局变量的作用域。

外部变量有以下用途。

(1)在同一文件中,全局变量若在文件的开始处定义,则在整个文件范围内的函数都可以使用该变量。但若不是在文件的开头定义的全局变量,则只有该变量定义点之后的函数可以直接使用。若在全局变量的定义点之前的函数要使用该变量,则要先用 extern 声明外部变量。

(2)一个 C 程序可以由一个或多个源程序文件组成。对于多文件的 C 程序,若一个文件中的程序,要使用另外一个文件中的全局变量,就要用 extern 声明外部变量,这样就可将全局变量的作用域扩展到其他文件。

7.7.5 静态外部变量

用 static 声明的全局变量,称为静态外部变量。这种变量只能被本文件中的函数使用。其他文件即使用 extern 声明该变量也无法使用该变量。

  • 26
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值