C 函数
C 函数
在 C 语言中,函数(Function) 是组织代码的基本单位。它不仅可以将程序划分为多个逻辑模块,还能提高代码的可读性、复用性和维护性。
掌握好函数的定义与使用,是编写结构清晰、高效稳定程序的关键。
一、学习目标 🎯
- 掌握 C 语言中函数的定义、声明与调用方法。
- 理解函数参数传递机制(值传递)和返回值的使用。
- 能够根据实际需求设计函数,并理解函数调用栈的基本原理。
二、核心重点 🔑
- C 中函数只能返回一个值(可以通过指针或结构体模拟多值返回)。
- 函数调用时参数是“值传递”,不会影响原始变量(除非使用指针)。
- 函数应保持单一职责原则:每个函数只做一件事。
三、详细讲解
✅ 1. 函数的定义与调用
语法:
返回类型 函数名(参数列表) {
// 函数体
return 返回值;
}
示例:定义一个求最大值的函数
#include <stdio.h>
// 函数定义
int max(int a, int b) {
return (a > b) ? a : b;
}
int main(void) {
int x = 10, y = 20;
int result = max(x, y); // 函数调用
printf("较大的数是:%d\n", result);
return 0;
}
⚠️ 注意事项:
- 函数必须先定义或声明,再调用;
- 函数名要具有描述性;
main函数是程序入口,不能被其他函数调用。
✅ 2. 函数的声明(原型)
如果函数定义在调用之后,就需要提前声明其原型。
示例:
#include <stdio.h>
// 函数声明
int add(int a, int b);
int main(void) {
int sum = add(5, 7); // 调用尚未定义的函数
printf("sum = %d\n", sum);
return 0;
}
// 函数定义在后面
int add(int a, int b) {
return a + b;
}
⚠️ 建议:
- 将函数声明放在头文件
.h中,便于模块化开发;
- 使用宏防止重复包含。
✅ 3. 参数传递机制 —— 值传递(Pass by Value)
C 语言中所有参数都是“值传递”——函数接收的是变量的副本。
示例:
#include <stdio.h>
void changeValue(int x) {
x = 100; // 只修改副本
}
int main(void) {
int a = 10;
changeValue(a);
printf("a = %d\n", a); // 输出仍是 10
return 0;
}
⚠️ 注意事项:
- 值传递不会影响原变量;
- 如果想改变原变量,需要使用指针(见下一章《指针》)。
✅ 4. 返回值机制
函数通过 return 语句返回一个值给调用者。
示例:
#include <stdio.h>
int square(int x) {
return x * x;
}
int main(void) {
int result = square(5);
printf("5 的平方是:%d\n", result);
return 0;
}
⚠️ 注意事项:
- 函数可以有多个
return语句;- 不建议返回局部变量的地址(会导致悬空指针);
- 若无返回值,使用
void类型。
✅ 5. 递归函数(Recursion)
函数可以调用自身,这种称为“递归”。
示例:计算阶乘
#include <stdio.h>
int factorial(int n) {
if (n == 0 || n == 1) {
return 1;
}
return n * factorial(n - 1);
}
int main(void) {
int result = factorial(5);
printf("5! = %d\n", result);
return 0;
}
⚠️ 注意事项:
- 必须设置终止条件;
- 递归深度过大可能导致栈溢出;
- 有时可用循环替代递归以提高效率。
✅ 6. 函数调用栈(Call Stack)
当你调用一个函数时,系统会为其分配一块内存空间(称为“栈帧”),用于保存参数、局部变量、返回地址等信息。
调用过程如下:
- 主函数调用子函数;
- 子函数压入调用栈;
- 子函数执行完毕后弹出栈;
- 返回结果给主函数继续执行。
⚠️ 实战建议:
- 避免过深嵌套调用;
- 使用调试器查看调用栈有助于理解程序流程。
四、常见陷阱与避坑指南 ⚠️
| 陷阱 | 描述 | 解决方案 |
|---|---|---|
| ❗未声明就调用函数 | 编译器无法识别 | 提前声明函数原型 |
| ❗函数返回局部变量地址 | 悬空指针 | 使用静态变量或动态内存分配 |
| ❗参数顺序错误 | 导致逻辑错误 | 明确命名参数含义 |
| ❗递归没有退出条件 | 死循环/栈溢出 | 设置明确的递归终止条件 |
五、拓展练习 🧩
🧩 练习题 1:实现一个判断素数的函数
输入一个正整数,判断是否为素数(质数)并返回布尔值。
提示:函数签名可设为 int is_prime(int n),返回 1 表示是素数,0 表示不是。
🧩 练习题 2:封装一个菜单驱动程序
编写一个函数 show_menu() 显示操作选项,并根据用户选择执行不同功能(如加法、减法等)。
要求:
- 使用函数封装各个功能;
- 用户可多次选择操作直到退出。
🧩 练习题 3:实现斐波那契数列函数
写一个函数 fibonacci(int n),返回第 n 项的斐波那契数。
要求:
- 分别用递归和非递归方式实现;
- 比较两者性能差异。
🧩 练习题 4:函数封装排序算法
编写一个函数 sort_array(int arr[], int size),对数组进行升序排序(如冒泡排序)。
要求:
- 函数不返回新数组,直接修改原数组;
- 在
main函数中测试排序效果。
六、实战建议总结
| 场景 | 推荐做法 |
|---|---|
| 功能复用 | 提取为函数,命名清晰 |
| 多个返回值 | 返回结构体或使用指针输出参数 |
| 模块化开发 | 使用 .h 文件声明函数原型 |
| 性能优化 | 合理使用内联函数(inline) |
| 错误处理 | 函数返回状态码或使用全局变量 errno |
恭喜你完成了《C 函数》这一章的学习!
你现在可以熟练地将程序拆分为多个函数,写出结构清晰、易于维护的代码了!
✅ 下一章推荐学习内容(任选其一):
- 《C 数组与字符串基础》
- 《C 指针入门:地址、指针变量、数组访问》
- 《C 结构体与联合体详解》
- 《C 预处理器与宏定义》
你想继续学哪个?我来为你定制下一章 👇

浙公网安备 33010602011771号