函数
翻译整理自 cppreference - 函数。
1. 函数定义与声明
C 要求先声明后使用:
// 声明(原型)
int add(int, int);
int main(void) {
int s = add(1, 2);
return 0;
}
// 定义
int add(int a, int b) {
return a + b;
}不写原型而直接调用,编译器可能默认返回 int,已经过时且不安全。
2. 参数传递
C 所有参数都是值传递(包括指针):
void swap_wrong(int a, int b) {
int t = a; a = b; b = t; // 改不动调用方
}
void swap(int *a, int *b) {
int t = *a; *a = *b; *b = t;
}
int main(void) {
int x = 1, y = 2;
swap(&x, &y); // 传地址
printf("%d %d\n", x, y); // 2 1
}3. 数组参数
数组作为参数会退化为指针:
void f(int arr[10]) {
// 等价于 int *arr,size 信息丢失
sizeof(arr); // 8(指针大小)
}
void g(int *arr, int n) {
for (int i = 0; i < n; i++) arr[i] *= 2;
}4. 变长参数
通过 <stdarg.h> 实现:
#include <stdarg.h>
int sum(int n, ...) {
va_list args;
va_start(args, n);
int total = 0;
for (int i = 0; i < n; i++) {
total += va_arg(args, int);
}
va_end(args);
return total;
}
sum(3, 1, 2, 3); // 6
sum(5, 1, 2, 3, 4, 5); // 15
变长参数没有类型检查,使用要小心。
5. 返回值
int add(int, int);
double divide(int, int);
void log_msg(const char *); // 无返回
不要返回局部变量的地址!局部变量在函数返回后失效。
6. 递归
int fact(int n) {
return n <= 1 ? 1 : n * fact(n - 1);
}
// 斐波那契(朴素,效率低)
int fib(int n) {
return n < 2 ? n : fib(n - 1) + fib(n - 2);
}7. 存储期与作用域
int global = 1; // 静态存储期,全局
void f(void) {
int x = 1; // 自动(栈),函数返回即销毁
static int count = 0; // 静态存储期,只初始化一次
count++;
}
static int internal_counter; // 仅本文件可见
extern int external_var; // 引用其它文件中定义的全局
8. inline 函数(C99)
static inline int square(int x) {
return x * x;
}通常配合
static使用,避免链接冲突。
9. 函数指针
int (*op)(int, int);
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int main(void) {
op = add;
printf("%d\n", op(1, 2)); // 3
op = sub;
printf("%d\n", op(1, 2)); // -1
}qsort 接受函数指针:
int cmp(const void *a, const void *b) {
int x = *(const int *)a;
int y = *(const int *)b;
return (x > y) - (x < y);
}
qsort(arr, n, sizeof(int), cmp);小结
函数是 C 模块化的核心,掌握值传递、指针参数、函数指针后,可以写出灵活的库。下一章学习数组与指针。