🎯 本章你会学到:函数原型、值传递的本质、static 与头文件,以及怎么把代码拆成多个文件。建议边读边敲,每节练习先自己做,再展开答案对照。
函数把一段逻辑打包并起名字。C 的函数参数全部是值传递——这一点决定了:想改外面的变量,必须传指针。
原型、定义与调用
函数原型与定义
#include <stdio.h>
int max_of(int a, int b); /* 函数原型:先告诉编译器有这么个函数 */
long long gcd(long long a, long long b);
int main(void) {
int a = 0, b = 0;
if (scanf("%d %d", &a, &b) != 2) {
return 1;
}
printf("max=%d\n", max_of(a, b));
printf("gcd=%lld\n", gcd(a, b));
return 0;
}
int max_of(int a, int b) {
return a > b ? a : b;
}
long long gcd(long long a, long long b) { /* 辗转相除 */
while (b != 0) {
long long t = a % b;
a = b;
b = t;
}
return a;
}输入
12 18运行结果
max=18
gcd=6
输入 12 18 输出 max=18 与 gcd=6。原型要写在调用之前,否则编译器无从知道返回类型。
多文件:头文件放声明,源文件放定义
util.h
#ifndef UTIL_H
#define UTIL_H
int square(int x); /* 只有声明 */
#endif
util.c
#include "util.h"
int square(int x) { /* 定义放在 .c 里 */
return x * x;
}
main.c
#include <stdio.h>
#include "util.h"
int main(void) {
printf("%d\n", square(12));
return 0;
}运行结果
144
编译多文件工程
gcc -std=c17 -Wall -Wextra -o app main.c util.c # 两个 .c 一起交给编译器
头文件里的 #ifndef / #define / #endif 是 include guard,防止同一个头文件被重复包含。函数定义绝不能放进头文件,否则每个包含它的 .c 都会定义一次,链接时报重复定义。
⚠️ 易错点 值传递改不了实参:
void f(int x) { x = 100; } 调用后原变量不变,想改就得传地址 void f(int *x) { *x = 100; }。⚠️ 易错点
static 修饰函数表示只在本文件可见,是隐藏实现细节的常用手段,多文件工程里非常好用。✍️ 本节练习
4.1必做写两个小函数
写 int add(int a, int b) 和 int sub(int a, int b),读入两个整数,输出和与差。
输入 一行两个整数 a b。
输出 两行:sum=和、diff=差。
样例输入
7 3样例输出
sum=10
diff=4💡 提示 两个函数写在 main 之前,或者先写原型。
✅ 查看参考答案与解析
#include <stdio.h>
int add(int a, int b);
int sub(int a, int b);
int main(void) {
int a = 0, b = 0;
if (scanf("%d %d", &a, &b) != 2) {
return 1;
}
printf("sum=%d\n", add(a, b));
printf("diff=%d\n", sub(a, b));
return 0;
}
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }解析 函数很短时可以写成一行;参数是值传递,函数内改 a、b 不影响 main。
4.2挑战判断质数
写函数 int is_prime(long long n),读入 n(n ≥ 2),是质数输出 yes,否则 no。
输入 一个整数 n(2 ≤ n ≤ 10^9)。
输出 yes 或 no。
样例输入
17样例输出
yes💡 提示 只试除到 √n:for (long long i = 2; i * i <= n; ++i)。
✅ 查看参考答案与解析
#include <stdbool.h>
#include <stdio.h>
static bool is_prime(long long n) {
if (n < 2) {
return false;
}
for (long long i = 2; i * i <= n; ++i) {
if (n % i == 0) {
return false;
}
}
return true;
}
int main(void) {
long long n = 0;
if (scanf("%lld", &n) != 1) {
return 1;
}
printf("%s\n", is_prime(n) ? "yes" : "no");
return 0;
}解析 i * i <= n 比 i <= sqrt(n) 更好:不引入浮点,也不会因精度出错。参数用 long long 避免相乘溢出。