C 语言中的函数到底是什么从“重复劳动”到“代码积木”的入门课适合读者已经学过变量、if、for、数组等基础内容准备开始理解函数的 C 语言新手。阅读目标读完这篇文章你应该能明白函数是什么分清函数声明、函数定义、函数调用理解参数、返回值、void和作用域的基本用法。想象你每天都要做一杯奶茶。流程大概是烧水 - 放茶包 - 加牛奶 - 加糖 - 搅拌你当然可以每天重新写一遍这些步骤。问题是写多了人会烦代码也会烦。更好的办法是把这套流程整理好起个名字叫makeMilkTea。以后想喝奶茶时直接调用这个流程。函数就是这么来的。函数就是把一段可以重复使用的代码打包起来起一个名字需要时调用它。目录一、为什么 C 语言需要函数二、函数到底是什么三、函数的基本结构四、声明、定义、调用分别是什么五、参数和返回值有什么用六、形参和实参名字像亲戚其实很好分七、void 是什么意思八、变量作用域和函数九、函数如何让代码更清晰、更容易复用十、完整示例用函数计算两个数的最大值十一、初学者常见错误十二、总结与 5 个要点一、为什么 C 语言需要函数学函数之前先看一个朴素的问题重复代码。假设你要输出接水步骤两次都要写printf(打开水龙头\n);printf(接水\n);printf(关水龙头\n);printf(打开水龙头\n);printf(接水\n);printf(关水龙头\n);这段代码能运行但它有三个问题重复。同样三行写了两遍。难改。如果要把“接水”改成“接一杯水”每个地方都要改。不清晰。代码一多读者会被重复细节淹没。如果用函数可以这样写voidgetWater(void){printf(打开水龙头\n);printf(接水\n);printf(关水龙头\n);}需要接水时调用它getWater();getWater();这样代码就清爽很多。函数的作用不是让程序看起来高级而是把重复劳动收纳起来。程序员喜欢偷懒但这种偷懒叫“抽象”听起来立刻正经了不少。二、函数到底是什么函数可以理解成一个“代码积木”。你把一段代码打包成一个小模块给它起名字。以后哪里需要就把这块积木拿出来用。函数通常解决三类问题问题函数怎么帮忙重复代码太多把重复逻辑打包程序太长不好读把大任务拆成小任务同一功能多处使用写一次多次调用比如计算两个数的和intadd(inta,intb){returnab;}这个函数的意思是给我两个整数我返回它们的和。像不像一个小工具你把材料递进去它把结果递回来。三、函数的基本结构一个函数通常长这样返回值类型 函数名(参数列表){函数体;return返回值;}拿add来看intadd(inta,intb){returnab;}拆开解释部分示例含义返回值类型int函数最后会返回一个整数函数名add调用这个函数时使用的名字参数列表int a, int b调用函数时需要提供两个整数函数体{ ... }函数真正执行的代码returnreturn a b;把结果返回给调用者也可以画成一个小盒子输入参数 a, b ↓ [ add 函数 ] ↓ 返回 a b函数像一个小加工厂参数是原材料函数体是加工流程返回值是成品。四、声明、定义、调用分别是什么这三个词特别容易把新手绕晕。用“开店”来理解会轻松一点。概念小白理解代码例子函数声明先贴个招牌我这里有这个函数int add(int a, int b);函数定义真正把店开起来写清楚怎么干活int add(int a, int b) { return a b; }函数调用顾客来点单让函数执行add(3, 5);1. 函数声明intadd(inta,intb);声明告诉编译器后面会有一个叫add的函数它接收两个int返回一个int。2. 函数定义intadd(inta,intb){returnab;}定义才是真正写函数内容的地方。3. 函数调用intresultadd(3,5);调用就是让函数真正执行。这里add(3, 5)会得到结果8再赋值给result。完整示例#includestdio.hintadd(inta,intb);// 函数声明intmain(void){intresultadd(3,5);// 函数调用printf(%d\n,result);return0;}intadd(inta,intb){// 函数定义returnab;}为什么要声明因为 C 语言编译时通常从上往下看。main先用到了add编译器需要提前知道这个函数确实存在而且应该怎么用。五、参数和返回值有什么用函数如果完全不接收数据也不返回结果就像一个只会喊口号的工具。能用但用途有限。参数和返回值让函数真正灵活起来。1. 参数把数据传进去intadd(inta,intb){returnab;}这里的a和b是参数。调用时可以传不同的值add(1,2);add(10,20);add(100,200);同一个函数因为参数不同可以处理不同数据。2. 返回值把结果带回来intsumadd(3,5);add(3, 5)算出8这个8就是返回值。调用者可以把它保存起来、打印出来或者继续参与计算。调用者给函数3 和 5 函数内部计算3 5 函数返回结果8做奶茶也是一样。参数可以是“甜度、杯数、是否加冰”返回值就是做好的奶茶。只不过 C 语言不会真的给你递奶茶最多给你一个结果。六、形参和实参名字像亲戚其实很好分形参和实参是函数里很常见的一对词。名称出现位置含义形参函数定义里占位用的变量实参函数调用时真正传进去的值看代码intadd(inta,intb){returnab;}intresultadd(3,5);这里a、b是形参3、5是实参。你可以把形参理解成点单表上的空格实参就是你真正填进去的内容。形参甜度、杯数 实参七分糖、2 杯函数被调用时实参的值会传给形参。函数内部用形参做计算。七、void 是什么意思void在函数里常见有两个主要意思。1. 没有返回值voidsayHello(void){printf(Hello!\n);}函数名前面的void表示这个函数不返回结果。它只是做一件事比如输出一句话。调用时这样写sayHello();不能这样写intxsayHello();// 错误sayHello 没有返回值2. 没有参数voidsayHello(void)括号里的void表示这个函数不需要你传任何参数。所以void sayHello(void)可以理解成不需要输入也不返回结果只负责打招呼。如果函数既不需要输入也不需要输出void就会出现两次。看着有点重复其实很诚实。八、变量作用域和函数函数会形成自己的小房间。你在函数里定义的变量通常只能在这个函数里使用。voidtest(void){intx10;printf(%d\n,x);}intmain(void){printf(%d\n,x);// 错误main 里看不到 test 里的 xreturn0;}x是test函数里的局部变量。它住在test的房间里main不能隔墙直接拿。这叫作用域。先记住一句话变量在哪里定义通常就只能在哪里附近使用。函数之间如果要传数据不能靠“偷看别人房间”而要通过参数和返回值。intsquare(intx){returnx*x;}这里main可以把一个数传给squaresquare算完后通过return把结果带回来。这才是函数之间沟通的正规路线。九、函数如何让代码更清晰、更容易复用函数最大的价值不只是“少写几行代码”。它还会让程序结构更清楚。比如一个成绩程序可以拆成输入成绩 - 计算平均分 - 判断是否及格 - 输出结果写成函数后可以变成inputScores();averagecalculateAverage();printResult(average);这三行不一定能直接运行因为它们只是示意把不同任务拆成不同函数。哪怕你还不知道函数内部怎么写也能大概看懂程序在做什么。这就是函数的好处好处说明减少重复同一段逻辑写一次多次调用结构清晰大任务拆成小任务方便修改改函数内部调用处不用全改容易测试可以单独测试某个函数更像人类思考每个函数负责一件事好的函数不一定很长。很多时候一个函数如果能清楚表达一件事就已经很有价值。十、完整示例用函数计算两个数的最大值下面写一个完整、可运行的小程序输入两个整数输出较大的那个。#includestdio.hintgetMax(inta,intb);intmain(void){intx;inty;intmax;printf(请输入两个整数);scanf(%d %d,x,y);maxgetMax(x,y);printf(较大的数是%d\n,max);return0;}intgetMax(inta,intb){if(ab){returna;}else{returnb;}}拆开看intgetMax(inta,intb);这是函数声明提前告诉编译器后面会有一个getMax函数。maxgetMax(x,y);这是函数调用。x和y是实参真正传给函数的数据。intgetMax(inta,intb){if(ab){returna;}else{returnb;}}这是函数定义。a和b是形参函数内部用它们比较大小并通过return返回结果。这个程序虽然简单但函数的几个关键点都出现了声明、定义、调用、参数、返回值。真实项目里通常还会检查scanf是否读取成功。为了让入门示例更清楚这里先保留最简单写法。十一、初学者常见错误错误类型示例问题原因正确理解忘记函数声明main前调用了后面才定义的函数编译器提前不知道函数信息在前面写函数声明返回值类型不匹配int f() { return 3.14; }会发生类型转换可能丢失信息返回类型要和结果匹配void函数还拿来赋值int x sayHello();sayHello不返回结果void函数只执行动作参数个数不对add(1);函数需要两个参数只给了一个调用时参数数量要匹配混淆形参和实参把a、b当成调用时的固定值形参只是占位变量实参才是真正传入的值局部变量跨函数使用在main使用别的函数里的变量超出作用域用参数和返回值传递数据忘记写 returnint f() { }声明返回int却没返回非void函数应返回对应值函数错误多数不是因为“函数很难”而是因为调用、返回、作用域这些边界没分清。十二、总结与 5 个要点函数就是把一段代码打包成一个有名字的小模块。它让我们可以把重复逻辑收起来把复杂任务拆开把代码写得更清楚。如果说变量是一个小盒子数组是一排小盒子那么函数就是一块代码积木。你可以把它拼进程序里也可以在不同地方反复使用。读完这篇文章记住下面五点函数用来打包可复用代码。同一段逻辑写一次需要时调用。函数有结构。返回值类型、函数名、参数列表、函数体、return都各有作用。声明、定义、调用不是一回事。声明是提前打招呼定义是写具体实现调用是让函数执行。参数负责把数据传进去返回值负责把结果带回来。函数有作用域边界。函数里的局部变量外面的函数不能直接使用。先别急着学递归和函数指针。把普通函数写熟理解参数、返回值和作用域后面的复杂内容才不会像从天上掉下来。C 语言中的函数到底是什么从“重复劳动”到“代码积木”的入门课适合读者已经学过变量、if、for、数组等基础内容准备开始理解函数的 C 语言新手。阅读目标读完这篇文章你应该能明白函数是什么分清函数声明、函数定义、函数调用理解参数、返回值、void和作用域的基本用法。想象你每天都要做一杯奶茶。流程大概是烧水 - 放茶包 - 加牛奶 - 加糖 - 搅拌你当然可以每天重新写一遍这些步骤。问题是写多了人会烦代码也会烦。更好的办法是把这套流程整理好起个名字叫makeMilkTea。以后想喝奶茶时直接调用这个流程。函数就是这么来的。函数就是把一段可以重复使用的代码打包起来起一个名字需要时调用它。目录一、为什么 C 语言需要函数二、函数到底是什么三、函数的基本结构四、声明、定义、调用分别是什么五、参数和返回值有什么用六、形参和实参名字像亲戚其实很好分七、void 是什么意思八、变量作用域和函数九、函数如何让代码更清晰、更容易复用十、完整示例用函数计算两个数的最大值十一、初学者常见错误十二、总结与 5 个要点一、为什么 C 语言需要函数学函数之前先看一个朴素的问题重复代码。假设你要输出接水步骤两次都要写printf(打开水龙头\n);printf(接水\n);printf(关水龙头\n);printf(打开水龙头\n);printf(接水\n);printf(关水龙头\n);这段代码能运行但它有三个问题重复。同样三行写了两遍。难改。如果要把“接水”改成“接一杯水”每个地方都要改。不清晰。代码一多读者会被重复细节淹没。如果用函数可以这样写voidgetWater(void){printf(打开水龙头\n);printf(接水\n);printf(关水龙头\n);}需要接水时调用它getWater();getWater();这样代码就清爽很多。函数的作用不是让程序看起来高级而是把重复劳动收纳起来。程序员喜欢偷懒但这种偷懒叫“抽象”听起来立刻正经了不少。二、函数到底是什么函数可以理解成一个“代码积木”。你把一段代码打包成一个小模块给它起名字。以后哪里需要就把这块积木拿出来用。函数通常解决三类问题问题函数怎么帮忙重复代码太多把重复逻辑打包程序太长不好读把大任务拆成小任务同一功能多处使用写一次多次调用比如计算两个数的和intadd(inta,intb){returnab;}这个函数的意思是给我两个整数我返回它们的和。像不像一个小工具你把材料递进去它把结果递回来。三、函数的基本结构一个函数通常长这样返回值类型 函数名(参数列表){函数体;return返回值;}拿add来看intadd(inta,intb){returnab;}拆开解释部分示例含义返回值类型int函数最后会返回一个整数函数名add调用这个函数时使用的名字参数列表int a, int b调用函数时需要提供两个整数函数体{ ... }函数真正执行的代码returnreturn a b;把结果返回给调用者也可以画成一个小盒子输入参数 a, b ↓ [ add 函数 ] ↓ 返回 a b函数像一个小加工厂参数是原材料函数体是加工流程返回值是成品。四、声明、定义、调用分别是什么这三个词特别容易把新手绕晕。用“开店”来理解会轻松一点。概念小白理解代码例子函数声明先贴个招牌我这里有这个函数int add(int a, int b);函数定义真正把店开起来写清楚怎么干活int add(int a, int b) { return a b; }函数调用顾客来点单让函数执行add(3, 5);1. 函数声明intadd(inta,intb);声明告诉编译器后面会有一个叫add的函数它接收两个int返回一个int。2. 函数定义intadd(inta,intb){returnab;}定义才是真正写函数内容的地方。3. 函数调用intresultadd(3,5);调用就是让函数真正执行。这里add(3, 5)会得到结果8再赋值给result。完整示例#includestdio.hintadd(inta,intb);// 函数声明intmain(void){intresultadd(3,5);// 函数调用printf(%d\n,result);return0;}intadd(inta,intb){// 函数定义returnab;}为什么要声明因为 C 语言编译时通常从上往下看。main先用到了add编译器需要提前知道这个函数确实存在而且应该怎么用。五、参数和返回值有什么用函数如果完全不接收数据也不返回结果就像一个只会喊口号的工具。能用但用途有限。参数和返回值让函数真正灵活起来。1. 参数把数据传进去intadd(inta,intb){returnab;}这里的a和b是参数。调用时可以传不同的值add(1,2);add(10,20);add(100,200);同一个函数因为参数不同可以处理不同数据。2. 返回值把结果带回来intsumadd(3,5);add(3, 5)算出8这个8就是返回值。调用者可以把它保存起来、打印出来或者继续参与计算。调用者给函数3 和 5 函数内部计算3 5 函数返回结果8做奶茶也是一样。参数可以是“甜度、杯数、是否加冰”返回值就是做好的奶茶。只不过 C 语言不会真的给你递奶茶最多给你一个结果。六、形参和实参名字像亲戚其实很好分形参和实参是函数里很常见的一对词。名称出现位置含义形参函数定义里占位用的变量实参函数调用时真正传进去的值看代码intadd(inta,intb){returnab;}intresultadd(3,5);这里a、b是形参3、5是实参。你可以把形参理解成点单表上的空格实参就是你真正填进去的内容。形参甜度、杯数 实参七分糖、2 杯函数被调用时实参的值会传给形参。函数内部用形参做计算。七、void 是什么意思void在函数里常见有两个主要意思。1. 没有返回值voidsayHello(void){printf(Hello!\n);}函数名前面的void表示这个函数不返回结果。它只是做一件事比如输出一句话。调用时这样写sayHello();不能这样写intxsayHello();// 错误sayHello 没有返回值2. 没有参数voidsayHello(void)括号里的void表示这个函数不需要你传任何参数。所以void sayHello(void)可以理解成不需要输入也不返回结果只负责打招呼。如果函数既不需要输入也不需要输出void就会出现两次。看着有点重复其实很诚实。八、变量作用域和函数函数会形成自己的小房间。你在函数里定义的变量通常只能在这个函数里使用。voidtest(void){intx10;printf(%d\n,x);}intmain(void){printf(%d\n,x);// 错误main 里看不到 test 里的 xreturn0;}x是test函数里的局部变量。它住在test的房间里main不能隔墙直接拿。这叫作用域。先记住一句话变量在哪里定义通常就只能在哪里附近使用。函数之间如果要传数据不能靠“偷看别人房间”而要通过参数和返回值。intsquare(intx){returnx*x;}这里main可以把一个数传给squaresquare算完后通过return把结果带回来。这才是函数之间沟通的正规路线。九、函数如何让代码更清晰、更容易复用函数最大的价值不只是“少写几行代码”。它还会让程序结构更清楚。比如一个成绩程序可以拆成输入成绩 - 计算平均分 - 判断是否及格 - 输出结果写成函数后可以变成inputScores();averagecalculateAverage();printResult(average);这三行不一定能直接运行因为它们只是示意把不同任务拆成不同函数。哪怕你还不知道函数内部怎么写也能大概看懂程序在做什么。这就是函数的好处好处说明减少重复同一段逻辑写一次多次调用结构清晰大任务拆成小任务方便修改改函数内部调用处不用全改容易测试可以单独测试某个函数更像人类思考每个函数负责一件事好的函数不一定很长。很多时候一个函数如果能清楚表达一件事就已经很有价值。十、完整示例用函数计算两个数的最大值下面写一个完整、可运行的小程序输入两个整数输出较大的那个。#includestdio.hintgetMax(inta,intb);intmain(void){intx;inty;intmax;printf(请输入两个整数);scanf(%d %d,x,y);maxgetMax(x,y);printf(较大的数是%d\n,max);return0;}intgetMax(inta,intb){if(ab){returna;}else{returnb;}}拆开看intgetMax(inta,intb);这是函数声明提前告诉编译器后面会有一个getMax函数。maxgetMax(x,y);这是函数调用。x和y是实参真正传给函数的数据。intgetMax(inta,intb){if(ab){returna;}else{returnb;}}这是函数定义。a和b是形参函数内部用它们比较大小并通过return返回结果。这个程序虽然简单但函数的几个关键点都出现了声明、定义、调用、参数、返回值。真实项目里通常还会检查scanf是否读取成功。为了让入门示例更清楚这里先保留最简单写法。十一、初学者常见错误错误类型示例问题原因正确理解忘记函数声明main前调用了后面才定义的函数编译器提前不知道函数信息在前面写函数声明返回值类型不匹配int f() { return 3.14; }会发生类型转换可能丢失信息返回类型要和结果匹配void函数还拿来赋值int x sayHello();sayHello不返回结果void函数只执行动作参数个数不对add(1);函数需要两个参数只给了一个调用时参数数量要匹配混淆形参和实参把a、b当成调用时的固定值形参只是占位变量实参才是真正传入的值局部变量跨函数使用在main使用别的函数里的变量超出作用域用参数和返回值传递数据忘记写 returnint f() { }声明返回int却没返回非void函数应返回对应值函数错误多数不是因为“函数很难”而是因为调用、返回、作用域这些边界没分清。十二、总结与 5 个要点函数就是把一段代码打包成一个有名字的小模块。它让我们可以把重复逻辑收起来把复杂任务拆开把代码写得更清楚。如果说变量是一个小盒子数组是一排小盒子那么函数就是一块代码积木。你可以把它拼进程序里也可以在不同地方反复使用。读完这篇文章记住下面五点函数用来打包可复用代码。同一段逻辑写一次需要时调用。函数有结构。返回值类型、函数名、参数列表、函数体、return都各有作用。声明、定义、调用不是一回事。声明是提前打招呼定义是写具体实现调用是让函数执行。参数负责把数据传进去返回值负责把结果带回来。函数有作用域边界。函数里的局部变量外面的函数不能直接使用。先别急着学递归和函数指针。把普通函数写熟理解参数、返回值和作用域后面的复杂内容才不会像从天上掉下来。