第 6 章 函数
对应教材目录
Section titled “对应教材目录”- 6.1 函数的分类和定义
- 6.2 函数的返回值和参数
- 6.3 嵌套调用
- 6.4 变量的作用域
- 6.5 函数的作用域
- 6.6 编程实战
学完这一章,你应该能做到:
- 理解函数的作用是“封装功能”。
- 能自己定义简单函数。
- 知道形参、实参、返回值的含义。
- 能使用函数解决重复代码问题。
- 理解局部变量和全局变量的区别。
- 初步理解递归和嵌套调用。
1. 为什么要学函数
Section titled “1. 为什么要学函数”如果一个程序越来越长,所有代码都写在 main 函数里,会很乱。
函数的作用就是:
- 把一段独立功能单独封装起来
- 方便重复使用
- 让程序更清晰
2. 函数的基本形式
Section titled “2. 函数的基本形式”返回类型 函数名(参数列表){ 函数体}例如:
int add(int x, int y){ return x + y;}3. 函数的定义和调用
Section titled “3. 函数的定义和调用”完整例子:
#include <stdio.h>
int add(int x, int y){ return x + y;}
int main(void){ int a, b, c; scanf("%d%d", &a, &b); c = add(a, b); printf("%d\n", c); return 0;}这里:
add是函数名x、y是形参a、b是实参return x + y;是返回值
4. 无参和有参
Section titled “4. 无参和有参”4.1 无参函数
Section titled “4.1 无参函数”void hello(void){ printf("hello\n");}这里的 void hello(void) 里其实有两个 void,但它们的意思不一样:
- 前面的
void:表示这个函数没有返回值。 - 括号里的
void:表示这个函数没有参数。
也就是说:
void hello(void)可以拆开理解成:
hello这个函数执行一个动作- 不需要传入任何数据
- 执行完以后也不返回结果
再看一个对比例子:
int square(int x)这里:
- 前面的
int表示函数执行后会返回一个整数 - 括号里的
int x表示调用这个函数时,要传入一个整型参数x
还有一个你很容易混淆的点:
hello(void):明确表示“无参数”,这是标准、清晰的写法。hello():在 C 语言里更接近“参数没有写明”,初学阶段不要把它当成严格意义上的“无参函数”写法。
所以以后看到:
int main(void):表示main没有参数,但会返回一个intvoid print_line(void):表示print_line没有参数,也没有返回值
最后看看实际中的效果


