工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Industrial programming >> C言語

C 言語の関数ポインタ: 実践例とベストプラクティス

関数ポインタは C 言語で強力な機能を解き放ち、関数が値をコピーする代わりにメモリアドレスを通じてデータを直接操作できるようにします。ポインタパラメータにアドレスを渡すことで、関数は元の変数を変更でき、インプレーススワップ、動的コールバック、高階関数などのパターンを実現します。

関数ポインタの例

古典的な swap ルーチンは、関数が 2 つの変数の値をそれらのアドレスを操作することで交換する方法を示しています。

void swap(int *a, int *b);
int main() {
    int m = 25;
    int n = 100;
    printf("m is %d, n is %d\n", m, n);
    swap(&m, &n);
    printf("m is %d, n is %d\n", m, n);
    return 0;
}
void swap(int *a, int *b) {
    int temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

出力:

m is 25, n is 100
m is 100, n is 25

C 言語の関数ポインタ: 実践例とベストプラクティス

  1. 2 つの整数ポインタで swap を宣言。
  2. main で m と n を初期化し出力。
  3. swap(&m, &n) でアドレスを渡す。
  4. swap 内で一時変数を使って値を交換。
  5. ポインタを逆参照して実際のデータを読み書き。

配列パラメータを持つ関数

配列は関数に渡されるとポインタに減衰します。次のプログラムは、ポインタを介して配列の要素を反復処理し、合計を求めます。

int add_array(int *a, int num_elements);
int main() {
    int Tab[5] = {100, 220, 37, 16, 98};
    printf("Total summation is %d\n", add_array(Tab, 5));
    return 0;
}
int add_array(int *p, int size) {
    int total = 0;
    for (int k = 0; k < size; k++) {
        total += p[k]; /* total += *p; p++; と等価 */
    }
    return total;
}

出力:

Total summation is 471

C 言語の関数ポインタ: 実践例とベストプラクティス

  1. add_array をポインタとサイズを受け取り合計を返すように定義。
  2. 配列名 Tab (ポインタに減衰) とその長さを関数に渡す。

配列を返す関数

関数は静的配列へのポインタを返すことができます。このアプローチは、呼び出し側がメモリ割り当てを管理せずに一時的な配列を必要とする場合に有用です。

#include <stdio.h>
int *build_array();
int main() {
    int *a;
    a = build_array(); /* 最初の 5 個の偶数を取得 */
    for (int k = 0; k < 5; k++) printf("%d\n", a[k]);
    return 0;
}
int *build_array() {
    static int Tab[5] = {1,2,3,4,5};
    return Tab;
}

出力:

1 2 3 4 5

C 言語の関数ポインタ: 実践例とベストプラクティス

  1. 静的配列へのポインタを返す関数を宣言。
  2. 返されたポインタを使用して配列内容を反復出力。

関数ポインタ

関数ポインタは関数のエントリーポイントのアドレスを保持し、動的ディスパッチとコールバックを可能にします。アスタリスクを括弧で囲む宣言構文が必要です (そうでないと誤解釈されるため)。

return_type (*function_name)(arguments)

例: ポインタ経由でルーチンを呼び出し。

#include <stdio.h>
void Hi_function(int times); /* 関数 */
int main() {
    void (*function_ptr)(int); /* 関数ポインタ */
    function_ptr = Hi_function; /* 代入 */
    function_ptr(3); /* 呼び出し */
    return 0;
}
void Hi_function(int times) {
    for (int k = 0; k < times; k++) printf("Hi\n");
}

出力:

Hi
Hi
Hi

C 言語の関数ポインタ: 実践例とベストプラクティス

  1. 通常の関数を定義。
  2. 正しいシグネチャで関数ポインタを宣言。
  3. ポインタに関数名を代入。
  4. ポインタ経由で関数を呼び出し。

関数ポインタの配列

複数の関数ポインタを配列に格納すると、switch 文のようなテーブル駆動アプローチが可能になります。次のプログラムは簡易電卓を示します。

#include <stdio.h>
int sum(int num1, int num2);
int sub(int num1, int num2);
int mult(int num1, int num2);
int divi(int num1, int num2);
int main() {
    int x, y, choice, result;
    int (*ope[4])(int, int);
    ope[0] = sum;
    ope[1] = sub;
    ope[2] = mult;
    ope[3] = divi;
    printf("Enter two integer numbers: ");
    scanf("%d%d", &x, &y);
    printf("Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: ");
    scanf("%d", &choice);
    result = ope[choice](x, y);
    printf("%d", result);
    return 0;
}
int sum(int x, int y) {return x + y;}
int sub(int x, int y) {return x - y;}
int mult(int x, int y) {return x * y;}
int divi(int x, int y) {return y != 0 ? x / y : 0;}

結果: 13 48 2 を入力 → 624

C 言語の関数ポインタ: 実践例とベストプラクティス

  1. 4 つの算術関数を定義。
  2. 一致するシグネチャで 4 要素の関数ポインタ配列を作成。
  3. 各ポインタを対応する関数に代入。
  4. ユーザーの選択を取得し、選択された関数を呼び出し。

void ポインタを使用する関数

void ポインタはデータへの型に依存しないアクセスを提供します。関数パラメータで使用すると、呼び出し側が正しいキャストを提供する限り、任意のデータ型を受け入れられるルーチンを作成できます。

void *cube(const void *);

例プログラム:

#include <stdio.h>
void* cube(const void* num);
int main() {
    int x = 4;
    int cube_int = (int)cube(&x);
    printf("%d cubed is %d\n", x, cube_int);
    return 0;
}
void* cube(const void *num) {
    int result = (*(int *)num) * (*(int *)num) * (*(int *)num);
    return (void*)result;
}

結果: 4 cubed is 64

C 言語の関数ポインタ: 実践例とベストプラクティス

  1. const void ポインタを受け取り void ポインタを返す関数を定義。
  2. ポインタを int * にキャストして値にアクセス。
  3. 立方を計算し、結果を void * にキャストして返却。

引数としての関数ポインタ

関数ポインタを別の関数に渡すのはコールバックの一般的なパターンです。標準ライブラリの qsort はこの技術を用いて任意の型の配列をソートします。

void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *));

