07 · 函数与作用域
函数的三个部分
int add(int a, int b); // 1. 声明(原型):告诉编译器长啥样
int main(void) {
int s = add(3, 5); // 2. 调用
return 0;
}
int add(int a, int b) { // 3. 定义:具体实现
return a + b;
}
- 声明必须在调用之前出现(否则编译器不知道函数存在)。
- 声明通常放进
.h头文件供多文件共享(见 16-预处理器与头文件)。
⭐ C 的参数传递:一律「值传递」(理解指针的钥匙)
void badSwap(int a, int b) { // ❌ 只改了副本,外面没变
int t = a; a = b; b = t;
}
void goodSwap(int *a, int *b) { // ✅ 传地址,改的是原变量
int t = *a; *a = *b; *b = t;
}
int x = 1, y = 2;
badSwap(x, y); // x=1, y=2 没变
goodSwap(&x, &y); // x=2, y=1 成功
这是 C 最重要的一条规则:函数里想改外部变量,只能传指针。Java 里「对象传引用」的直觉在 C 里不成立。
没有函数重载
C 不支持同名不同参,同一作用域函数名必须唯一。
int add(int a, int b);
double add(double a, double b); // ❌ 编译错误:函数名重复
作用域规则
| 种类 | 范围 |
|---|---|
| 局部变量 | 函数/代码块内 |
| 全局变量 | 整个文件,所有函数可见 |
| 形式参数 | 函数内部,是实参的副本 |
| 静态局部 | 函数内可见,但活得和程序一样久 |
- 局部变量会遮蔽(shadow)同名的全局变量。
- 全局变量尽量少用,多个函数乱改会让 bug 难查。
递归(见 18-递归与可变参数)
函数可以调用自己,必须有终止条件,否则栈溢出。
关联
08-数组 · 09-指针 · 18-递归与可变参数 · 04-常量与存储类