0Pricing
C Academy · レッスン

関数の受け渡し

コールバックを引数にします。

「関数の受け渡し」はCoddyKit上の無料C Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C Academyコースには全4レッスンが含まれています。

引数としての関数

関数ポインタは単なる値なので、関数を別の関数に渡せます。受け取った関数はコールバックと呼ばれます。

これにより、1つの処理の一部の動作をカスタマイズできます。

#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;
}

述語によるフィルタリング

述語とは、trueまたはfalseを返すコールバックです。これを使って、一致する要素を数えたり選択したりできます。

#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;
}

1つの値への畳み込み

reduce関数は、二項コールバックと初期アキュムレーターを使って、配列を1つの値に畳み込みます。

#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コールバックに備えます。

よくある質問

「関数の受け渡し」レッスンは無料ですか?

はい。「関数の受け渡し」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C Academyコースには全4レッスンが含まれています。

「関数の受け渡し」で何を学びますか?

コールバックを引数にします。 ブラウザで直接実行するハンズオンコードでC Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「関数の受け渡し」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC Academyレッスンでコードを書いて実行できますか?

はい。すべてのC Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 関数ポインターの宣言
  2. 関数の受け渡し
  3. 比較関数付き qsort
  4. 関数ポインターテーブル
← C Academyに戻る