C言語学習ポータル(無料版) 学習コンテンツ 関数とスコープ 値渡しの本質

🧩 関数とスコープ

値渡しの本質

無料公開版に収録・読む目安 13分

🎯 引数はコピーが渡ることを理解し、関数内の変更が呼び出し元に届かない理由を説明できる

このトピックは、第2部のポインタへ続く最重要の伏線です。ここを曖昧にしたままポインタに進むと、必ず迷子になります。

Cの関数に値を渡すと、渡るのは原本ではなくコピーです。書類の原本を手渡すのではなく、コピー機で複製を取って渡すイメージ。これを値渡しと呼びます。

#include <stdio.h>

void add_ten(int n)
{
    n = n + 10;          // 手元のコピーを書き換えただけ
    printf("%d\n", n);   // 15
}

int main(void)
{
    int n = 5;
    add_ten(n);
    printf("%d\n", n);   // 5 のまま!
    return 0;
}

add_ten の中の n と main の n は、名前が同じでも別の箱です。前のトピックのコールスタックで言えば、add_ten のフレームに新しく作られた n に、main の n の値 5 が写し取られただけ。フレームが降ろされれば、書き換えた 15 ごと消えてしまいます。

int も double も char も、引数は例外なくコピーされます。第3部で学ぶ構造体のような大きなデータでも、まるごと写しが取られます。渡す=写す。これがCの基本ルールです。

有名なのが「入れ替え関数が動かない」問題です。

#include <stdio.h>

void swap(int a, int b)   // これは動かない
{
    int t = a;
    a = b;
    b = t;
}

int main(void)
{
    int x = 3, y = 7;
    swap(x, y);
    printf("%d %d\n", x, y);   // 3 7(入れ替わらない)
    return 0;
}

コピーどうしをどれだけ丁寧に入れ替えても、原本は無傷です。

では、どうすれば原本を変えられるのか

方法は2つあります。ひとつは、結果を戻り値で返して呼び出し元が代入し直すこと。もうひとつが、原本の置き場所(番地)を渡すこと。後者がポインタで、第2部の主役になります。

int add_ten(int n)      // 値を返す形なら意図どおり動く
{
    return n + 10;
}
// 呼び出し側: n = add_ten(n);

関数から結果を持ち帰る3つの手

  1. 戻り値で返す(いまできる方法。いちばん安全で分かりやすい)
  2. 原本の番地を渡して直接書き換えてもらう(第2部・ポインタ)
  3. グローバル変数を共有する(追跡しづらいので最後の手段)

初学のうちは1番だけで十分です。「戻り値は1つしか返せないのに、3つの値を更新したい」——そんな場面に出会ったとき、2番が必要になる理由が実感として分かります。

罠・注意

師範関数に渡るのは値の写しじゃ。写しをいくら書き換えても、原本は変わらん

ここまでの話をひとことにすると、「関数の中と外は、値でしかつながっていない」ということです。第2部でポインタを学ぶと、このつながり方に新しい選択肢が加わります。そのとき「なぜわざわざ番地を渡すのか」で悩まないために、いまは値渡しの動きだけをしっかり身体に入れておいてください。

まとめ: 引数はコピー。関数の中の変更は呼び出し元に届きません。届けたいなら「返す」か「番地を渡す」。この一文が、ポインタ理解の土台になります。

要点まとめ

アプリで演習問題まで解く(無料・登録不要)

この項目に出てくる用語

引数ひきすう

関数を呼び出すときに渡す値のこと。関数の中ではその値を使って処理を行う、外から中への入力口としての役割を果たす。渡す引数の順番や型は、関数側の仮引数の並びに合わせる必要がある。

戻り値もどりち

関数が処理を終えたときに、呼び出し元へ返す結果の値のこと。returnというキーワードを使って、その値を指定する。戻り値の型は関数の宣言部分(int func(...)のintの部分)で決まる。

コールスタックこーるすたっく

関数が呼び出されるたびに積み上がっていく、実行中の関数の記録のこと。関数から戻ると一番上から取り除かれる、積み木のような仕組み。スタックオーバーフローは、この積み重ねが限界を超えたときに起きる。

同じトラックのほかの項目

関数とは——処理に名前を付ける関数の役割と基本の書き方が分かり、自分で作った関数を呼び出せる 引数と戻り値引数で値を受け取り、returnで結果を返す関数を書ける プロトタイプ宣言プロトタイプ宣言の役割を理解し、関数を好きな順番で書けるようになる 変数のスコープ——見える範囲ブロックごとのスコープを理解し、変数がどこから見えるか判断できる 変数の寿命とstatic自動変数とstatic変数の寿命の違いを説明でき、使い分けられる コールスタック——関数呼び出しの舞台裏関数呼び出しでスタックフレームが積まれ、戻るときに降ろされる流れを説明できる グローバル変数との付き合い方グローバル変数の性質と危険を理解し、使いどころを判断できる 関数分割の設計センス1関数1仕事の原則で、長い処理を読みやすい関数に分けられる 再帰の入口——自分を呼ぶ関数再帰の2要素(停止条件と縮小)を理解し、階乗を再帰で書ける
‹ コールスタック——関数呼び出しの舞台裏 グローバル変数との付き合い方 ›

もっと先へ:ポインタ・メモリ・ファイル入出力・セキュアコーディングを含む全26トラックと、段位検定・模試のフルセットは完全版に収録しています。

完全版(BOOTH)を見る

📚 姉妹教材:手を動かして覚える Linux 教材 — Linuxとインフラの仕組みを地図で学ぶ

Web版 / BOOTH