1. 函数的基本结构和作用

1.1 定义、声明、调用

函数定义包括函数的返回类型、函数名、参数列表和函数体。函数体是执行的代码块。

1.1.1 声明

函数的声明(也称为函数原型)告诉编译器函数的名称、返回类型和参数类型,而不包含函数的具体实现。函数可以在定义前进行声明,以便在定义之前使用函数。

1
return_type function_name(parameter_list);

1.1.2 定义

函数定义包括函数的返回类型、函数名、参数列表和函数体。函数体是执行的代码块。

1
2
3
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
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

void modifyValue(int *x) {
*x = 10; // 通过指针修改实参的值
}

int main() {
int a = 5;
modifyValue(&a); // 传递a的地址
printf("a = %d\n", a); // 输出:a = 10,原值被修改
return 0;
}

2.2.3 数组作为函数参数

在C语言中,数组传递给函数时实际上是按地址传递的。数组名本身是指向数组第一个元素的指针,因此数组传参的效果等同于按地址传递。

3.函数的作用域与生命周期

3.1 局部变量

局部变量是在函数或代码块内部定义的变量。它们的作用域只限于定义它们的函数或代码块。函数执行完毕后,局部变量的内存会被释放。

3.2 全局变量

全局变量是在所有函数之外定义的变量,可以在整个程序中使用。全局变量的生命周期从定义它的那一刻起,直到程序结束。

3.3 静态局部变量

使用static关键字定义的局部变量具有持久性。即使函数结束,静态局部变量的值也会保留到下次函数调用时。

1
static int count = 0;  // 静态局部变量

4.递归函数

递归(Recursion) 是函数调用自身的一种方式。递归调用的特点是函数会在满足特定条件下反复调用自身,直到达到终止条件。

递归函数通常包括以下三个关键要素:

  1. 递归条件:即函数调用自身的条件,解决的问题会递归地被分解成更小的子问题。
  2. 基准条件(结束条件):递归必须有一个终止条件,告诉函数何时不再递归,否则会导致无限递归,进而导致栈溢出。
  3. 递归过程:这是函数的主体逻辑,在递归调用的过程中,问题的规模逐渐变小,直到符合基准条件。

一般结构:

1
2
3
4
5
6
7
8
9
return_type function_name(parameters) {
if (基准条件) {
// 基准情况,递归终止
return 基准值;
} else {
// 递归情况
return function_name(更新后的参数);
}
}

尾递归(Tail Recursion) 是一种特殊的递归形式,即递归调用位于函数的最后一步,并且不包含额外的操作。

5.指针与地址操作

指针:指针是一个存储变量地址的变量,它是C语言中的重要概念。

  • 地址运算符 &:用于获取变量的地址。
  • 间接运算符 *:用于访问指针指向的地址处的值(解引用)。
  • 指针与函数:指针可以作为参数传递给函数,以允许函数修改调用者的变量。

局部变量与全局变量:局部变量存储在栈中,全局变量存储在静态/全局数据区。

类型转换:在C语言中,类型转换可分为隐式和显式两种。显式类型转换使用 () 括号,如 int a = (int)b;