7.2.1 函数的定义
任何函数(包括主函数main())都是由函数说明和函数体两部分组成。根据函数是否需要参数,可将函数分为无参函数和有参函数两种。
-
无参函数的一般形式
函数类型 函数名( )
{ 说明语句部分;
可执行语句部分;
} -
有参函数的一般形式
函数类型 函数名( 数据类型 参数1[,数据类型 参数2…] )
{ 说明语句部分;
可执行语句部分;} -
空函数的定义
既无参数、函数体又为空的函数。其一般形式为:
[函数类型] 函数名()
{ }
说明:
(1)函数类型:用于指定函数带回来的值的类型,可以是任何有效类型。函数类型可以省略,则系统默认为int型,这时函数返回一个整数值。当函数无返回值时函数类型一般应写成void,称为无类型或空类型。
(2)参数表:它是一个用逗号分隔的变量说明表,参数表中的参数称为“形式参数”,简称“形参” 。形参用于主调函数和被调用函数之间进行数据传递,即当函数被调用时,形参接收实参传过来的值。
参数表的定义形式如下:
类型标识符 形式参数1,类型标识符 形式参数2,……
例如:float area(float a,float b,float c)
(3)可以定义空函数,即形式参数和函数体均为空。调用此函数时,不做任何工作,只是表明这里需要调用一个函数。 -
函数返回值与return语句
return语句的一般格式为:
return ( 返回值表达式 );
功能:返回调用函数,并将“返回值表达式”的值带给调用函数。
说明:
(1)一个函数中可以有一个或多个return语句,当执行到某个return语句时,程序的控制流程将返回到主调函数,并将return语句中表达式的值作为函数值带回。
(2)若函数体内没有return语句,则一直执行到函数体末尾的“}”为止,然后返回到主调函数,这时也会有一个不确定的值被带回到主调函数。若不需要带回函数值,一般可将函数定义为void类型。
(3)return语句中表达式的类型应与函数类型一致,若不一致时,以函数类型为准。 -
函数类型
函数类型与return语句返回值的类型一致。
对被调用函数进行说明,其一般格式为:
函数类型 函数名(数据类型[ 参数名1][, 数据类型[ 参数名2]…]);
C语言规定,以下两种情况,可以省去对被调用函数的说明:
(1)当被调用函数的函数定义出现在调用函数之前时。因为在调用之前,编译系统已经知道了被调用函数的函数类型、参数个数、类型和顺序。
(2)如果在所有函数定义之前,在函数外部(例如文件开始处)预先对各个函数进行了说明,则在调用函数中可缺省对被调用函数的说明。
1.函数调用
C语言中函数调用的一般形式为:
函数名([实际参数表])
注意:
实参的个数、类型和顺序,应该与被调用函数所要求的参数个数、类型和顺序一致,才能正确地进行数据传递。
2.函数调用方式
(1)函数表达式。函数作为表达式的一项,出现在表达式中,以函数返回值参与表达式的运算。这种方式要求函数是有返回值的。 例如:c=2*max(a,b);
(2)函数语句。C语言中的函数可以只进行某些操作而不返回函数值,这时的函数调用可作为一条独立的语句。例如:max(a,b);
(3)函数实参。函数作为另一个函数调用的实际参数出现。这种情况是把该函数的返回值作为实参进行传送,因此要求该函数必须是有返回值的。
例如:n=max(a,max(b,c));其中max(b,c)是一次调用,它的值作为max另一次调用的实参。
(4)调用时实参与形参在类型必须匹配。
函数的参数分为形参和实参两种,作用是实现数据传送。形参出现在函数定义中,只能在该函数体内使用。发生函数调用时,调用函数把实参的值复制1份,传送给被调用函数的形参,从而实现调用函数向被调用函数的数据传送。
关于形参与实参的说明:
(1)实参可以是常量、变量、表达式、函数等。无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。
(2)形参变量只有在被调用时,才分配内存单元;调用结束时,即刻释放所分配的内存单元。
(3)实参对形参的数据传送是单向的,即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。
(4)实参和形参占用不同的内存单元,即使同名也互不影响。
7.3.1 函数的嵌套调用
函数的嵌套调用是指,在执行被调用函数时,被调用函数又调用了其他函数。其关系可表示如图所示。
所谓函数的递归调用是指,一个函数在它的函数体内,直接或间接地调用它自身。递归调用分为直接递归调用和间接递归调用两种,如图所示。
7.4.1 数组元素作为函数参数
数组元素就是下标变量,与普通变量并无区别。数组元素只能用作函数实参,其用法与普通变量完全相同。在发生函数调用时,把数组元素的值传送给形参,实现单向值传送。
数组名作函数参数时,既可以作形参,也可以作实参。而且形参和相对应的实参都必须是类型相同的数组(或指向数组的指针变量),都必须有明确的数组说明。
7.5.1 局部变量
在一个函数内部或一个复合语句内定义的变量称为局部变量,它只在本函数范围或该复合语句内有效,即只有在本函数内或本复合语句内才能使用它们,离开该范围是不能使用这些变量的。例如:
int f1(int a) /*函数f1*/
{ int b,c;
…
} /*a,b,c作用域:仅限于函数f1()中*/
int f2(int x) /*函数f2*/
{ int y,z;
…
} /*x,y,z作用域:仅限于函数f2()中*/
main()
{ int m,n;
…
} /*m,n作用域:仅限于函数main()中*/
在函数外部定义的变量,它的作用域是:从定义变量的位置开始,到本文件结束。外部变量可被作用域内的所有函数直接引用。
例如:
int x,y; /* 全局变量*/
float f1(int a)
{… }
float a,b; /* 全局变量*/
int f2(int c)
{ int z;
…
}
main()
{ int m,n;
…
}
C语言对变量的存储类型说明有四种:自动变量(auto)、寄存器变量(register)、外部变量(extern)、静态变量(static)。
7.6.1 静态变量
定义格式: static 数据类型 变量表;
注意:
静态变量属于静态存储。在程序执行过程中,即使所在函数调用结束也不释放。换句话说,在程序执行期间,静态变量始终存在。
定义静态变量但不初始化,则自动赋以"0"(整型和实型)或'\0'(字符型);且每次调用它们所在的函数时,不再重新赋初值,只是保留上次调用结束时的值。
当需要保留函数上一次调用结束时的值或者变量只被引用而不改变其值时,才使用静态变量。
自动变量
定义格式:[auto] 数据类型 变量表;
注意:
自动变量属于动态存储方式。在函数中定义的自动变量,只在该函数内有效;函数被调用时分配存储空间,调用结束就释放。
在复合语句中定义的自动变量,只在该复合语句中有效;退出复合语句后,也不能再使用,否则将引起错误。
定义动态变量而不初始化,则其值是不确定的。如果初始化,则赋初值操作是在调用时进行的,且每次调用都要重新赋一次初值。
由于自动变量的作用域和生存期,都局限于定义它的个体内(函数或复合语句),因此不同的个体中允许使用同名的变量而不会混淆。即使在函数内定义的自动变量,也可与该函数内部的复合语句中定义的自动变量同名。
7.6.3 寄存器变量
一般情况下,变量的值都是存储在内存中的。为提高执行效率,C语言允许将局部变量的值存放到寄存器中,这种变量就称为寄存器变量。其定义格式为:
register 数据类型 变量表;
注意:
只有局部变量才能定义成寄存器变量,即全局变量不行。
允许使用的寄存器数目是有限的,不能定义任意多个寄存器变量。
7.6.4 外部变量
外部变量属于静态存储方式。其定义格式为:
extern 数据类型 外部变量表;