値渡しと参照渡し

2018-01-12 (金) 10:08:28 (2286d) | Topic path: Top / 授業 / C言語基礎 / 値渡しと参照渡し

関数に引数を渡す方法には、値渡し参照渡しがあります。

値渡し

関数に値を引数として渡すと、関数は引数を記憶するための領域をメモリー内の別の場所に確保し、受け取った値をそこに代入します。

つまり、呼び出された関数が受け取った引数(変数)は、関数を呼び出したときに渡した引数(変数または定数)とは別の場所に記憶されます。

これを値渡しといいます。

値渡しのとき、呼び出された側で受け取った引数の値を変更しても、呼び出した側が渡した引数の値は変更されません。 これは、別の場所に記憶されている変数の値を変更しているだけだからです。

次のプログラムでは、main関数がinc関数に変数 i を渡し、inc関数が受け取った引数 i の値を 1 増やしていますが、main関数で宣言されている変数 i の値は変わりません(プログラム1)。

/*
 *  受け取った引数の値を1増やして出力する
 */
void inc(int i) {{
  i++;
  printf(">> %d\n", i)
}


int main(void) {
  int i = 0;
  inc(i);  // 変数を渡す
  printf("%d\n", i);
  return 0;
}

このプログラムを実行すると、次のようになります。

luna% a.out
>> 1
0

参照渡し

関数に、変数を記憶している領域のアドレス参照)を渡し、受け取った関数も同じ領域に格納されている変数にアクセスする引数の渡し方を参照渡しといいます

参照渡しのとき、呼び出された側で受け取った引数の値を変更すると、呼び出した側が渡した引数の値も変更されます。 渡した引数と同じアドレスの変数にアクセスし、その値を変えたからです。

C言語の参照渡しは、ポインター型の引数に、変数を記憶している領域のアドレスを渡すことによって行いま す。

ポインターとアドレスについては、C言語応用で勉強する内容なので、ここでは詳しくは説明しません。

配列は参照渡し

配列を関数の引数にすると、配列の要素数は無視されます。

実は、配列を宣言すると、配列名がポインター型の変数となり、配列を記憶している領域の先頭のアドレスを記憶します。

したがって、配列を関数の引数にすることは、ポインター型の引数に配列を記憶している領域の先頭アドレスを渡していることになり、参照渡しと同じになります。

/*
 *  受け取った配列の先頭要素の値を1増やして出力する
 */
void inc(int a[]) {{
  a[0]++;
  printf(">> %d\n", a[0])
}


int main(void) {
  int a[] = { 0 };
  inc(a);  // 配列を渡す
  printf("%d\n", a[0]);
  return 0;
}
luna% a.out
>> 1
1

ポインターによる参照渡し(おまけ)

C言語の参照渡しは、ポインター型の引数に、変数を記憶している領域のアドレスを渡すことによって行います。

ポインターとアドレスについては、C言語応用で勉強する内容なので、ここでは詳しくは説明しません。

/*
 * 参照渡しで受け取った値を1増やす
 */
void inc(int *i) {
  (*i)++;
  printf(">> %d\n", *i);
}


int main(void) {
  int i = 0;
  inc(&i);  // 変数 i のアドレスを渡す
  printf("%d\n", i);
  return 0;
}
luna% a.out
>> 1
1

まとめ

値渡しでは、引数を格納するための記憶領域が新たに確保され、そこに引数の値が代入されます。 値渡しでは、受け取った引数の値を変更しても、引数として渡した変数の値は変更されません。 基本型の変数を引数として関数に渡すと値渡しになります。

参照渡しでは、変数を格納している記憶領域のアドレスが引数として渡されます。 参照渡しでは、受け取ったアドレスに格納されている値を変更すると、引数として私た変数の値も変更されます。 配列を引数として渡すと参照渡しになります。


練習問題

練習問題はこちら

トップ   編集 凍結解除 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS