C语言的函数
C函数是一系列语句的集合。我们可以说C程序就是函数的集合。
我们可以把代码划分到不同的函数中。模块化代码是结构化程序设计的基本特点。
- 函数声明 declaration 告诉编译器函数名称、返回类型和参数类型。
- 函数定义 definition 提供了函数实际主体。
函数还有很多叫法,如方法、子过程、子程序等等。
函数定义
定义C函数的语法如下:
return_type function_name( parameter list ){
/* body of the function */
}
在 C 语言中,函数由一个函数头和一个函数体组成:
返回类型:一个函数可以返回一个值。return_type 是函数返回值的数据类型。有些函数只执行所需的操作而不返回值,在这种情况下,return_type 是关键字
void
。函数名称:函数的实际名称。函数名本质上是一个内存地址,标识函数在内存中的位置。
形式参数:函数形式参数就像是占位符。当函数被调用时,向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。函数参数是可选的,函数可能不包含任何参数,这种情况下,函数参数可以是关键字
void
。函数主体:函数主体包含一组定义函数执行任务的语句。
函数调用
调用一个已经定义好的参数,直接使用函数名 + 实际参数即可。
...
function_name( arguments ); /* 调用函数 */
...
函数类型就是函数返回值的类型。
函数声明与函数定义
函数声明会告诉编译器函数名称及如何调用函数。函数主体可以单独定义。
函数声明的语法:
return_type function_name( parameter list );
可以看到,函数声明其实就是函数头。函数声明并不产生实际的机器代码,只是告诉编译器如何调用该函数。
使编译器可以在实际调用该函数时正确分配栈空间。所以,函数声明中的形参列表可以只带类型,不带参数名,但是我们一般都会带上参数名。
C函数必须先声明后调用。所以我们一般将函数声明放入头文件中,在需要使用此函数时将相应的头文件包含进来。
C函数不允许嵌套定义。我们可以在一个函数体中声明函数,但不能定义函数。
形式参数与实际参数
我们把函数定义中参数列表(圆括号内)中出现的变量称为形式参数,把函数调用中与形式参数对应的值称为实际参数。
传值调用
在C语言中,被调函数不能直接修改主调函数中变量的值,而只能修改其私有的临时副本的值,这是C函数调用的重要特征:传值调用(Call by values)。
如果想让被调函数能够修改主调函数中的变量,调用者需要向被调用函数提供待设置值的变量的地址(传递指针),被调用函数则需要将对应的形式参数声明为指针类型,通过指针间接访问变量。注意,即使是传递指针,也不违反传值调用的特征,其本质是将一个地址值赋给了形参指针变量。
如果传递数组变量,等同于传递数组首地址的指针,C并不会拷贝整个数组(出于性能考量)。C语言中数组与指针之间有着千丝万缕的联系。
内联函数
C99 引入一个新关键字inline
,用于定义内联函数(inline function)。inline
关键字告诉编译器:这个函数的调用要尽可能快,可以当普通的函数调用实现,也可以用内联展开的办法实现。
对比宏定义,内联函数的优势在于:编译器会在编译时刻检查函数参数类型的匹配。
但是,到底做不做内联展开,取决于编译器…宏定义倒是一定会展开的。