関数ポインタ
C 言語では、ポインタ関数はポインタを返す関数です。具体的には、ポインター関数は、配列、構造体、関数などの特定の種類のデータへのポインターを返します。
意味:
戻り値の型(*関数名)(パラメータリスト)
ここで、戻り値の型はポインターが指すデータ型、関数名はポインター関数の名前、パラメーター リストはポインター関数によって受け入れられるパラメーター リストであり、空にすることもできます。
以下は、int 型データへのポインタを返す関数の例です。
int *max(int *a, int *b) {
if (*a > *b) {
return a;
} else {
return b;
}
}
上記のコードでは、max という名前のポインタ関数を定義します。この関数は、int 型の 2 つのポインタ a と b をパラメータとして受け取り、int 型のデータへのポインタを返します。関数内ではポインタaとポインタbが指すデータを比較し、aが指すデータがbが指すデータより大きい場合はポインタaを返し、そうでない場合はポインタbを返します。
ポインター関数を使用した例を次に示します。
int main() {
int a = 1, b = 2;
int *p = max(&a, &b);
printf("The maximum value is %d\n", *p);
return 0;
}
上記のコードでは、int 型の 2 つの変数 a と b を定義し、ポインタ関数 max を呼び出し、それらのアドレスをパラメータとして渡します。ポインタ関数は、a と b の大きい方へのポインタを返します。これをポインタ p に割り当て、逆参照して、それが指すデータを出力します。
ポインタ関数によって返されるポインタは、グローバル変数、静的変数、動的メモリによって割り当てられたデータなどを指すことができますが、ローカル変数へのポインタを返すべきではないことに注意してください。ローカル変数が配置されると解放され、その変数へのポインタが無効なポインタになり、未定義の動作やプログラムのクラッシュが発生します。
void 関数ポインタを返す
以下は、無効なポインターを返すポインター関数の例です。
#include <stdio.h>
int *get_array() {
int arr[3] = {
1, 2, 3};
return arr;
}
int main() {
int *ptr = get_array();
printf("%d\n", *ptr);
return 0;
}
上記のコードでは、int 型データへのポインタを返す get_array というポインタ関数を定義しました。関数内で、長さ 3 の int 型の配列 arr を定義し、それをポインターとして返します。ただし、arr は関数内で定義されたローカル変数であるため、関数が復帰すると、arr が配置されていたメモリ空間が解放され、それへのポインタは無効なポインタとなります。
main関数では、ポインタ関数から返されたポインタをポインタ変数ptrに代入し、ポインタが指すデータを出力しようとします。ポインタが無効なポインタとなっているため、プログラムが未定義の結果を出力したり、プログラムがクラッシュしたりする可能性があります。したがって、ポインター関数を作成するときは、ポインターが無効なポインターにならないように、ローカル変数へのポインターを返さないようにする必要があります。
無効なポインタを返す問題を解決する
無効なポインターを返さないようにする例を次に示します。
#include <stdio.h>
#include <stdlib.h>
int *get_array() {
int *arr = malloc(3 * sizeof(int));
if (arr == NULL) {
printf("Memory allocation failed.");
return NULL;
}
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
return arr;
}
int main() {
int *ptr = get_array();
if (ptr == NULL) {
return 1;
}
printf("%d\n", ptr[0]);
free(ptr);
return 0;
}
上記のコードでは、malloc関数サイズ 3 の int 型のメモリ空間をヒープ上に確保し、ポインタとして返します。メモリ空間はヒープ上に確保されるため、関数復帰後にメモリ空間が解放されることはなく、不正なポインタを返すことを回避できます。
main関数では、ポインタ関数から返されたポインタをポインタ変数ptrに代入し、ポインタが指すデータを出力しようとします。ポインタが指すメモリ空間は有効であるため、プログラムはptrが指す最初の要素の値を正しく出力できます。最後に、私たちが使用するのは、無料機能そのメモリ領域を解放します。
したがって、ポインタ関数を作成するときは、無効なポインタが返されないように、ヒープ上にメモリ領域を割り当て、それをポインタとして返すことを検討できます。同時に、メモリリークを避けるために、メモリ空間は使用後に適時に解放される必要があります。