Cプログラミング
 Computer >> コンピューター >  >> プログラミング >> Cプログラミング

値渡し(Call by Value)と参照渡し(Call by Reference)の違いを徹底解説


プログラミングにおいて、関数へ引数を渡す方法は大きく分けて2種類あります。それが「値渡し(Call by Value)」「参照渡し(Call by Reference)」です。

名前が示す通り、値渡しでは引数の実際の値そのものを関数に渡すのに対し、参照渡しでは引数のメモリ上の場所(アドレス・参照)を渡します。この違いにより、関数内でのデータの扱いや変更の影響範囲が大きく異なってきます。

以下の表に、値渡しと参照渡しの重要な違いをまとめました。

No.項目値渡し(Call by Value)参照渡し(Call by Reference)
1命名の由来引数の「値」そのものを渡して関数を呼び出すため、「値渡し」と呼ばれます。引数の「参照(アドレス)」を渡して関数を呼び出すため、「参照渡し」と呼ばれます。
2内部的な仕組み関数呼び出し時に渡された引数の値は、関数内のローカルな仮引数にコピーされます。渡された引数のアドレス(参照)が仮引数にコピーされるため、実引数と仮引数は同じメモリ位置を共有します。
3変更の影響値がコピーされるだけなので、関数内で仮引数を変更しても、呼び出し元の実引数には一切影響しません実引数と仮引数が同じ場所を参照しているため、関数内での変更が呼び出し元にも反映されます
4参照するメモリ領域実引数と仮引数が参照するメモリ領域は別々です。実引数と仮引数が参照するメモリ領域は同一です。
5対応している主な言語C、C++、PHP、Visual Basic .NET、C# など、ほぼすべての主要言語が標準的な引数渡しとして採用しています。C++(参照型)、PHP(&付き引数)、Perl、Visual Basic .NET(ByRef)、C#(ref/out キーワード)などが明示的にサポートしています。

補足: Java は常に値渡しとして動作します。オブジェクトを渡す場合も、オブジェクトへの参照という「値」がコピーされるため、厳密には参照渡しではありません。これは多くの開発者が混同しやすいポイントなので注意が必要です。

値渡しと参照渡しのサンプルコード

ここでは、2つの整数の値を入れ替える(スワップする)例を使って、両者の違いを確認してみましょう。

例1:値渡しの場合

by_value.c

#include <stdio.h>

/* プロトタイプ宣言 */
void swapByValue(int a, int b);

int main(void) {
    int n1 = 10, n2 = 20;
    swapByValue(n1, n2);
    printf("n1: %d, n2: %d\n", n1, n2);
    return 0;
}

/* 値渡しによる入れ替え */
void swapByValue(int a, int b) {
    int t;
    t = a; a = b; b = t;
}

実行結果

n1: 10, n2: 20

このように、関数内で ab の値を入れ替えても、n1 と n2 の値は元のまま変化していません。これは、値がコピーされただけであり、関数内の仮引数 ab と呼び出し元の n1n2 はまったく別のメモリ領域にあるためです。

例2:参照渡し(ポインタ)の場合

by_reference.c

#include <stdio.h>

/* プロトタイプ宣言 */
void swapByReference(int *a, int *b);

int main(void) {
    int n1 = 10, n2 = 20;
    swapByReference(&n1, &n2);
    printf("n1: %d, n2: %d\n", n1, n2);
    return 0;
}

/* 参照渡し(ポインタ)による入れ替え */
void swapByReference(int *a, int *b) {
    int t;
    t = *a; *a = *b; *b = t;
}

実行結果

n1: 20, n2: 10

今度は n1 と n2 の値が正しく入れ替わりました& 演算子で変数のアドレスを渡し、関数側ではポインタ経由でそのメモリ領域を直接操作しているためです。

まとめ

値渡しは呼び出し元のデータが保護されるため安全性が高い一方、大きなデータを扱う場合はコピーのコストが発生します。一方、参照渡しはコピー不要で効率的ですが、意図しない副作用が起きる可能性があるため、使いどころを見極めることが重要です。用途に応じて適切な引数渡しを選択しましょう。

  1. JavaScriptで「2乗の和」と「和の2乗」の差を求める方法

    数値 n を唯一の引数として受け取るJavaScript関数を作成することを考えます。この関数は、以下の3つの処理を行います。最初のn個の自然数の2乗の和(1² + 2² + … + n²)を計算する最初のn個の自然数の和の2乗((1 + 2 + … + n)²)を計算する両者の差の絶対値を返す例として、n = 5 の場合を確認してみましょう。2乗の和 = 1 + 4 + 9 + 16 + 25 = 55 和の2乗 = (1 + 2 + 3 + 4 + 5)² = 15 × 15 = 225したがって、出力結果は 225 − 55 = 170 となります。実装コードこの問題を解くJavaScr

  2. CellpaddingとCellspacingの違いとは?HTMLテーブルの余白設定をわかりやすく解説

    HTMLで表(テーブル)を作成する際、セル内やセル同士の余白を調整したい場面は多くあります。そのときに登場するのが「cellpadding」と「cellspacing」という2つの属性です。名前は似ていますが、役割はまったく異なります。本記事では、それぞれの特徴と具体的な使い方、そして両者の違いについて詳しく解説します。Cellpadding(セルパディング)とは単一のセルに対して作用する属性です。セルの枠線(ボーダー)とセル内のコンテンツ(文字や画像など)との間の余白を調整します。デフォルト値は1(ピクセル)です。コンテンツが枠に密着して見づらくなるのを防げるため、視認性向上に効果的な手法と