函数详解:代码复用的艺术
从重复代码到优雅函数
什么是函数?
又要学数学了吗?
关系可大了!
编程中的函数 和 数学中的函数:
- ✅ 名字一样
- ❌ 实现不同
- ❌ 用途不同
但核心思想类似: 输入 → 处理 → 输出
为什么需要函数?
问题:代码重复
场景: 计算某年某月某日是星期几
版本1.0: 计算一个日期
int year = 2025;
int month = 6;
int day = 3;
// 一堆计算代码(假设有10行)
int result = /* 复杂计算 */;
// result = 0 表明星期六
// result = 1 表明星期天
// result = 2-6 表明星期一到星期五
版本2.0: 计算两个日期
// 第一个日期
int year1 = 2025;
int month1 = 6;
int day1 = 3;
int result1 = /* 复杂计算 */; // 重复代码!
// 第二个日期
int year2 = 2024;
int month2 = 12;
int day2 = 25;
int result2 = /* 复杂计算 */; // 又重复了!
问题严重性
如果项目中有100个地方需要这个功能:
- 写100遍一样代码?
- 代码量暴增
- 修改一处,要改100处
- 容易出错
必须有更好的办法!
函数:代码复用的解决方案
✨ 优雅版本
定义函数:
int GetWeekDay(int year, int month, int day) {
// 复杂计算逻辑
int result = /* 计算 */;
return result;
}
使用函数:
// 计算第一个日期
int result1 = GetWeekDay(2025, 6, 3);
// 计算第二个日期
int result2 = GetWeekDay(2024, 12, 25);
// 计算第三个、第四个...
int result3 = GetWeekDay(2023, 1, 1);
函数的好处
代码复用
↓
减少重复
↓
易于维护
↓
提高效率
函数的定义
四个部分
返回类型 函数名(参数列表) {
// 函数体(实现)
return 返回值;
}
示例:
int Add(int a, int b) {
int sum = a + b;
return sum;
}
四部分详解
|
部分 |
说明 |
示例 |
|
返回类型 |
函数返回什么类型的值 |
int |
|
函数名 |
给函数起的名字 |
Add |
|
参数列表 |
函数需要什么输入 |
int a, int b |
|
函数体 |
函数的具体实现 |
{ … } |
类比:函数 = 机器
洗衣机的例子
洗衣机 = 函数
┌─────────────────────────┐
│ 洗衣机(函数) │
├─────────────────────────┤
│ │
│ 放入: │
│ ├─ 衣服(参数1) │
│ └─ 洗衣液(参数2) │
│ │
│ 内部处理: │
│ └─ 洗涤、漂洗、脱水 │
│ │
│ 取出: │
│ └─ 干净的衣服(返回值)│
│ │
└─────────────────────────┘
对应到代码
衣服类型 洗衣机(衣服类型 脏衣服, 清洁剂类型 洗衣液) {
// 内部处理
衣服类型 干净衣服 = 洗涤过程(脏衣服, 洗衣液);
return 干净衣服;
}
⚠️ 参数类型要匹配
错误示例:
// 洗衣机要求:衣服 + 洗衣液
洗衣机(室友, 点燃的鞭炮); // ❌ 类型不对!
正确示例:
洗衣机(脏衣服, 洗衣液); // ✅ 类型匹配
函数的完整示例
求星期几的函数
#include <stdio.h>
// 函数定义
int GetWeekDay(int year, int month, int day) {
// 蔡勒公式(简化版)
int result;
if (month < 3) {
month += 12;
year -= 1;
}
int c = year / 100;
int y = year % 100;
result = (c / 4 - 2 * c + y + y / 4 +
26 * (month + 1) / 10 + day - 1) % 7;
if (result < 0) {
result += 7;
}
return result;
}
int main() {
int weekday;
// 函数调用
weekday = GetWeekDay(2025, 6, 3);
printf("2025年6月3日是星期 %d
", weekday);
weekday = GetWeekDay(2024, 12, 25);
printf("2024年12月25日是星期 %d
", weekday);
return 0;
}
函数的调用
调用语法
返回值 = 函数名(参数1, 参数2, ...);
示例
// 定义函数
int Add(int a, int b) {
return a + b;
}
int main() {
int result;
// 调用函数
result = Add(3, 5);
printf("结果:%d
", result); // 输出:8
return 0;
}
调用过程
1. 程序执行到 Add(3, 5)
↓
2. 跳转到 Add 函数
↓
3. a = 3, b = 5
↓
4. 执行函数体
↓
5. return 8
↓
6. 回到调用处,result = 8
主函数 main
特殊的函数
int main() {
// 程序从这里开始
return 0;
}
main 函数特点:
|
特点 |
说明 |
|
唯一性 |
每个程序有且只有一个 |
|
固定名称 |
必须叫 main |
|
程序入口 |
程序从这里开始执行 |
|
操作系统调用 |
不是你调用,是系统调用 |
为什么叫 main?
main = 主要的、主函数
↓
程序的主入口
↓
就像房子的大门
参数详解
参数名可以不同
常见疑惑:
“调用时的变量名和参数名必须一样吗?”
答案: 不需要!
int Add(int a, int b) { // 参数名:a, b
return a + b;
}
int main() {
int x = 3;
int y = 5;
int result = Add(x, y); // 变量名:x, y
// 参数名和变量名不同,没问题!
return 0;
}
参数名随意起
int Add(int num1, int num2) { // 叫 num1, num2
return num1 + num2;
}
int main() {
int apple = 3;
int banana = 5;
int result = Add(apple, banana); // 传水果名也行
return 0;
}
重点:类型匹配
只要类型对上就行:
int Add(int a, int b); // 期望两个 int
// ✅ 正确
Add(10, 20);
Add(x, y);
Add(apple, banana);
// ❌ 错误
Add(3.14, 2.5); // double 类型不匹配
返回值详解
return 关键字
作用:
- 结束函数执行
- 返回指定的值
单一返回
int GetMax(int a, int b) {
if (a > b) {
return a;
} else {
return b;
}
}
多个返回点
int CheckAge(int age) {
if (age < 0) {
return -1; // 错误码
}
if (age < 18) {
return 0; // 未成年
}
return 1; // 成年
}
⚠️ return 后的代码不执行
int Test() {
printf("执行这句
");
return 10;
printf("不会执行
"); // 永远不会执行
}
void 函数
不返回值的函数
语法:
void 函数名(参数列表) {
// 函数体
}
示例
void PrintHello() {
printf("Hello World
");
// 不需要 return
}
void PrintLine(int n) {
int i;
for (i = 0; i < n; i++) {
printf("-");
}
printf("
");
}
int main() {
PrintHello(); // 输出:Hello World
PrintLine(10); // 输出:----------
return 0;
}
void 函数的 return
可以用 return 提前退出:
void CheckNumber(int n) {
if (n < 0) {
printf("错误:负数
");
return; // 提前退出
}
printf("数字是:%d
", n);
}
值传递
重大致念
C语言中,参数传递是值传递(拷贝)
void ChangeValue(int x) {
x = 100; // 只改变副本
}
int main() {
int num = 10;
ChangeValue(num);
printf("%d
", num); // 输出:10(没变)
return 0;
}
传递过程
main中:
num = 10
↓ 调用 ChangeValue(num)
↓
函数中:
创建副本 x = 10
↓
修改副本 x = 100
↓
函数结束,副本销毁
↓
main中:
num = 10(原件未变)
类比:银行复印件
你去银行办业务
↓
提交身份证复印件(副本)
↓
银行对复印件做标记
↓
你的原件身份证不受影响
函数内部对参数的修改,不影响原变量!
综合示例
矩形面积函数
#include <stdio.h>
// 计算矩形面积
double GetRectArea(double width, double height) {
double area = width * height;
return area;
}
// 打印矩形信息
void PrintRectInfo(double width, double height) {
double area = GetRectArea(width, height);
printf("宽:%.2lf
", width);
printf("高:%.2lf
", height);
printf("面积:%.2lf
", area);
}
int main() {
double w = 5.0;
double h = 3.0;
// 方式1:获取面积
double area = GetRectArea(w, h);
printf("面积:%.2lf
", area);
printf("
");
// 方式2:打印信息
PrintRectInfo(w, h);
return 0;
}
输出:
面积:15.00
宽:5.00
高:3.00
面积:15.00
判断质数函数
#include <stdio.h>
// 判断是否为质数
int IsPrime(int n) {
int i;
if (n < 2) {
return 0; // 不是质数
}
for (i = 2; i * i <= n; i++) {
if (n % i == 0) {
return 0; // 不是质数
}
}
return 1; // 是质数
}
int main() {
int num;
printf("请输入一个数:
");
scanf("%d", &num);
if (IsPrime(num)) {
printf("%d 是质数
", num);
} else {
printf("%d 不是质数
", num);
}
return 0;
}
函数的优势
✨ 五大好处
- 代码复用
- 写一次,用多次
- 减少代码量
- 易于维护
- 修改一处,全部生效
- 降低出错概率
- 逻辑独立
- 每个函数负责一件事
- 代码更清晰
- 提高可读性
- 函数名表达意图
- 代码更易懂
- 便于测试
- 单独测试每个函数
- 更容易找bug
对比
没有函数:
// 1000行代码全在 main 里
int main() {
// 计算1
// 计算2
// 计算3
// ...
// 乱成一团
}
有函数:
int Calculate1() { ... }
int Calculate2() { ... }
int Calculate3() { ... }
int main() {
int r1 = Calculate1();
int r2 = Calculate2();
int r3 = Calculate3();
// 清晰明了
}
本文要点回顾
- ✨ 函数作用:代码复用、逻辑独立
- ✨ 函数定义:返回类型 + 函数名 + 参数 + 实现
- ✨ 函数调用:函数名(参数)
- ✨ main函数:程序入口,有且只有一个
- ✨ 参数名:可以和调用时的变量名不同
- ✨ return:返回值并结束函数
- ✨ void函数:不返回值
- ✨ 值传递:传递的是副本,不影响原变量
记忆口诀
函数封装一段码,复用方便又可靠。
返回类型名参数,花括号里写实现。
调用传参是副本,原件不变要记牢。
实战练习
练习1:求最大值
任务: 写一个函数,返回两个数中较大的
点击查看答案
cpp #include <stdio.h> int GetMax(int a, int b) { if (a > b) { return a; } else { return b; } } int main() { int x = 10; int y = 20; int max = GetMax(x, y); printf(“最大值:%d
“, max); return 0; }
练习2:求三个数的最大值
任务: 写一个函数,返回三个数中最大的
点击查看答案
cpp #include <stdio.h> int GetMax3(int a, int b, int c) { int max = a; if (b > max) { max = b; } if (c > max) { max = c; } return max; } int main() { int result = GetMax3(10, 25, 15); printf(“最大值:%d
“, result); return 0; }
练习3:打印分隔线
任务: 写一个void函数,打印n个’-‘
点击查看答案
cpp #include <stdio.h> void PrintLine(int n) { int i; for (i = 0; i < n; i++) { printf(“-“); } printf(”
“); } int main() { printf(“标题
“); PrintLine(20); printf(“内容
“); return 0; }
输出:
标题 ——————– 内容
练习4:阶乘函数
任务: 写一个函数计算n的阶乘
点击查看答案
cpp #include <stdio.h> long long Factorial(int n) { long long result = 1; int i; for (i = 1; i <= n; i++) { result *= i; } return result; } int main() { int n; printf(“请输入n:
“); scanf(“%d”, &n); long long result = Factorial(n); printf(“%d! = %lld
“, n, result); return 0; }
练习5:验证值传递
任务: 写一个函数,尝试修改参数,观察原变量是否改变
点击查看答案
cpp #include <stdio.h> void TryChange(int x) { printf(“函数内修改前:x = %d
“, x); x = 999; printf(“函数内修改后:x = %d
“, x); } int main() { int num = 10; printf(“调用前:num = %d
“, num); TryChange(num); printf(“调用后:num = %d
“, num); return 0; }
输出:
调用前:num = 10 函数内修改前:x = 10 函数内修改后:x = 999 调用后:num = 10
结论: 原变量未改变!
互动时间
思考题:
- 一个函数可以调用另一个函数吗?
- 函数可以调用自己吗?(提示:递归)
- 如果要在函数内修改原变量,该怎么办?(提示:指针)
如果本文对你有协助,欢迎:
- 点赞支持
- 关注不迷路
- 评论区分享你的函数设计
- ⭐ 收藏慢慢看
—-本文为”C++ 大白话”系列第 11 篇