整数配列をソートする例:

#include <stdio.h>
#include <stdlib.h>
int compare(const void *, const void *);
int main() {
    int arr[5] = {52, 14, 50, 48, 13};
    size_t num = sizeof(arr)/sizeof(arr[0]);
    size_t width = sizeof(arr[0]);
    qsort((void *)arr, num, width, compare);
    for (size_t i = 0; i < num; i++) printf("%d ", arr[i]);
    return 0;
}
int compare(const void *elem1, const void *elem2) {
    int a = *(int *)elem1;
    int b = *(int *)elem2;
    return (a - b);
}

結果: 13 14 48 50 52

C 言語の関数ポインタ: 実践例とベストプラクティス

  1. compare を実装し、2 つの整数に基づいて負/零/正を返す。
  2. sizeof で配列サイズと要素幅を決定。
  3. 配列、要素数、幅、比較関数で qsort を呼び出し。
  4. ソート済み配列を出力して動作確認。

C言語

  1. C言語ユーザー定義関数の4つの実証済みパターン
  2. C++ do-while文:構文、実践例、ネストしたループ
  3. C++ポインタをマスター:概念、例、実践的応用
  4. C++演算子オーバーロード:コード例付き実践ガイド
  5. C++関数を実例で徹底解説:基本から応用まで
  6. C#コレクション実践チュートリアル:実例で学ぶ柔軟なデータ管理
  7. C 言語ポインタ完全ガイド: 型、使い方、ベストプラクティス
  8. Python str.count()マスター:文字と部分文字列のカウント実例集
  9. Pythonラムダ関数をマスターする:実例とベストプラクティス
  10. Python round()関数を実例で徹底解説
  11. Python map()関数をマスター:構文、例、ベストプラクティス