目录
记得刚写代码时总爱把所有逻辑堆在main函数里,就像把做饭、洗碗、拖地全塞给一个人干 —— 代码乱成 “一锅粥” 不说,改个功能得从头翻到尾。这时候函数就得登场了,它给我的感觉就像送外卖的“众包大神”,专门接手各种不同的单子和任务。

一、函数是啥?就是代码界的 “外卖小哥”
简单说,函数就是 “专门干一件事的代码块”。就像外卖小哥:你下单(调用函数),他专门负责把餐送到你手上(执行特定功能),完事就走人(返回结果)。
看个最简单的例子:
// 定义一个专门做加法的函数(就像专门送奶茶的小哥)
int Add(int x, int y) {
return x + y; // 接到两个单子,加起来送回去
}
int main() {
int a = 0, b = 0;
scanf("%d%d", &a, &b);
int c = Add(a, b); // 调用Add函数,把a和b“下单”过去
printf("%d\n", c);
return 0;
}
以前你可能直接写c = a + b,但用了函数就不一样了:以后不管在哪需要加法,直接喊Add就行,不用每次都写一遍计算过程。这就像你想喝奶茶,自己动手做可能很费劲,直接点外卖就行 —— 省时省力还不容易错!
1. 补充一些知识:
二、函数的 “三要素”:返回类型 + 函数名 + 参数列表
函数也有 “身份证”,三要素一个都不能少:
- 返回类型:函数执行完给你啥 “结果”(比如
int表示返回整数,void表示啥也不返回) - 函数名:给函数起个名(就像外卖平台的 “奶茶店名字”)
- 参数列表:你要传给函数的 “材料”(比如
Add函数需要两个整数x和y)函数使⽤的过程中,把函数的参数分为,实参和形参
举个 “啥也不返回” 的例子:
// void表示:我只干活,不给结果(就像清洁工,干完就走)
void print_hehe() {
printf("hehe\n"); // 专门负责打印hehe
}
int main() {
print_hehe(); // 喊它一声,它就打印hehe
print_hehe(); // 再喊一声,再打一次
return 0;
}
运行结果会打印两次hehe,感觉用上了函数让代码逻辑更加清楚有条理。是不是比写两次printf清爽多了?这就是函数的第一个好处:代码复用,少写重复劳动!
三、形参和实参:别搞混的 “双胞胎”
调用函数时,你会遇到两个概念:形参和实参,比如Add(a, b)里,a和b是实参,Add函数里的x和y是形参。
简单说:
- 实参:你实际传给函数的 “原材料”,比如
a和b,是真实存在的变量。 - 形参:函数用来接原材料的 “容器”,比如
x和y,只有函数被调用时才会临时创建,用完就销毁。
重点:形参是实参的 “临时拷贝”,就像你把奶茶配方(实参)抄给朋友(形参),朋友改他的抄本,不会影响你的原配方。比如你在Add里改x的值,a的值不会变:
int Add(int x, int y) {
x = x + 1; // 改x的值
return x + y;
}
int main() {
int a = 3, b = 5;
int sum = Add(a, b); // 这里x变成4,a还是3
printf("a=%d, sum=%d\n", a, sum); // 输出a=3, sum=9
return 0;
}
四、函数的 “潜规则”:这些坑千万别踩
函数虽然好用,但规矩不少,踩坑了能让你怀疑人生。咱们一个个说:
1. 返回值会 “自动变形”?小心被坑!
函数的返回值会自动转换成 “返回类型”,但这可能帮倒忙:
int test() {
return 3.14; // 函数说返回int,你给个小数?
}
int main() {
int r = test();
printf("%d\n", r); // 猜猜输出啥?
return 0;
}
答案是3。因为int类型只能存整数,小数部分会被直接砍掉(不是四舍五入)。
2. 分支语句必须 “雨露均沾”,别厚此薄彼
如果函数里有if分支,一定要保证每种情况都有返回值,不然编译器会给你 “使绊子”:
int is_odd(int n) {
if (n % 2 == 1) {
return 1; // 奇数返回1
}
// 这里漏了else!偶数咋办?
}
这种情况下,要是传入偶数,函数就不知道该返回啥了,可能会返回一个随机数(就像外卖小哥说不好意思你的筷子丢了一样*-*)。正确写法应该是:
int is_odd(int n) {
if (n % 2 == 1) {
return 1;
} else {
return 0; // 偶数也有返回值,完美!
}
}
3. 数组传参:表面兄弟,实则 “地址传递”
数组传参时,函数里的数组名其实是个 “骗子”—— 它看起来是数组,实际是数组首元素的地址。不信看代码:
void set_arr(int arr[10], int sz) { // 这里的[10]只是个摆设,没用!
for (int i = 0; i < sz; i++) {
arr[i] = -1; // 能修改原数组,因为传的是地址
}
}
int main() {
int arr[10] = {0};
int sz = sizeof(arr) / sizeof(arr[0]); // 必须在外面算数组长度!
set_arr(arr, sz); // 传数组名和长度
return 0;
}
为啥要单独传sz?在上一讲中有详细说到。因为在函数里用sizeof(arr)算出来的不是数组长度(而是地址的大小),这就像你给朋友寄一箱苹果,他只收到了快递单(地址),不知道箱子里有几个苹果,所以你得提前告诉他数量,避免被别人偷吃了。
4.return 语句:函数的 “下班信号”
return语句就像函数的 “下班铃”,一旦执行,函数就立马结束,后面的代码再写也没用。比如:
int Add(int x, int y) {
return x + y; // 执行完这句,函数直接下班
printf("这句代码永远不会执行!"); // 白写了
}
五、函数的 “高级玩法”:嵌套调用和链式调用
学会了基础,咱们来玩点高级的!函数可不是孤立的,它们能互相 “合作”,效率直接翻倍。就像好几个外卖小哥一起出动的时候也会相互帮忙一样,让效率最高。
1. 嵌套调用:函数里再喊其他函数,分工明确
就像你点外卖时,奶茶店(函数1)喊快递小哥(函数2)来取餐 —— 函数也能在内部调用其他函数.
那让我们一起算算某一年的某一月有多少天:
// 判断闰年的函数(专门干这一件事)
int is_leap_year(int y) {
return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0);
}
// 计算某个月有多少天(需要用到闰年判断)
int get_days(int y, int m) {
int days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
int day = days[m];
// 如果是闰年且是2月,多一天
if (is_leap_year(y) && m == 2) {
day++;
}
return day;
}
int main() {
int year, month;
scanf("%d %d", &year, &month);
printf("%d天\n", get_days(year, month)); // 调用get_days,它又调用is_leap_year
return 0;
}
这种分工就像工厂流水线:is_leap_year专门查闰年,get_days专门算天数,各司其职,代码逻辑清晰得一批!
2. 链式调用:函数的返回值直接当另一个函数的参数
更牛的操作来了:函数的返回值可以直接 “传给” 另一个函数,就像接力赛一样:
#include <string.h>
int main() {
// 正常写法:先算长度,再打印
int len = strlen("abcdef");
printf("%d\n", len);
// 链式调用:一步到位!
printf("%d\n", strlen("abcdef"));
return 0;
}
strlen函数返回字符串长度,这个结果直接被printf当成参数,少写一行代码。
六、函数声明和定义:别让编译器 “迷路”
编译器读代码是 “从上到下” 的,如果函数定义在调用后面,编译器会 “不认识” 这个函数,比如:
#include <stdio.h>
int main() {
int sum = Add(3, 5); // 编译器:Add是谁?没见过!
printf("%d\n", sum);
return 0;
}
// 函数定义在调用后面
int Add(int x, int y) {
return x + y;
}
这时候就得用 “函数声明”—— 提前告诉编译器 “有这么个函数”,就像提前跟朋友说 “我明天要带个蛋糕来”,朋友就不会惊讶了。
函数声明的写法很简单:把函数定义的 “头” 抄下来,加个分号就行:
#include <stdio.h>
// 函数声明:提前告诉编译器有Add这个函数
int Add(int x, int y); // 参数名可省,写成int Add(int, int);也可以
int main() {
int sum = Add(3, 5); // 编译器:哦,Add是之前说的那个函数!
printf("%d\n", sum);
return 0;
}
// 函数定义
int Add(int x, int y) {
return x + y;
}
七、多文件写法:企业级规范
在公司写代码,不会把所有代码放一个文件里,而是分文件管理:
- 头文件(.h):放函数声明、头文件包含,比如
add.h。 - 源文件(.c):放函数定义,比如
add.c写Add的实现,main.c写主函数。
举个例子:
add.h(头文件):// 函数声明 int Add(int x, int y);add.c(源文件,写函数实现):#include "add.h" // 包含头文件 // 函数定义 int Add(int x, int y) { return x + y; }main.c(源文件,写主函数):#include <stdio.h> #include "add.h" // 包含头文件,才能用Add int main() { int sum = Add(3, 5); printf("%d\n", sum); return 0; }这样分工清晰,多人协作时不会互相干扰 —— 你改
add.c的实现,我改main.c的逻辑,互不影响。
八、总结:函数是代码的 “万能工具”
看到这里,你应该明白函数的好处了吧:
- 省时间:写一次能用 N 次,不用重复写代码。
- 好理解:按功能拆分代码,就像文章分段落,一眼能看懂。
- 易维护:改功能只改对应函数,不用动整个代码。
- 能协作:多文件管理,多人一起写代码不混乱。
其实函数不难, 一开始觉得难,多写几个例子就熟了。下次写代码时,别再把所有逻辑堆在main里,试着拆成一个个小函数,你会发现代码突然变清爽了!
好了,今天的函数教学就到这,赶紧去写个自定义函数试试吧~
转载自CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/hy20060720/article/details/152457897



