10 · 函数
- 会定义和调用函数
- 理解参数是「拷贝」进去的
- 会用返回值把结果交回来
为什么拆函数
函数 = 一段有名字、可重复使用的代码。写函数时想清楚三件事:
- 输入:参数列表(要哪些信息)
- 输出:返回类型(算完交回什么);只做事可返回 void
- 职责:名字要能说明它干什么,例如 add、print_line、max2
调用 add(3, 4) 时:把 3、4 拷贝给 a、b → 执行函数体 → return 把结果交回调用处。
#include <stdio.h>
int add(int a, int b)
{
return a + b;
}
void say_hello(void)
{
printf("hello\n");
}
int main(void)
{
int s = add(3, 4);
say_hello();
printf("sum = %d\n", s); // 7
return 0;
}
返回值类型
int add(...):算完交回一个 intvoid say_hello(void):只做事,不交回值- 调用时:
int s = add(3,4);或say_hello();
return 的类型必须和声明一致。声明 int 却不 return,返回值是垃圾;声明 void 却 return 10,编译报错。
参数是拷贝
把变量传给函数,函数里改的是自己的那份副本,外面的变量不会变。这叫传值(pass by value)。
推论:若参数是 int/float 这类小盒子,函数无法「顺手改掉调用方的变量」——要么 return 新值,要么传地址(指针,第 13 课)。
#include <stdio.h>
void try_change(int x)
{
x = 100; /* 只改了副本 */
}
int main(void)
{
int n = 1;
try_change(n);
printf("%d\n", n); /* 还是 1,不是 100 */
return 0;
}
声明(原型)
如果函数写在 main 后面,要在前面先「打招呼」,否则编译器不认识:
#include <stdio.h>
int max2(int a, int b); /* 声明 */
int main(void)
{
printf("%d\n", max2(3, 9));
return 0;
}
int max2(int a, int b) /* 定义 */
{
return a > b ? a : b;
}
局部变量与作用域
函数里定义的变量,出了大括号就没了。两个函数可以各自有同名变量,互不干扰。
#include <stdio.h>
void f1(void)
{
int n = 1;
printf("f1 n=%d\n", n);
}
void f2(void)
{
int n = 2; /* 和 f1 的 n 无关 */
printf("f2 n=%d\n", n);
}
int main(void)
{
f1();
f2();
return 0;
}
函数设计小原则
- 一个函数尽量只做一件事
- 名字用动词或动宾:
print_line、calc_sum - 参数不要太多(超过 4 个就考虑用结构体)
- 先想「输入是什么、输出是什么」,再写函数体
三元运算符(函数里很好用)
条件 ? A : B 条件真取 A,否则取 B。
int max = (a > b) ? a : b;
int absx = (x < 0) ? -x : x;
单片机场景 · 函数:输入、输出与范围
一个函数完成一件事。小类型相加也可能产生更大的结果,避免截断返回值。
边界与验证:面向常见 8 位 unsigned char 环境的桌面示例,输出 300。返回类型改为 unsigned int;桌面程序用 int main(void),不照搬特定嵌入式环境的 void main。
#include <stdio.h>
unsigned int add(unsigned char a, unsigned char b)
{
return (unsigned int)a + (unsigned int)b;
}
int main(void)
{
printf("%u\n", add(200, 100));
return 0;
}
本课过关
必做函数里修改 int 形参,会改变调用处的实参吗?
C 默认是「传值」:调用 try_change(n) 时,会把 n 的值复制一份给形参 x。函数里 x=100 改的是这份副本,main 里的 n 原封不动,所以打印仍是 1。若希望函数改到外面的变量,标准做法是传地址:void try_change(int *x){ *x=100; },调用写 try_change(&n)。也可以让函数 return 新值,由调用方自己赋值:n = compute(n);。先分清「传值」和「传址」,后面学指针会轻松很多。
- 写函数 int square(int n) 返回 n*n。
- 写 void print_line(void) 打印一行分隔线。
- 解释为什么 try_change 改不了 main 里的 n。
先自己写完,再点开看解答
1:square
int square(int n)
{
return n * n;
}2:分隔线
void print_line(void)
{
printf("----------------\n");
}3:为何改不了 n:调用 try_change(n) 时,实参 n 的值被复制给形参 x。x 在函数自己的栈帧里,x=100 只动了副本。main 的 n 从未被写入。要改外面,用指针:void try_change(int *x){ *x=100; } 调用写 try_change(&n);。
下一课:字符串——程序里怎么处理文字。