C语言08-函数
1. 函数的基本结构和作用
1.1 定义、声明、调用
函数定义包括函数的返回类型、函数名、参数列表和函数体。函数体是执行的代码块。
1.1.1 声明
函数的声明(也称为函数原型)告诉编译器函数的名称、返回类型和参数类型,而不包含函数的具体实现。函数可以在定义前进行声明,以便在定义之前使用函数。
1 | return_type function_name(parameter_list); |
1.1.2 定义
函数定义包括函数的返回类型、函数名、参数列表和函数体。函数体是执行的代码块。
1 | return_type function_name(parameter_list) { |
1.1.3 调用
函数定义好后,可以通过函数名和参数列表来调用它。在调用时,参数的顺序和类型必须匹配。例如:
1 | int result = add(5, 3); |
2. 函数参数
2.1 形参和实参
函数的参数允许在调用时传递数据,函数根据传递的数据执行不同的逻辑。
- 形式参数:函数定义中使用的占位符,如 ch 和 num。
- 实际参数:函数调用时传入的真实值。
2.2 函数的参数传递方式
2.2.1 按值传递
按值传递是C语言中最常见的传参方式。函数在调用时,会将实际参数的值拷贝一份传递给函数的形参(函数内部的参数)。在函数内部,对形参的任何操作都不会影响实际参数,因为它们是两个独立的内存空间。
特点:
- 函数接收到的是实际参数的副本。
- 在函数内部对参数的修改不会影响实际参数。参数不需要在函数内进行修改,或者即使修改也不会影响外部的实际变量。
- 适合传递简单类型(如整数、浮点数等),因为拷贝这些值的开销较低。参数是简单数据类型(如int、float、char等)。
2.2.2 按指针(地址)传递
按地址传递(通常通过指针实现)是C语言中的另一种传参方式。实际参数的地址(内存位置)被传递给函数,因此函数可以通过这个地址访问和修改实际参数的值。
特点:
- 适合传递大对象(如数组、结构体等),因为传递地址的开销比复制整个对象的开销要小得多。
- 函数接收的是实际参数的内存地址。
- 在函数内部通过访问地址可以修改实际参数的值,函数对形参的修改会直接影响到外部的实际参数。
- 常用于需要在函数内修改外部变量值的情况。
示例:
1 |
|
2.2.3 数组作为函数参数
在C语言中,数组传递给函数时实际上是按地址传递的。数组名本身是指向数组第一个元素的指针,因此数组传参的效果等同于按地址传递。
3.函数的作用域与生命周期
3.1 局部变量
局部变量是在函数或代码块内部定义的变量。它们的作用域只限于定义它们的函数或代码块。函数执行完毕后,局部变量的内存会被释放。
3.2 全局变量
全局变量是在所有函数之外定义的变量,可以在整个程序中使用。全局变量的生命周期从定义它的那一刻起,直到程序结束。
3.3 静态局部变量
使用static关键字定义的局部变量具有持久性。即使函数结束,静态局部变量的值也会保留到下次函数调用时。
1 | static int count = 0; // 静态局部变量 |
4.递归函数
递归(Recursion) 是函数调用自身的一种方式。递归调用的特点是函数会在满足特定条件下反复调用自身,直到达到终止条件。
递归函数通常包括以下三个关键要素:
- 递归条件:即函数调用自身的条件,解决的问题会递归地被分解成更小的子问题。
- 基准条件(结束条件):递归必须有一个终止条件,告诉函数何时不再递归,否则会导致无限递归,进而导致栈溢出。
- 递归过程:这是函数的主体逻辑,在递归调用的过程中,问题的规模逐渐变小,直到符合基准条件。
一般结构:
1 | return_type function_name(parameters) { |
尾递归(Tail Recursion) 是一种特殊的递归形式,即递归调用位于函数的最后一步,并且不包含额外的操作。
5.指针与地址操作
指针:指针是一个存储变量地址的变量,它是C语言中的重要概念。
- 地址运算符 &:用于获取变量的地址。
- 间接运算符 *:用于访问指针指向的地址处的值(解引用)。
- 指针与函数:指针可以作为参数传递给函数,以允许函数修改调用者的变量。
局部变量与全局变量:局部变量存储在栈中,全局变量存储在静态/全局数据区。
类型转换:在C语言中,类型转换可分为隐式和显式两种。显式类型转换使用 ()
括号,如 int a = (int)b;
。