関数の受け渡し
コールバックを引数にします。
「関数の受け渡し」は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フィードバックを取得できます。ローカル設定は不要です。