1. 函数初探:为什么需要函数?
各位同学,咱们今天聊聊C语言里一个绕不开的话题——函数。
说实话,我刚开始学C的时候,对函数这玩意儿挺不屑的。心想:我写个main函数不就完了吗?干嘛还要拆成那么多小函数?多麻烦啊。
直到有一次,我在一个嵌入式项目里写了800多行的main函数……嗯,那感觉,就像把整个衣柜的衣服全塞进一个行李箱。找bug找到怀疑人生。
从那以后,我彻底服了。函数不是麻烦,是救星。
1.1 为什么需要函数?
你想想看,写代码跟盖房子是一个道理。你不会把地基、墙壁、屋顶全混在一起浇筑吧?肯定是一块一块来。
函数的作用,说白了就是模块化。把一个大问题拆成若干个小问题,每个小问题用一个函数搞定。
函数的核心价值:
- 代码复用——同一段逻辑,写一次,调N次
- 逻辑清晰——主函数像目录,子函数像章节
- 便于调试——哪个函数出问题,就盯着哪个查
- 团队协作——你写你的函数,我写我的,互不干扰
我在项目中遇到过最典型的例子:一个温度采集模块,需要做滤波、转换、报警判断。如果全塞在main里,代码又臭又长。拆成 filter()、convert()、alarm_check() 三个函数,清爽得像刚整理过的桌面。
1.2 函数的定义与调用
函数的定义,就是告诉编译器:嘿,我这里有一块功能代码,你记好了,以后我喊名字你就跑。
基本语法长这样:
返回值类型 函数名(参数列表) {
// 函数体
return 返回值;
}
举个例子,写一个计算两个整数最大值的函数:
int max(int a, int b) {
if (a > b) {
return a;
} else {
return b;
}
}
调用就更简单了:
int result = max(10, 20); // result 就是 20
小提示:函数名最好见名知意。我见过有人给函数起名叫 f1()、f2()……三个月后他自己都看不懂了。命名别偷懒,后面省大事。
1.3 第一个完整的函数示例
咱们写一个完整的程序,感受一下函数的魅力。
#include <stdio.h>
// 函数声明:告诉编译器有这个函数
void print_hello(void);
// 主函数
int main() {
printf("程序开始运行...\n");
// 调用函数
print_hello();
printf("程序结束。\n");
return 0;
}
// 函数定义:具体实现
void print_hello(void) {
printf("你好,函数世界!\n");
}
运行结果:
程序开始运行...
你好,函数世界!
程序结束。
你看,main函数像指挥官,print_hello 像士兵。指挥官一声令下,士兵就去干活。干完活回来,指挥官继续往下走。
注意:函数要么先声明再定义,要么把定义放在调用之前。否则编译器不认识它,会报错。我曾经因为这个被编译器骂了半小时……
1.4 函数调用的底层逻辑(简单理解)
为什么会这样?函数调用时,CPU到底干了啥?
我画了一张图,帮你理解这个过程:
这张图展示了函数调用的核心流程:跳转出去,执行完再跳回来。就像你去图书馆借书——你从座位(main)走到书架(函数),拿到书再回到座位继续看。
1.5 函数分类速览
C语言的函数,大致分这么几类:
| 分类 | 说明 | 例子 |
|---|---|---|
| 库函数 | 编译器自带的,直接调用 | printf()、scanf() |
| 用户自定义函数 | 你自己写的 | max()、print_hello() |
| 有参函数 | 调用时传数据进去 | max(10, 20) |
| 无参函数 | 不需要传数据 | print_hello() |
| 有返回值函数 | 执行完返回一个结果 | int max(...) |
| 无返回值函数 | 只干活,不返回结果 | void print_hello() |
核心要点总结:
- 函数是C语言的基本组成单元
- 定义函数要写清楚:返回值类型、函数名、参数、函数体
- 调用函数就是喊它的名字,带上需要的参数
- 函数可以嵌套调用,但别搞太深,小心栈溢出
好了,这一章就到这里。函数这东西,你越用越觉得它香。刚开始写代码时,别怕多写几个函数。等你回头再看,你会感谢那个愿意拆函数的自己。
我的一个小习惯:每个函数只做一件事。如果一个函数干了三件事,那就拆成三个。这个原则叫"单一职责",后面讲模块化的时候还会细聊。