linux C 函数
1.1 概述
函数的定义:为了使程序大而不繁,简单明了,程序设计者要根据软件的总体要求,把相同功能或相似功能的操作归纳成模块的形式,并实现程序设计的模块化。
面对一项复杂任务,通常采取模块化的解决方法(首先,将该复杂任务分解成几个大的功能模块,根据需要还可以继续细分,直到分解成一个个功能独立的模块为止)如图1所示。
图1
1.2 函数定义与声明
1.2.1函数的定义如下。
调用函数必须遵循“定义在先,使用在后”的原则。
函数定义的一般格式:
类型说明符 函数名 (类型说明符 形参变量1,类型说明符 形参变量2,...)
{
声明语句部分;
执行语句部分;
}
如图2所示。
图2
关于return语句说明如下。
return语句是函数的逻辑结尾,不一定是函数的最后一条语句,一个函数中允许出现多条return语句,但每次只能有一条return语句被执行,
如果不需要从被调函数带回返回值,可以不要return语句,一般情况下,将函数类型定义为void型,也叫空类型,此种类型的函数用来完成某种操作,例如输出程序运行结果等。
还可以用不带表达式的return作为函数和逻辑结尾,这时,return的作用是将控制权交给调用函数,而不是返回一个值。
1.2.2函数的声明
(1)标准库函数的说明。如被调用函数为C语言系统提供的标准库函数,可在程序的开头部分用#include进行文件包含,printf()和sqrt()等函数就是属于这种形式。
(2)自定义函数的说明。如果是用户自定义函数,如函数与主调用函数在同一程序文件中,在调用前用如下语句进行说明:
类型说明符 函数名 (类型说明符 形参变量1,类型说明符 形参变量2,...);
函数声明按其位置不同,作用范围也不同。
(1)在所有函数外部进行说明。在函数外部进行说明的函数,说明语句之后的所有函数中都可对其进行调用。通常把函数说明语句放在程序文件的头部,以方便其后的程序对其进行调用。
(2)在函数内部进行说明。在某一函数内说明的函数,仅可在说明它的函数内部被调用。
1.3函数的参数与返回值
1.3.1函数的参数
函数的参数分为形参和实参两种,作用是实现数据的传送。有参函数在调用时,主调函数和被调函数之间有数据传递,主调函数传递数据给被调函数。主调函数传递来的数据称为实际参数,简称实参。
定义函数时,函数名后的参数称为形式参数,简称形参。
在定义函数时,系统并不给形参分配存储单元,当然形参也没有具体的数值,所以称它是形参,也叫作虚参。
形参和实参之间的关系如下:
(1)
实参的个数、类型应该和形参的个数和类型一致。调用函数时,系统给形象分配存储单元,并且把实参的数值传递给形参。
(2)参数和形参分别属于主调函数和被调函数,具有不同的内存单元。所以,在函数调用时形参发生改变,不会影响到实参。
(3)C语言中实参和形参的结合采取的是“单向值传递”方式,只有实参传递参数给形参,形参不回传参数给实参。
如图3所示。
图3
程序说明:
程序从主函数开始执行,首先输入a,b的数值(假如输入5,6)接下来调用函数add(a,b)。具体调用过程如下。
1.给形参x,y分配内空间。
2.将实参b的值传递给形参y,a的值传递给x,于是y的值为5,x的值为3.
3.执行函数体。
(1)给函数体内的变量分配存储空间。即给z分配存储空间。
(2)执行算法实现部分,得到z的值11.
(3)执行return语句,完成以下功能。将返回值返回主调函数,即将z的值返回给main()。释放函数调用过程中分配的所有内存空间,即释放x,y,z的内存空间。结束函数调用,将流程控制权交给主调函数。当调用函数结束后继续执行main()函数直至结束。
函数调用前后实参、形参的变化情况如图4所示。
图4
1.3.2 函数的返回值
在函数定义时需要描述函数类型,但没有给出函数如何得到返回值。调用有值函数时,要求被调函数返回数据给主调函数,返回的数据称为函数返回值,简称函数值。得到的函数返回值的方法是使用return语句。
return语句使用的一般形式为:
return(表达式)
return语句应书写在函数体的算法实现部分,圆括号可以省略。
通常return语句完成以下功能:返回一个值给主函数;释放在函数的执行过程中分配的所有内存空间;结束被调函数的运行,将流程控制权交给主调函数。
注意
若调用函数中无return语句,并不是不返回一个值,而是一个不确定的值。为了明确表示不返回值,可以用“void”定义成“无(空)类型”。
1.4 函数的调用
1.4.1 函数的一般调用形式
1.函数的声明
对外调用函数的声明具体形式为:函数类型 函数名();
main函数是主函数,它可以调用其他函数,而不允许被其他函数调用。
2.函数的调用
C语言中,函数调用的一般形式为:函数名 (【实际参数列表】)
实际参数列表是函数入口参数的实际值。
示例如图5所示。
图5
在C语言中,可以用以下几种方式调用函数
1.函数表达式。函数作为表达式的一项,出现在表达式中,以函数返回值与表达式的运算。这种方式要求函数是有返回值的。
c=add(a+b);
2.函数语句。C语言中的函数可以只进行某些操作而不返回函数值,这时的函数调用可作为一条独立的语句。
function();
3.函数实参。函数作为另一个函数调用的实际参数出现。这种情况是把该函数的返回值作为实参进行传送,因此要求该函数必须是有返回值的。
d=add(a,add(b,c));
C函数调用过程如图6所示。
图6
1.4.2 函数的嵌套调用
嵌套调用值得是在函数中调用过程中又出现了另外一种函数调用,称为函数的嵌套调用。
函数的嵌套调用指的更多的是指函数的连环调用。
函数嵌套调用层次越多,时间开销越大(即运行时间长,占用内存空间多)。
1.4.3 函数的递归调用
函数的递归调用是函数嵌套调用的特殊形式。一个函数在它的函数体内直接或间接的调用自己的函数称为函数的递归调用。在递归调用中,主函数又是被调函数。执行递归函数调用的函数将反复调用其自身,每调用一次就进入新的一层。
运用递归函数时会发现逻辑“相似性”
运用递归函数时会不要忘记递归出口
1.5 变量的作用范围与存储过程
在C语言中按照变量的作用范围可以将变量分为局部变量和全局变量两种。
1.5.1 局部变量
不管是主函数还是其他函数,在函数内声明的变量(包括函数参数)统称为局部变量。
例如:如图7所示。
图7
关于局部变量的作用域还要说明以下几点:
(1)主函数main()中定义的局部变量,也只能在主函数中使用,其他函数不能使用。同时,主函数中也不能使用其他函数中定义的局部变量。因为主函数也是一个函数,与其他函数是平行关系。这一点是与其他语言不同的,应予以注意。
(2)形参变量也是局部变量,属于被调函数;实参变量,则是调用函数的局部变量。
(3)允许在不同的函数中使用相同的变量名,他们代表不同的对象,分配不同的单元,互不干扰,也不会混淆。
(4)在复合语句中也可定义局部变量,其作用域只在复合语句范围内。
1.5.2 全局变量
函数外定义的变量称为全局变量。全局变量可以被定为它的文件中的所有函数使用。
全局变量的作用范围是从定义变量的位置开始到它所在源文件结束的位置。
示例:如图8所示。
图8
全局变量说明的一般形式:
extern 数据类型 全局变量 [,全局变量2... ];
外部变量使用关键字 “ertern”定义,在函数体之外定义,存放在静态存储区。
全局变量的优点:
(1)增加了各函数间的数据传送的渠道。
(2)利用全局变量可以减少函数实参与形参的个数。
全局变量的缺点:
(1)全局变量作用范围大,为此必然要付出的代价是其占用存储单位时间长。
(2)函数过多使用全局变量,降低了函数使用的通用性。
(3)多人合作完成的程序通常由多个源文件组成。
(4)使用全局变量过多,会降低程度的清晰度,使人难以判断某一时刻各个全局变量的值,因为各个函数在执行时都可以改变全局变量的值。
1.5.3 变量的存储类别
完整的变量定义应该与稳定它的两种属性:存储类型和数据类型。
变量定义的完整形式为:[ 存储类型 ] 类型说明符 变量名表列;
变量存储类型:
(1)自动型存储类型
存储类型符: auto
具有动态性、随函数调用而生成、局部变量默认。
动态变量的定义格式:auto 数据类型 变量名; /* 关键字auto可缺省*/
例:定义a,b,c为整型自动存储类别变量:
auto int a,b,c;
(2)寄存器存储类型
存储类型符: register
要大量重复使用、提高执行效率、仅局限于定义它的函数。
寄存器变量定义格式:register 数据类型 变量名;
关键字register表示变量是寄存器存储类型。
示例:如图9所示。
图9
(3)外部存储类型
存储类型符: extern
多个程序文件间进行变量的引用时,就需要将变量说明为外部变量。
关键字 extern 表示变量是外部存储类型,定义格式为:exten 数据类型 变量名;
(4)静态存储类型
存储类型符: static
固定的内存单元、程序运行结束才释放。
关键字static表示变量是静态存储类型。
注意
局部变量默认为auto型;
register型变量个数受限,且不能为long,double,float型;
局部static变量具有全局寿命和局部可见性;
局部static变量具有可继承性;
extern不是变量定义,可扩展外部变量作用域。