★関数(引数と戻り値3)★


引数として「値渡し」と「アドレス渡し」があることは説明しました。

では戻り値としてはどうでしょうか?

次のような関数があるとします。

関数名 Counter

機 能 渡された値に1を加えた値を返す

引 数 int型の数値(変数名はvalue)

戻り値 int型の数値(valueに1を加えた値)

本体を書くと、

int Counter(int value)
{
    return value + 1;
}

このようになるでしょうか。

この関数に1を渡せば2が、2を渡せば3が返ってきます。

明らかに「値」が返ってきています。


では、「アドレス」は返せるのでしょうか?

答えは、「返せます」です。

戻り値に、「int*」と書けば「int型のアドレスを返す」という意味になります。

ただ、気を付けて欲しいことがあります。

関数内で宣言された変数は、関数の実行が終わり次第、解放されるということです。

変数が宣言された時点では、そのメモリ領域が確保され、他のプログラムなどが使えないように保護されます。

解放されるということは、保護が外れ、他のプログラムがそのメモリ領域を確保する可能性があります。


テストするためのプログラムを作ってみましょう。

<sample program 136-01>

#include <stdio.h>

void Display(int value);

int main(void)
{
    Display(123);

    return 0;
}

void Display(int value)
{
    printf("value = %d\n", value);
}

<実行結果>

value = 123
続行するには何かキーを押してください・・・

とりあえず、int型の値を受け取り表示するDisplay関数を作りました。

引数を受け取るため、int型で変数valueを用意しています。

このvalueにも、当然アドレスが存在します。

確認してみましょう。

<sample program 136-02>

#include <stdio.h>

void Display(int value);

int main(void)
{
    Display(123);

    return 0;
}

void Display(int value)
{
    printf("value address = %p\n", &value);

    printf("value = %d\n", value);
}

<実行結果>

value address = 00D7F660
value = 123
続行するには何かキーを押してください・・・

※実行結果(アドレス部分)は毎回変わる可能性があります。


このように変数valueにもアドレスが存在していますので、そのアドレスを返すことも可能です。

Display関数の戻り値を「void」から「int*」に変更して、変数valueのアドレスを返すように変更してみます。

main関数では、戻ってきたアドレスをポインタ変数pValueで受け取るようにします。

きちんと受け取れているかどうか調べるため、pValueの中身を表示するようにしましょう。

<sample program 136-03>

#include <stdio.h>

int* Display(int value);

int main(void)
{
    int *pValue;

    pValue = Display(123);

    printf("pValue = %p\n", pValue);

    return 0;
}

int* Display(int value)
{
    printf("value address = %p\n", &value);

    printf("value = %d\n", value);

    return &value;
}

コンパイルした時点で↓のような警告が出ました。

  warning C4172: ローカル変数またはテンポラリのアドレスを返します: value

これは、関数が終わったら解放される変数のアドレスを返すのは危険!ということです。

ただし、警告なので一応は実行可能です。

やってみましょう。

<実行結果>

value address = 00B9FD88
value = 123
pValue = 00B9FD88
続行するには何かキーを押してください・・・

※実行結果(アドレス部分)は毎回変わる可能性があります。


pValueの中身は変数valueのアドレスが入っていることが確認出来ました。

では、pValueに入っているアドレスを使って間接的に変数valueの中身を見れるかどうか試します。

警告は無視して実行してみてください。

<sample program 136-04>

#include <stdio.h>

int* Display(int value);

int main(void)
{
    int *pValue;

    pValue = Display(123);

    printf("pValue = %p\n", pValue);

    printf("*pValue = %d\n", *pValue);

    return 0;
}

int* Display(int value)
{
    printf("value address = %p\n", &value);

    printf("value = %d\n", value);

    return &value;
}

<実行結果>

value address = 00B9FDBC
value = 123
pValue = 00B9FDBC
*pValue = 12189116
続行するには何かキーを押してください・・・

※実行結果(アドレス部分)は毎回変わる可能性があります。


「*pValue」と書くことで、変数valueの中身を扱うことが出来ますが、「123」は入っていませんでした。

これは、すでに変数valueは解放され、他のプログラムが中身を書き換えたということでしょう。

つまり、解放された変数のアドレスを扱うのは危険であり、やってはならないことだということです。

このように、解放された変数のアドレスを指すポインタ変数を「ダングリングポインタ」と言います。

非常に危険な状態なので、絶対に避けなければなりません。


では、アドレスを返すプログラムは書いてはならないのか、というとそうでもありません。

次回は、以前紹介した標準関数からアドレスを返すプログラムを見てみましょう。


次へ

戻る

目次へ