当前位置: 首页 > news >正文

C语言入门教程(第6讲):函数——让程序学会“分工合作”的魔法

🌱 文章摘要

写程序就像建城市——
变量是建筑,循环是道路,而函数是城市的“部门”
它让你的代码学会“分工合作”,不再混乱无章。


本讲带你彻底掌握函数的定义、参数、返回值与作用域,
让C语言从“能跑”变成“能管理”


📘 导读

到目前为止,我们的程序能输入、能循环、能存数据。
但是不是越来越“长”,甚至有点“乱”?

一眼望去,全是printf和scanf堆在一起。

这时候,就需要函数登场了——
它能把程序“切块”,让每一块只干一件事。

在这一讲中,我们将:

  • 理解函数的核心思想;

  • 学会自己定义函数;

  • 掌握参数、返回值与作用域;

  • 明白库函数、自定义函数的区别;

  • 体验真正“模块化编程”的感觉。


准备好了吗?让我们一起打开C语言的“逻辑引擎”!


📘 建议收藏本专栏:后续章节会持续更新,
包括控制语句、函数、指针、数组、文件操作等完整体系。

如果你能坚持学完,你会发现——
C语言不仅是工具,更是理解计算机世界的第一扇门。


目录

一、为什么要有函数

二、函数的结构

2.1 调用流程

三、函数的分类

3.1 库函数:C语言的“工具箱”

3.2 自定义函数:你的“逻辑工厂”

四、形参与实参:函数的“传话机制”

4.1 示例:形参与实参

4.2 示例:交换失败的经典陷阱

五、return:函数的“快递出口”

5.1 示例:有返回值的函数

5.2 示例:无返回值的函数

六、数组作为函数参数:批量任务的传递方式

6.1 示例:打印数组

6.2 示例:修改数组

七、实战:用函数做一个“迷你计算器”

7.1 项目:命令行计算器

八、函数声明与多文件协作

8.1 示例:先声明,后使用

九、static 与 extern:函数的“活动范围”

9.1 static:只在本文件可见

9.2 extern:跨文件访问

十、总结

十一、下一讲预告

11.1 下一讲预告

11.2 提前准备建议


一、为什么要有函数

先来想一个小故事:

你是一个程序员,在做一款“学生成绩管理系统”。
你要输入成绩、求平均值、求最大值、输出结果。

结果写完的 main 函数大概长这样:

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 是“老板”,函数是“员工”,
老板发任务,员工干活,干完再汇报结果。


二、函数的结构

先看一个最经典的例子:

#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;
}

输出:

结果为:8

函数结构拆解:

返回值类型 函数名(参数类型 参数名, ...) {函数体语句;
}
部分含义
int返回一个整数
add函数名称
(int x, int y)参数(形参)
return x + y;返回结果

2.1 调用流程

  1. main 调用 add;

  2. 参数 3、5 传给 x、y;

  3. add 执行完毕;

  4. return 把结果送回 main;

  5. main 输出结果。


函数就是“任务模块”,写一次,用很多次。


三、函数的分类

C语言中的函数可以分为两类:

类型示例说明
库函数printf, scanf, strlen, sqrt系统自带
自定义函数add, max, print_sum用户编写

3.1 库函数:C语言的“工具箱”

这些函数早已写好,我们只需调用。

示例:

#include <math.h>
double result = sqrt(9.0);
printf("%.2f\n", result);

输出:

3.00

常见库:

头文件常见函数功能
stdio.hprintf, scanf输入输出
math.hsqrt, pow数学运算
string.hstrlen, strcpy字符串处理
stdlib.hrand, atoi工具函数

3.2 自定义函数:你的“逻辑工厂”

当库函数不够用时,就自己造!

int max(int a, int b) {return (a > b ? a : b);
}

调用:

printf("最大值为:%d\n", max(10, 20));

输出:

最大值为:20

库函数是C语言的“现成工具”,自定义函数是你的“创造力体现”。


四、形参与实参:函数的“传话机制”

在现实世界里,老板(main函数)给员工(子函数)下任务时,总得告诉他“干啥”和“数据是多少”。
在C语言里,这种“任务沟通”靠的是——参数传递


4.1 示例:形参与实参

#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;
}

输出:

两数之和:30

解释:

  • 形参:函数定义时用来接收值的“容器”;

  • 实参:函数调用时传入的实际值。

调用时,实参的值会被“复制”给形参,函数内部修改形参,不会影响外部的实参。


4.2 示例:交换失败的经典陷阱

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;
}

输出:

3 5   // 没有交换成功

原因:

函数内部的 ab 只是“副本”。
真正的 xy 在外面安然无恙。


C语言的参数默认是“值传递”。
想真正交换,需要传递地址(指针篇将讲)。


五、return:函数的“快递出口”

函数干完活,总得告诉调用者结果。
这个“出口”就是 return


5.1 示例:有返回值的函数

