函数从入门到进阶
很多初学C语言的朋友,学到 函数 这一章都会卡壳:
看不懂形参实参、不知道返回值怎么用、分不清全局/局部变量、写代码只会堆main函数、代码杂乱冗余还容易报错。
今天这篇博客,不堆砌概念,全程纯干货+可直接运行的实战代码,从零带你吃透C语言函数,学完直接上手写模块化代码。
一、先搞懂:到底什么是函数?
1. 通俗理解
函数就是封装好的一段可重复使用的代码块。
类比生活:洗衣机就是一个“函数”。
- 输入:衣服、洗衣液(参数)
- 内部执行:进水、洗涤、脱水(函数内部逻辑)
- 输出:干净的衣服(返回值)
写代码时,把重复用到的功能(求和、判断奇偶、排序、计算最值)封装成函数,不用每次重复写代码,大幅精简代码、减少bug。
2. C语言函数两大核心优势
- 代码复用:写一次,随处调用,不用重复造轮子
- 模块化编程:功能拆分清晰,代码易读、易改、易排查错误
二、C语言函数完整语法(必背)
1. 标准函数格式
返回值类型 函数名(形参列表)
{// 函数主体:实现具体功能return返回值;// 和返回值类型对应}2. 各部分详解(新手最易混淆点)
- 返回值类型:函数执行完返回的数据类型(int、float、void、char)
- 函数名:自定义命名,遵循标识符规则(字母/数字/下划线,不能数字开头)
- 形参列表:函数接收的参数,相当于“变量占位符”,可空
- void:无返回值函数,不需要写return
3. 函数的3种分类(实战常用)
- 无参无返回值(简单打印类功能)
- 有参无返回值(对传入数据做处理,不返回结果)
- 有参有返回值(核心常用!处理数据并返回结果)
三、从零实战:3类函数完整代码案例
所有代码可直接复制编译运行,适配Dev-C++、VS、gcc所有编译环境。
实战1:无参无返回值函数
适用场景:固定提示、固定图案打印、无需传参和结果的功能。
#include<stdio.h>// 自定义无参无返回值函数voidprintHello(){printf("===== C语言函数实战 =====\n");printf("干货满满,零基础入门\n");}intmain(){// 直接调用函数printHello();printHello();// 可重复调用return0;}运行结果:
===== C语言函数实战 =====
干货满满,零基础入门
===== C语言函数实战 =====
干货满满,零基础入门
核心要点:void无返回值,括号无形参,直接函数名()调用。
实战2:有参无返回值函数
适用场景:接收外部数据,完成打印、判断、修改等操作,无需返回结果。
案例:传入两个整数,打印两数之和
#include<stdio.h>// 有参无返回值函数:形参a、bvoidgetSum(inta,intb){intsum=a+b;printf("两数之和为:%d\n",sum);}intmain(){intx=10,y=20;// 传入实参x、ygetSum(x,y);getSum(50,30);// 直接传常量也可以return0;}运行结果:
两数之和为:30
两数之和为:80
重点区分:形参 vs 实参
- 形参:函数定义时括号内的变量(int a, int b),仅占位,不分配实际内存
- 实参:调用函数时传入的变量/常量(x、y、50、30),是真实数据
实战3:有参有返回值函数(项目核心)
这是最常用的函数类型:接收参数,处理后返回结果给主函数使用。
案例1:求两个数的最大值
#include<stdio.h>// 有参有返回值:接收两个int,返回最大值intintgetMax(inta,intb){if(a>b){returna;// 返回结果}else{returnb;}}intmain(){intnum1,num2;printf("请输入两个整数:");scanf("%d %d",&num1,&num2);// 接收函数返回值intmax=getMax(num1,num2);printf("最大值为:%d\n",max);return0;}案例2:进阶实战:判断一个数是否为素数
#include<stdio.h>#include<math.h>// 素数判断函数:是素数返回1,不是返回0intisPrime(intn){// 小于2不是素数if(n<2)return0;// 遍历判断是否能被整除for(inti=2;i<=sqrt(n);i++){if(n%i==0){return0;// 能被整除,不是素数}}return1;// 是素数}intmain(){intnum;printf("请输入一个数字:");scanf("%d",&num);if(isPrime(num)){printf("%d 是素数\n",num);}else{printf("%d 不是素数\n",num);}return0;}四、新手必踩坑:函数声明与调用规则
1. 经典报错:隐式声明函数
C语言规则:函数必须先声明/定义,后调用。
如果把自定义函数写在main函数后面,直接调用会报错。
定义在调用之后,且未声明就会报错:
2. 两种解决方法(必掌握)
方法一:函数写在main函数之前(适合小型代码)
方法二:函数声明(大型项目标准写法)
#include<stdio.h>// 函数声明:只写头部,分号结尾intgetSum(inta,intb);intmain(){printf("%d\n",getSum(10,20));return0;}// 函数定义写在后面intgetSum(inta,intb){returna+b;}总结:声明告诉编译器“有这个函数”,定义是函数具体实现。
五、核心重难点:局部变量 & 全局变量
90%出错的根源:变量作用域搞不清楚。
1. 局部变量
- 定义在函数内部
- 仅在当前函数有效,函数结束立即销毁
- 不同函数可以定义同名局部变量,互不干扰
2. 全局变量
- 定义在所有函数外部
- 整个程序所有函数都可以使用
- 程序运行期间始终占用内存
3. 对比实战代码
#include<stdio.h>intnum=100;// 全局变量voidtest(){intnum=200;// 局部变量,优先使用printf("函数内部num:%d\n",num);}intmain(){printf("main全局num:%d\n",num);test();return0;}运行结果:
main全局num:100
函数内部num:200
核心规则:局部变量优先,局部会屏蔽全局。
六、高阶实战:递归函数(经典例题)
递归:函数自己调用自己,核心是「递推+终止条件」,常用于阶乘、斐波那契数列、遍历问题。
实战:递归求 n 的阶乘
#include<stdio.h>// 递归求阶乘intfactorial(intn){// 终止条件if(n==1||n==0)return1;// 递归公式returnn*factorial(n-1);}intmain(){intn;printf("请输入阶乘数:");scanf("%d",&n);printf("%d的阶乘为:%d\n",n,factorial(n));return0;}递归必备核心:必须有终止条件,否则无限递归、栈溢出报错!
七、函数实战总结
- 无返回值用void,有返回值必须对应类型+return
- 先声明/定义,后调用,杜绝隐式声明报错
- 形参是占位符,实参是真实数据,数量、类型必须一一对应
- 局部变量仅限当前函数,全局变量全程序通用
- 递归必须设置终止条件,避免死递归
- 项目开发优先用函数封装,拒绝全部代码堆在main里
八、实战练习(巩固提升)
大家可以自己手写练习,吃透函数核心:
- 封装函数:求三个整数的最大值
- 封装函数:判断闰年
- 递归实现:斐波那契数列前n项输出
- 封装函数:实现数组求和、求平均值
函数是C语言从“入门”到“进阶”的关键,看懂概念没用,动手敲代码、调试报错、独立封装功能才是真正学会。
本篇所有案例均可直接运行,建议大家逐行敲写,修改参数测试效果,彻底吃透函数逻辑!