関数ポインターテーブル
ディスパッチパターンです。
「関数ポインターテーブル」はCoddyKit上の無料C Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C Academyコースには全4レッスンが含まれています。
関数のテーブル
関数ポインタを配列に格納すると、ディスパッチテーブルを作成できます。インデックスやコードで実行する関数を選べるため、長いif-elseやswitchの連鎖を置き換えられます。
#include <stdio.h>
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int main(void) {
int (*ops[2])(int,int) = { add, sub };
printf("%d\n", ops[0](5, 3));
printf("%d\n", ops[1](5, 3));
return 0;
}テーブルのインデックス指定
配列のインデックスによって、実行時に操作を選択します。インデックスはユーザー入力やプログラムの状態から取得できます。
#include <stdio.h>
int mul(int a, int b) { return a * b; }
int add(int a, int b) { return a + b; }
int main(void) {
int (*ops[2])(int,int) = { add, mul };
int choice = 1;
printf("%d\n", ops[choice](6, 7));
return 0;
}switchの置き換え
各caseが関数を呼び出すだけなら、ディスパッチテーブルのほうがswitchよりすっきりすることがよくあります。
#include <stdio.h>
void start(void) { printf("start\n"); }
void stop(void) { printf("stop\n"); }
void pause(void) { printf("pause\n"); }
int main(void) {
void (*table[3])(void) = { start, stop, pause };
for (int i = 0; i < 3; i++) table[i]();
return 0;
}typedefでテーブルを整理する
関数ポインタ型にtypedefを使うと、テーブルの宣言を短く読みやすくできます。
#include <stdio.h>
typedef int (*BinOp)(int,int);
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int main(void) {
BinOp ops[] = { add, sub };
printf("%d\n", ops[0](10, 4));
return 0;
}シンボルを関数に対応付ける
各演算子記号を対応する関数と並列配列または構造体テーブルに格納し、名前から検索できるようにします。
#include <stdio.h>
typedef int (*BinOp)(int,int);
int add(int a, int b){return a+b;}
int sub(int a, int b){return a-b;}
int main(void) {
char syms[] = {'+', '-'};
BinOp ops[] = { add, sub };
char want = '-';
for (int i = 0; i < 2; i++)
if (syms[i] == want) printf("%d\n", ops[i](9, 2));
return 0;
}構造体ベースのコマンドテーブル
名前とハンドラーを構造体にまとめ、それらの配列を作成します。これは典型的なコマンドテーブルパターンです。
#include <stdio.h>
#include <string.h>
typedef struct {
const char *name;
void (*run)(void);
} Command;
void hello(void){printf("hi\n");}
void bye(void){printf("bye\n");}
int main(void) {
Command cmds[] = {{"hello", hello}, {"bye", bye}};
const char *input = "bye";
for (int i = 0; i < 2; i++)
if (strcmp(cmds[i].name, input) == 0) cmds[i].run();
return 0;
}境界チェック
テーブルを通して関数を呼び出す前に、必ずインデックスを検証し、配列の範囲外を読み取らないようにしてください。
#include <stdio.h>
typedef int (*Fn)(int);
int sq(int x){return x*x;}
int neg(int x){return -x;}
int main(void) {
Fn table[] = { sq, neg };
int n = 2;
int idx = 5;
if (idx >= 0 && idx < n) printf("%d\n", table[idx](3));
else printf("index out of range\n");
return 0;
}状態機械
ディスパッチテーブルは状態機械を動かします。各状態は関数ポインタで表され、ハンドラーは次の状態のインデックスを返します。
#include <stdio.h>
int state_a(void){ printf("A\n"); return 1; }
int state_b(void){ printf("B\n"); return -1; }
int main(void) {
int (*states[2])(void) = { state_a, state_b };
int s = 0;
while (s >= 0) s = states[s]();
return 0;
}プラグイン風のディスパッチ
ハンドラーをテーブルに登録しておくと、大きなswitchを編集する代わりにエントリを追加するだけで新しい動作を追加できます。
#include <stdio.h>
typedef void (*Handler)(int);
void log_low(int v){printf("low %d\n", v);}
void log_high(int v){printf("high %d\n", v);}
int main(void) {
Handler handlers[] = { log_low, log_high };
int level = 1;
handlers[level](7);
return 0;
}デフォルトハンドラー
未知のコードでもディスパッチが黙って失敗しないように、1つのスロットまたはフォールバック用ポインタを用意してください。
#include <stdio.h>
typedef void (*Fn)(void);
void known(void){printf("known\n");}
void fallback(void){printf("unknown command\n");}
int main(void) {
Fn table[] = { known };
int n = 1, code = 9;
Fn f = (code >= 0 && code < n) ? table[code] : fallback;
f();
return 0;
}テーブルが拡張しやすい理由
ディスパッチテーブルを使うと、分岐ロジックをデータ検索に変えられます。ケースの追加がデータの追加になるため、コードを平坦で高速に保てます。
#include <stdio.h>
typedef int (*Fn)(int);
int a(int x){return x+1;}
int b(int x){return x*2;}
int c(int x){return x*x;}
int main(void) {
Fn t[] = { a, b, c };
for (int i = 0; i < 3; i++) printf("%d ", t[i](4));
printf("\n");
return 0;
}理解度チェック
関数ポインタテーブルについての理解度を確認しましょう。
まとめ
関数ポインタテーブルを使ったディスパッチパターンを学びました。
- 関数ポインタを配列に格納し、インデックスで選択します。
- 長いswitchの連鎖を置き換え、データを追加することで拡張できます。
typedefと構造体のコマンドテーブルを使って、コードを明確にします。- 必ずインデックスの範囲を確認し、デフォルトハンドラーを用意してください。
よくある質問
「関数ポインターテーブル」レッスンは無料ですか?
はい。「関数ポインターテーブル」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C Academyコースには全4レッスンが含まれています。
「関数ポインターテーブル」で何を学びますか?
ディスパッチパターンです。 ブラウザで直接実行するハンズオンコードでC Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「関数ポインターテーブル」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC Academyレッスンでコードを書いて実行できますか?
はい。すべてのC Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 関数ポインターの宣言
- 関数の受け渡し
- 比較関数付き qsort
- 関数ポインターテーブル