可以从图片中看到,第一个是黄色的警告(这个时候代码是可以运行的),第二个是直接报错了(编译不了)。
4.2 有参函数
Section titled “4.2 有参函数”int square(int x){ return x * x;}5. 有返回值和无返回值
Section titled “5. 有返回值和无返回值”5.1 有返回值
Section titled “5.1 有返回值”int max(int a, int b){ return a > b ? a : b;}5.2 无返回值
Section titled “5.2 无返回值”void print_line(void){ printf("------\n");}如果函数只是完成一个动作,不需要把结果交回来,可以使用 void。
这里前面的 void 是“无返回值”,括号里的 (void) 是“无参数”,两个位置的含义不要混在一起。
6. 参数传递
Section titled “6. 参数传递”C 语言函数参数传递的基础是值传递。
这意味着:函数接收到的是实参值的副本,不是原变量本身。
例如:
#include <stdio.h>
void change(int x){ x = 100;}
int main(void){ int a = 10; change(a); printf("%d\n", a); return 0;}输出仍然是:
10因为 change 改的是形参 x,不是 main 里的 a。
7. 函数声明
Section titled “7. 函数声明”如果函数定义写在 main 后面,通常要先声明。
#include <stdio.h>
int add(int x, int y);
int main(void){ printf("%d\n", add(2, 3)); return 0;}
int add(int x, int y){ return x + y;}8. 局部变量和全局变量
Section titled “8. 局部变量和全局变量”8.1 局部变量
Section titled “8.1 局部变量”在函数内部定义,只在本函数内有效。
8.2 全局变量
Section titled “8.2 全局变量”在所有函数外部定义,作用域更大。
示例:
#include <stdio.h>
int a = 100;
void fun(void){ int a = 10; printf("%d\n", a);}
int main(void){ fun(); printf("%d\n", a); return 0;}这里 fun 中的局部变量 a 会暂时屏蔽全局变量 a。
9. static 局部变量
Section titled “9. static 局部变量”int f(void){ static int a = 0; a++; return a;}static 局部变量的特点:
- 只初始化一次
- 函数调用结束后值不会消失
10. 递归的入门理解
Section titled “10. 递归的入门理解”递归就是函数自己调用自己。
例如求阶乘:
int fact(int n){ if (n == 1) return 1; return n * fact(n - 1);}递归一定要有结束条件,否则会无限调用。
11. 本章常见模板
Section titled “11. 本章常见模板”11.1 求最大值函数
Section titled “11.1 求最大值函数”int max(int a, int b){ if (a > b) return a; else return b;}11.2 判断奇偶函数
Section titled “11.2 判断奇偶函数”int is_even(int n){ if (n % 2 == 0) return 1; else return 0;}11.3 数组求和函数
Section titled “11.3 数组求和函数”int sum(int a[], int n){ int i, s = 0; for (i = 0; i < n; i++) s += a[i]; return s;}12. 本章最容易错的点
Section titled “12. 本章最容易错的点”- 忘记写函数声明。
- 把形参和实参混淆。
- 以为函数中改了参数,外面的原变量也会变。
- 返回值类型和实际返回内容不匹配。
- 递归没有结束条件。
- 局部变量和全局变量重名时判断不清作用范围。
13. 手写题
Section titled “13. 手写题”- 写出下面程序的输出结果。
#include <stdio.h>
int f(int x){ x = x + 10; return x;}
int main(void){ int a = 5; f(a); printf("%d\n", a); return 0;}- 写出下面程序的输出结果。
#include <stdio.h>
int f(void){ static int a = 0; a++; return a;}
int main(void){ printf("%d ", f()); printf("%d ", f()); printf("%d\n", f()); return 0;}- 写出下面程序的输出结果。
#include <stdio.h>
int a = 100;
void fun(void){ int a = 10; printf("%d\n", a);}
int main(void){ fun(); printf("%d\n", a); return 0;}- 写函数
max(int a, int b),返回两个数中的较大值。 - 写函数
sum(int n),返回1 + 2 + ... + n。 - 写函数
is_even(int n),判断一个数是否为偶数。 - 写函数求三个整数中的最大值。
- 写函数判断一个年份是否为闰年。
- 写函数求两个整数的最大公约数。
- 写函数判断一个正整数是否为素数。
- 在主函数中调用上题函数,输出 1 到 100 之间所有素数。
- 用递归函数求
n!。 - 用递归函数求斐波那契数列第
n项。 - 写函数求数组元素之和。
- 写函数统计字符串长度。
- 写函数将一个字符串中的小写字母转换为大写字母。
- 找出并改正下面程序中的错误。
#include <stdio.h>
int add(int x, int y){ printf("%d\n", x + y);}
int main(void){ int c; c = add(2, 3); printf("%d\n", c); return 0;}- 修改下面递归函数,使其能正确计算阶乘。
int fact(int n){ return n * fact(n - 1);}14. 自测清单
Section titled “14. 自测清单”- 我知道函数为什么能让程序更清晰。
- 我能自己写一个有参数、有返回值的函数。
- 我能区分形参和实参。
- 我知道什么是局部变量,什么是全局变量。
- 我能解释值传递为什么不会直接改变外部变量。
- 我会写最简单的递归函数。
15. 学习建议
Section titled “15. 学习建议”- 第 6 章一定要多写,不要只读。
- 每写一个函数,先用一句中文说明“它输入什么,输出什么”。
- 如果一个函数太长,就想一想能不能再拆小一点。
- 递归题先不要贪多,先把阶乘和斐波那契吃透。
学完这一章后,你就具备了把程序组织得更像“一个完整项目”的能力。