函数的定义、函数参数、函数声明
一 、课前知识提前学习
1、函数的定义
在比较大的程序中,通常包含比较复杂的逻辑和功能,这些功能包含若干子功能,子功能可能分解出更小的子功能。这些功能组合在一起,形成完整的程序。因此,一个模块化程序通常根据实际需要可分为若干个子程序模块,每个子程序模块实现一个特定的基本功能。
例如为了实现实数的四则运算,从功能上将其分解为如下四个模块:
图1 四则运算功能分解
可以有多种实现方式,例如以C语言为开发语言,由多人完成,每个模块放在一个.c文件中。当所有的函数分别调试通过后,可以将上述函数的定义合并到一个.c文件,经编译链接成一个完整的可执行程序.exe。
函数的出现实现了数据和指令的封装,函数相当一个“黑盒”,除了其形式参数和返回值外,主调函数无法直接访问被调函数内部的数据和指令。
函数是C语言的构建模块,每个函数本质上是一个自带声明和语句的小程序。函数可以实现代码复用,一个函数最初可能是某个大程序中的一部分(例如加法处理),但可以用于其它程序,或者将程序中公用部分提炼出来作为一个公用模块(例如输出)供其它模块使用。利用函数可以实现程序的模块化,无论C程序的设计规模有多大、多复杂,都可以将其划分为若干个相对独立、功能较单一的函数,通过对这些函数的调用,实现程序功能
2、函数的参数
C语言提供了三种传递方式:
(1)返回值传递:函数调用结束时return语句从函数内部带值返回;
(2)参数传递:函数调用时主调函数从外部传递数据给被调函数;
(3)全局变量传递:定义公共访问区的全局变量方式。
形式参数和实际参数
参数传递指通过函数参数将主调函数的数值(实际参数)传递到被调函数(形式参数)的过程。形式参数出现在函数定义中,在整个函数体内部都有效;实际参数出现在主调函数中,用于将实际处理数据传递给被调函数的形参,实现主调函数向被调函数传递数据的功能。
形参列表的一般格式:数据类型1 形式参数名1, ..., 数据类型n 形式参数名n
例如:
int func(int m, floati)
{ ... ...
}
每个形式参数必须指定数据类型,可以为基本数据类型也可以为用户自定义数据类型;函数参数数量根据函数的功能定义进行声明,多个形式参数定义之间要用逗号隔开。函数也可以没有参数,说明此参数不需要接收信息。例如:
void SayHello( void)/*或 void SayHello( )*/
{ printf(“Hello”);
}
只有当调用发生时,系统才给形式参数分配内存空间,并在函数调用结束后,释放形参所占用的存储空间。
由于形式参数属于函数内部的变量,因此函数的形参名不能和当前函数内的变量名相同。
实参列表的格式为:实参1,实参2,...,表达式n
例如:
power(2,1)
实际参数可以是常量、变量或表达式,但必须有确定的值。多个实参之间用逗号分隔。
函数调用过程中,实际参数和形式参数之间存在数据传递的关系,形式参数和实际参数在类型、个数及顺序上必须保持一致,否则会发生“类型不匹配”错误。
参数传递的方式
(1)值拷贝传递机制
值拷贝传递的特点是:形参和实参各自占用不同的存储空间,在函数内部对形参的任何操作,其结果只能影响形参本身,而不会影响到实参。这种方式只能实现外部数据向函数内部的传递,不能实现函数内部数据向外传递。
(2)地址拷贝传递机制
地址拷贝传递机制是将主调函数中某一数据存储区的地址通过函数参数传递给被调函数,主调函数和主调函数可以共同访问一段数据区。
只传递数据的地址信息,适合对大量数据信息的操作。
3、函数的定义
库函数声明
调用一个函数,首先该函数必须已经存在(定义)。其次遵循先声明后使用的原则对其进行函数声明。函数声明的目的是通知编译器,当前函数已经存在并可以使用。在源程序编译阶段,编译器并不检查已经声明函数的函数体,在链接阶段才检查此函数是否存在。
调用标准库函数时,需要在当前源文件的头部添加标准库函数所在的头文件。
预定义形式:#include "头文件名称"或#include <头文件名称>
用户自定义函数声明
调用用户自定义函数时,函数声明一般出现在其函数定义的前面,声明的基本原则是“谁使用,谁声明”。函数声明在于确认传递给函数的参数类型、数目以及函数返回值的类型。
声明格式: 返回值类型符 函数名称(形式参数列表);
例如:
void add(int a,intb); /*该声明语句写在main()函数内*/
在一个小程序的开发过程中,一般将所有函数的声明放在源程序的开始位置,其特点是:当前文件从声明位置到文件结束的任何函数中都可以调用该函数,而与函数定义的位置无关。此种声明方式为全局声明。例如:
#include<stdio.h>
int power(int m,int n);
void Myfun1( );
main( )
{ ……
}
void Myfun1( )
{ ……
}
int power(int m,int n)
{ ……
}
当开发大的应用程序时,一般将所有公用函数的声明保存在相应的头文件(.h)中,然后通过#include 指令将函数声明包含到当前文件中。
函数声明和函数定义完全不同。函数定义包括函数头和函数体,完整的定义了函数的输入、输出和具体实现;函数声明则是为编译的需要,只要理解了编译的特点,就比较容易理解声明的必要性和声明的有效范围。