🌱 文章摘要
写程序就像建城市------
变量是建筑,循环是道路,而函数 ,是城市的"部门"。
它让你的代码学会**"分工合作"**,不再混乱无章。
本讲带你彻底掌握函数的定义、参数、返回值与作用域,
让C语言从"能跑"变成"能管理"。
📘 导读
到目前为止,我们的程序能输入、能循环、能存数据。
但是不是越来越"长",甚至有点"乱"?
一眼望去,全是printf和scanf堆在一起。
这时候,就需要函数 登场了------
它能把程序"切块",让每一块只干一件事。在这一讲中,我们将:
理解函数的核心思想;
学会自己定义函数;
掌握参数、返回值与作用域;
明白库函数、自定义函数的区别;
体验真正"模块化编程"的感觉。
准备好了吗?让我们一起打开C语言的"逻辑引擎"!
📘 建议收藏本专栏 :后续章节会持续更新,
包括控制语句、函数、指针、数组、文件操作等完整体系。
如果你能坚持学完,你会发现------
C语言不仅是工具,更是理解计算机世界的第一扇门。
目录
[2.1 调用流程](#2.1 调用流程)
[3.1 库函数:C语言的"工具箱"](#3.1 库函数:C语言的“工具箱”)
[3.2 自定义函数:你的"逻辑工厂"](#3.2 自定义函数:你的“逻辑工厂”)
[4.1 示例:形参与实参](#4.1 示例:形参与实参)
[4.2 示例:交换失败的经典陷阱](#4.2 示例:交换失败的经典陷阱)
[5.1 示例:有返回值的函数](#5.1 示例:有返回值的函数)
[5.2 示例:无返回值的函数](#5.2 示例:无返回值的函数)
[6.1 示例:打印数组](#6.1 示例:打印数组)
[6.2 示例:修改数组](#6.2 示例:修改数组)
[7.1 项目:命令行计算器](#7.1 项目:命令行计算器)
[8.1 示例:先声明,后使用](#8.1 示例:先声明,后使用)
[九、static 与 extern:函数的"活动范围"](#九、static 与 extern:函数的“活动范围”)
[9.1 static:只在本文件可见](#9.1 static:只在本文件可见)
[9.2 extern:跨文件访问](#9.2 extern:跨文件访问)
[11.1 下一讲预告](#11.1 下一讲预告)
[11.2 提前准备建议](#11.2 提前准备建议)
一、为什么要有函数
先来想一个小故事:
你是一个程序员,在做一款"学生成绩管理系统"。
你要输入成绩、求平均值、求最大值、输出结果。
结果写完的 main 函数大概长这样:
cpp
int main() {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
int max = (a > b ? (a > c ? a : c) : (b > c ? b : c));
float avg = (a + b + c) / 3.0;
printf("最高分:%d\n平均分:%.2f\n", max, avg);
return 0;
}
能跑,但很"糟糕":
逻辑混在一起;
不可复用;
一改一个错。
于是,C语言告诉你:"让每件事,都交给一个人去做。"
那个人,就是函数。
定义:
函数(Function)是一段可以被多次调用的代码,用于完成特定任务。
你可以理解为:
main 是"老板",函数是"员工",
老板发任务,员工干活,干完再汇报结果。
二、函数的结构
先看一个最经典的例子:
cpp
#include <stdio.h>
// 定义函数
int add(int x, int y) {
return x + y;
}
int main() {
int result = add(3, 5); // 调用函数
printf("结果为:%d\n", result);
return 0;
}
输出:
cpp
结果为:8
函数结构拆解:
cpp
返回值类型 函数名(参数类型 参数名, ...) {
函数体语句;
}
部分 | 含义 |
---|---|
int |
返回一个整数 |
add |
函数名称 |
(int x, int y) |
参数(形参) |
return x + y; |
返回结果 |
2.1 调用流程
main 调用 add;
参数 3、5 传给 x、y;
add 执行完毕;
return 把结果送回 main;
main 输出结果。
函数就是"任务模块",写一次,用很多次。
三、函数的分类
C语言中的函数可以分为两类:
类型 | 示例 | 说明 |
---|---|---|
库函数 | printf, scanf, strlen, sqrt | 系统自带 |
自定义函数 | add, max, print_sum | 用户编写 |
3.1 库函数:C语言的"工具箱"
这些函数早已写好,我们只需调用。
示例:
cpp
#include <math.h>
double result = sqrt(9.0);
printf("%.2f\n", result);
输出:
cpp
3.00
常见库:
头文件 | 常见函数 | 功能 |
---|---|---|
stdio.h | printf, scanf | 输入输出 |
math.h | sqrt, pow | 数学运算 |
string.h | strlen, strcpy | 字符串处理 |
stdlib.h | rand, atoi | 工具函数 |
3.2 自定义函数:你的"逻辑工厂"
当库函数不够用时,就自己造!
cpp
int max(int a, int b) {
return (a > b ? a : b);
}
调用:
cpp
printf("最大值为:%d\n", max(10, 20));
输出:
cpp
最大值为:20
库函数是C语言的"现成工具",自定义函数是你的"创造力体现"。
四、形参与实参:函数的"传话机制"
在现实世界里,老板(main函数)给员工(子函数)下任务时,总得告诉他"干啥"和"数据是多少"。
在C语言里,这种"任务沟通"靠的是------参数传递。
4.1 示例:形参与实参
cpp
#include <stdio.h>
void print_sum(int a, int b) { // 形参:占位符
printf("两数之和:%d\n", a + b);
}
int main() {
int x = 10, y = 20;
print_sum(x, y); // 实参:实际值
return 0;
}
输出:
cpp
两数之和:30
解释:
-
形参:函数定义时用来接收值的"容器";
-
实参:函数调用时传入的实际值。
调用时,实参的值会被"复制"给形参,函数内部修改形参,不会影响外部的实参。
4.2 示例:交换失败的经典陷阱
cpp
void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 3, y = 5;
swap(x, y);
printf("%d %d\n", x, y);
return 0;
}
输出:
cpp
3 5 // 没有交换成功
原因:
函数内部的
a
、b
只是"副本"。真正的
x
、y
在外面安然无恙。
C语言的参数默认是"值传递"。
想真正交换,需要传递地址(指针篇将讲)。
五、return:函数的"快递出口"
函数干完活,总得告诉调用者结果。
这个"出口"就是 return
。
5.1 示例:有返回值的函数
cpp
int add(int a, int b) {
return a + b; // 返回结果
}
int main() {
int r = add(5, 7);
printf("结果是:%d\n", r);
return 0;
}
输出:
cpp
结果是:12
5.2 示例:无返回值的函数
cpp
void say_hi() {
printf("Hello, C!\n");
}
int main() {
say_hi(); // 不需要接收返回值
return 0;
}
输出:
cpp
Hello, C!
总结:
-
有返回值:带回数据;
-
无返回值:只执行操作;
-
return
语句执行后函数立即结束; -
一个函数只能有一个返回类型。
return 是函数与外界交流的"语言"。
没有它,函数就像一个"沉默的打工人"。
六、数组作为函数参数:批量任务的传递方式
有时候我们需要让函数处理整组数据,例如统计成绩或查找最大值。
这时我们可以把"数组"整个传给函数。
6.1 示例:打印数组
cpp
#include <stdio.h>
void print_array(int arr[], int n) {
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int nums[5] = {1, 2, 3, 4, 5};
print_array(nums, 5);
return 0;
}
输出:
cpp
1 2 3 4 5
说明:
数组名在传参时会自动转为"指针"。
函数内部访问的是原数组内容。
6.2 示例:修改数组
cpp
void double_array(int arr[], int n) {
for (int i = 0; i < n; i++) {
arr[i] *= 2;
}
}
int main() {
int a[3] = {1, 2, 3};
double_array(a, 3);
for (int i = 0; i < 3; i++) printf("%d ", a[i]);
}
输出:
cpp
2 4 6
结论:
函数中修改数组会影响原数据。
因为传递的是"地址",不是"副本"。
数组参数让函数处理大规模数据,是通向"指针世界"的第一个入口。
七、实战:用函数做一个"迷你计算器"
光讲理论没意思,来点"真刀真枪"的代码吧。
7.1 项目:命令行计算器
目标:输入表达式 3 + 5
,自动输出结果。
cpp
#include <stdio.h>
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
int divide(int a, int b) { return b != 0 ? a / b : 0; }
int main() {
int x, y;
char op;
printf("请输入表达式(如 3 + 5):");
scanf("%d %c %d", &x, &op, &y);
switch(op) {
case '+': printf("结果:%d\n", add(x, y)); break;
case '-': printf("结果:%d\n", sub(x, y)); break;
case '*': printf("结果:%d\n", mul(x, y)); break;
case '/': printf("结果:%d\n", divide(x, y)); break;
default: printf("暂不支持该运算符。\n");
}
return 0;
}
输出示例:
cpp
请输入表达式(如 3 + 5):8 * 9
结果:72
分析:
-
每个函数只干一件事;
-
main 函数只负责"分工";
-
代码结构清晰、逻辑分明。
当你能用函数写出这样的程序,就说明你真的理解了"模块化思维"。
八、函数声明与多文件协作
在大型项目中,代码常分散在多个文件。
C语言要求函数在使用前必须声明。
8.1 示例:先声明,后使用
cpp
#include <stdio.h>
int max(int a, int b); // 声明
int main() {
printf("%d\n", max(10, 20));
return 0;
}
int max(int a, int b) { // 定义
return (a > b ? a : b);
}
说明:
声明告诉编译器"函数长什么样";
定义告诉它"函数怎么做"。
九、static 与 extern:函数的"活动范围"
这两个关键字决定函数能在哪被访问。
9.1 static:只在本文件可见
cpp
static void say_hi() {
printf("Hi, I'm a static function!\n");
}
用途:
-
防止命名冲突;
-
常用于内部实现函数。
9.2 extern:跨文件访问
cpp
// file1.c
int num = 100;
// file2.c
extern int num;
printf("%d\n", num);
用途:
让不同源文件之间共享数据或函数。
static 管内部,extern 管外部。
它们是多文件工程的基础。
十、总结
这一讲,我们正式掌握了C语言的"灵魂武器"------函数。
你现在已经会:
-
定义函数、理解参数;
-
使用 return 返回结果;
-
让数组作为参数传递;
-
用函数构建小型项目;
-
掌握 static / extern 的作用。
到此为止,你的C语言不再是**"顺序执行"** ,而是**"逻辑分层"**的程序。
十一、下一讲预告
11.1 下一讲预告
《C语言入门教程(第7讲):数组和函数实践------扫雷游戏》
这一讲,你将真正把前六讲学到的知识"融会贯通" 。
我们要用数组存储棋盘,用函数管理逻辑,
一步步实现一个可玩的扫雷游戏!
主要内容包括:
扫雷游戏的功能分析与模块设计
9×9 棋盘与 10 个雷的随机布置
数组越界的处理与扩展技巧
函数模块化:初始化、布雷、排雷、显示
多文件结构(.h、.c)的实战分工
扫雷游戏的完整代码与扩展玩法
这一讲不仅是数组与函数的实践,更是你第一次亲手写出一个完整程序 的时刻。
从这里开始,C语言不再只是语法,而是"创造力"的工具。
11.2 提前准备建议
强烈建议提前准备以下内容:
在 VS2022 或 CLion 中新建一个空项目;
熟悉如何创建多个
.c
和.h
文件(如game.c
,game.h
,test.c
);回顾第5讲(数组)与第6讲(函数)的知识;
思考:如果要在 9×9 的棋盘上"埋雷",你会怎么存数据?
尝试写一个小函数:随机生成 10 个坐标。
💡 提示:
扫雷游戏的核心,不是**"图形界面"** ,而是逻辑控制与数据组织 。
这正是 C语言最锻炼编程思维的地方。
📘 系列结尾
本文属于《C语言入门教程》系列专栏第6讲
下一讲将带你用代码实现一个真正的小游戏------扫雷 。
这是一次知识的融合与实战的起点。
点赞 + 收藏 + 关注专栏,
一起在代码的世界中"拆解游戏的秘密" 💪