10.ポインタ

10-13. ポインタ関数

◇ポインタ関数

前回までポインタのポインタやポインタ配列、配列のポインタとやってきてさらにポインタ関数・・・。やっかいですね。

正式にはポインタ型関数と呼ぶようです。似たようなものに関数のポインタがあり、前回のポインタ配列、配列のポインタのような関係のように見えますがこれがまた、説明しにくいものなので、まずはポインタ型関数からやっていきます。

ポインタ型関数を簡単に説明しますと『戻り値がポインタ』である関数です。
戻り値がポインタ???となるとわけわからなくなるのではっきり申しますと『戻り値がポイント先のアドレス』のことを言います。

#include <stdio.h>

char *string_func(int n);

main()
{
    int     i;
    
    for ( i=1;i< =3;i++){
        printf("String No.%d %s\n",i,string_func(i));
    }
    return 0;
}

char *string_func(int n)
{
    static char *string[] = {
        "",
        "C-Production",
        "Official HomePage",
        "Spring Version"
    };
    return string[n];
}

/* 結果 */
String No.1 C-Production
String No.2 Official HomePage
String No.3 Spring Version

ここで少しポインタ関数の動作について説明します。
main()のprintf文(ステートメント)で string_func(i) として呼び出しています。printfの%sでは文字列の先頭アドレスと対応させれば良いので*(参照演算子)はつけていません。

呼出し後、変数 i の値が string_func() の 変数 n に代入されます。
ここでは例として i は 1 としてみます。

すると、string_func() は戻り値として string[1] つまり”C-Production” という文字列の先頭アドレスを返します。

これが呼び出し側のstring_func()の値となり、文字列の書き出しが行われます。

一応安全性を考えて string[] は static char * 型にしました。
実際は auto でも動作は同じです(ただし暴走する危険性あり)。

識別名でなくアドレス値によってアクセスを行うので関数が終了して auto 変数が開放されても問題ないようです。
ただし、開放された以上、他の変数がその領域を使い始める可能性があるので static にしておいてください。

それではもう一つのサンプル

#include <stdio.h>

int *int_func(int);

main()
{
    printf(" int_func(30) value = %d\n",int_func(30));
    printf("*int_func(30) value = %d\n",*int_func(30));
    return 0;
}

int *int_func(int n)
{
    int *integer;
    integer = &n;
    return integer;
}

/* 結果 */
int_func(30) value = 6618624
*int_func(30) value = 30

*(参照演算子)をつけて呼び出した時とそうでない時で、関数の値はちゃんと対応していますね。
1回目はアドレスの取得
2回目は値の取得