函数

翻译整理自 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 模块化的核心,掌握值传递、指针参数、函数指针后,可以写出灵活的库。下一章学习数组与指针。