int add(int a, int b) {return a + b;   // 返回结果
}int main() {int r = add(5, 7);printf("结果是:%d\n", r);return 0;
}

输出:

结果是:12

5.2 示例:无返回值的函数

void say_hi() {printf("Hello, C!\n");
}int main() {say_hi();   // 不需要接收返回值return 0;
}

输出:

Hello, C!

总结:

  • 有返回值:带回数据;

  • 无返回值:只执行操作;

  • return 语句执行后函数立即结束;

  • 一个函数只能有一个返回类型。


return 是函数与外界交流的“语言”。
没有它,函数就像一个“沉默的打工人”。


六、数组作为函数参数:批量任务的传递方式

有时候我们需要让函数处理整组数据,例如统计成绩或查找最大值。
这时我们可以把“数组”整个传给函数。


6.1 示例:打印数组

#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;
}

输出:

1 2 3 4 5

说明:

数组名在传参时会自动转为“指针”。
函数内部访问的是原数组内容。


6.2 示例:修改数组

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]);
}

输出:

2 4 6

结论:

函数中修改数组会影响原数据。
因为传递的是“地址”,不是“副本”。


数组参数让函数处理大规模数据,是通向“指针世界”的第一个入口。


七、实战:用函数做一个“迷你计算器”

光讲理论没意思,来点“真刀真枪”的代码吧。


7.1 项目:命令行计算器

目标:输入表达式 3 + 5,自动输出结果。

#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;
}

输出示例:

请输入表达式(如 3 + 5):8 * 9
结果:72

分析:

  • 每个函数只干一件事;

  • main 函数只负责“分工”;

  • 代码结构清晰、逻辑分明。


当你能用函数写出这样的程序,就说明你真的理解了“模块化思维”。


八、函数声明与多文件协作

在大型项目中,代码常分散在多个文件。
C语言要求函数在使用前必须声明


8.1 示例:先声明,后使用

#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:只在本文件可见

static void say_hi() {printf("Hi, I'm a static function!\n");
}

用途:

  • 防止命名冲突;

  • 常用于内部实现函数。


9.2 extern:跨文件访问

// 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 提前准备建议

强烈建议提前准备以下内容:

  1. 在 VS2022 或 CLion 中新建一个空项目;

  2. 熟悉如何创建多个 .c.h 文件(如 game.c, game.h, test.c);

  3. 回顾第5讲(数组)与第6讲(函数)的知识;

  4. 思考:如果要在 9×9 的棋盘上“埋雷”,你会怎么存数据?

  5. 尝试写一个小函数:随机生成 10 个坐标。

💡 提示:
扫雷游戏的核心,不是“图形界面”,而是逻辑控制与数据组织
这正是 C语言最锻炼编程思维的地方。


📘 系列结尾

本文属于《C语言入门教程》系列专栏第6讲
下一讲将带你用代码实现一个真正的小游戏——扫雷
这是一次知识的融合与实战的起点。

点赞 + 收藏 + 关注专栏
一起在代码的世界中“拆解游戏的秘密” 💪

http://www.dtcms.com/a/477455.html

相关文章:

  • 福建定制网站开发泰安一级的企业建站公司
  • 公司要建立网站要怎么做太原优化型网站建设
  • 开源 C++ QT QML 开发(十七)进程--LocalSocket
  • 2.CSS3.(3).html
  • 【MQ】RabbitMQ:架构、工作模式、高可用与流程解析
  • 零基础学AI大模型之大模型修复机制:OutputFixingParser解析器
  • 单个服务器部署多个rabbitmq
  • 银行资产管理系统核心业务架构设计
  • 面向快餐店的全程无人化自动化餐厅深度研究方案
  • 开源 C++ QT QML 开发(十八)多媒体--音频播放
  • 【开题答辩全过程】以 宾馆客房管理系统为例,包含答辩的问题和答案
  • 宁波网站建设设计价格我需要做网站
  • 使用 PyTorch 实现 MNIST 手写数字识别
  • ComfyUI安装和启动攻略1
  • h5移动端开发民治网站优化培训
  • uniapp 微信小程序蓝牙接收中文乱码
  • 多制式基站综合测试线的架构与验证实践 (1)
  • Ceph 分布式存储学习笔记(四):文件系统存储管理
  • ceph设置标志位
  • 系统升级丨让VR全景制作更全面、更简单
  • PyTorch 实现 MNIST 手写数字识别全流程
  • PyTorch实现MNIST手写数字识别:从数据到模型全解析
  • PostgreSQL 测试磁盘性能
  • 北京网站开发科技企业网站
  • 干货|腾讯 Linux C/C++ 后端开发岗面试
  • 【深度学习新浪潮】如何入门分布式大模型推理?
  • 基于单片机的螺旋藻生长大棚PH智能控制设计
  • 分布式专题——42 MQ常见问题梳理
  • mapbox基础,使用矢量切片服务(pbf)加载symbol符号图层
  • Linux中setup_arch和setup_memory相关函数的实现