0Pricing
C Academy · 课时

传递函数

将回调作为参数

传递函数 是 CoddyKit 上的免费 C Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C Academy 课程共包含 4 节课。

将函数作为参数

由于函数指针只是一个值,因此您可以将一个函数传入另一个函数。接收的这个函数称为回调函数。

这样,一个例程就可以定制其部分行为。

#include <stdio.h>

int apply(int x, int (*f)(int)) {
    return f(x);
}

int square(int x) { return x * x; }

int main(void) {
    printf("%d\n", apply(6, square));
    return 0;
}

回调参数

回调参数的声明方式与函数指针变量完全相同。在函数内部,您可以像调用普通函数一样调用它。

#include <stdio.h>

void run_twice(void (*action)(void)) {
    action();
    action();
}

void beep(void) { printf("beep\n"); }

int main(void) {
    run_twice(beep);
    return 0;
}

替换行为

传入不同的回调函数,就可以让同一个高阶函数产生不同的结果。

#include <stdio.h>

int combine(int a, int b, int (*op)(int, int)) {
    return op(a, b);
}

int add(int a, int b) { return a + b; }
int mul(int a, int b) { return a * b; }

int main(void) {
    printf("%d\n", combine(3, 4, add));
    printf("%d\n", combine(3, 4, mul));
    return 0;
}

映射数组

map函数会对数组中的每个元素应用回调函数,并直接修改数组。

#include <stdio.h>

void map(int *a, int n, int (*f)(int)) {
    for (int i = 0; i < n; i++) a[i] = f(a[i]);
}

int inc(int x) { return x + 1; }

int main(void) {
    int a[] = {1, 2, 3};
    map(a, 3, inc);
    for (int i = 0; i < 3; i++) printf("%d ", a[i]);
    printf("\n");
    return 0;
}

使用谓词进行筛选

谓词是一个返回真或假的回调函数。您可以用它统计或选择符合条件的元素。

#include <stdio.h>

int count_if(int *a, int n, int (*pred)(int)) {
    int c = 0;
    for (int i = 0; i < n; i++) if (pred(a[i])) c++;
    return c;
}

int is_even(int x) { return x % 2 == 0; }

int main(void) {
    int a[] = {1,2,3,4,5,6};
    printf("%d\n", count_if(a, 6, is_even));
    return 0;
}

归约为一个值

归约函数使用二元回调函数和初始累加值,将数组折叠为一个值。

#include <stdio.h>

int reduce(int *a, int n, int init, int (*op)(int,int)) {
    int acc = init;
    for (int i = 0; i < n; i++) acc = op(acc, a[i]);
    return acc;
}

int add(int a, int b) { return a + b; }

int main(void) {
    int a[] = {1,2,3,4};
    printf("%d\n", reduce(a, 4, 0, add));
    return 0;
}

传入比较函数

排序和搜索通常会接收一个比较回调函数,这样同一个算法就能适用于任意排序规则。

#include <stdio.h>

int max_by(int a, int b, int (*greater)(int,int)) {
    return greater(a, b) ? a : b;
}

int gt(int a, int b) { return a > b; }

int main(void) {
    printf("%d\n", max_by(3, 8, gt));
    return 0;
}

使用 typedef 定义回调类型

使用typedef为回调类型命名,可以让函数签名更易读。

#include <stdio.h>

typedef int (*IntFn)(int);

int apply(int x, IntFn f) { return f(x); }

int neg(int x) { return -x; }

int main(void) {
    printf("%d\n", apply(5, neg));
    return 0;
}

默认回调行为

如果回调函数可能为NULL,请提供默认行为,让调用者可以选择不提供回调。

#include <stdio.h>

int apply(int x, int (*f)(int)) {
    if (f == NULL) return x;
    return f(x);
}

int dbl(int x) { return x * 2; }

int main(void) {
    printf("%d\n", apply(9, NULL));
    printf("%d\n", apply(9, dbl));
    return 0;
}

回调函数实现代码解耦

回调函数让通用算法不必依赖具体操作。库提供循环逻辑,而您提供具体行为。

#include <stdio.h>

void for_each(int *a, int n, void (*visit)(int)) {
    for (int i = 0; i < n; i++) visit(a[i]);
}

void show(int x) { printf("[%d]", x); }

int main(void) {
    int a[] = {7, 8, 9};
    for_each(a, 3, show);
    printf("\n");
    return 0;
}

在运行时选择回调函数

将条件选择与传递结合起来:先选择一个回调函数,再将它交给高阶函数。

#include <stdio.h>

int apply(int x, int (*f)(int)) { return f(x); }
int sq(int x) { return x * x; }
int cube(int x) { return x * x * x; }

int main(void) {
    int power = 3;
    int (*f)(int) = (power == 2) ? sq : cube;
    printf("%d\n", apply(2, f));
    return 0;
}

快速检查

请检验您对传递函数的理解。

回顾

您已经学会了将函数作为回调函数传递:

  • 像声明函数指针一样声明回调参数。
  • 构建 map、filter、reduce 和 for_each 等高阶函数。
  • 使用typedef为回调类型命名。
  • 为NULL回调函数提供默认行为。

常见问题解答

「传递函数」课时是免费的吗?

是的 — 「传递函数」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C Academy 课程的其余内容,请升级到 CoddyKit PRO。 C Academy 课程共包含 4 节课。

「传递函数」这节课中我会学到什么?

将回调作为参数 你通过在浏览器中直接运行的动手代码来练习 C Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「传递函数」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C Academy 课中编写并运行代码吗?

能。每节 C Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 声明函数指针
  2. 传递函数
  3. 使用比较器调用 qsort
  4. 函数指针表
← 返回 C Academy