カテゴリ: C++ 更新日: 2026/04/06

C++の値渡し(pass by value)とは?仕組みと使い方を初心者向けに徹底解説

値渡し (pass by value) の仕組み
値渡し (pass by value) の仕組み

先生と生徒の会話形式で理解しよう

生徒

「関数に数字を渡して計算してもらったのに、元の数字が変わっていないんです。これって故障ですか?」

先生

「それは故障ではなく、C++の『値渡し』という仕組みが動いているからですよ。」

生徒

「アタイワタシ……?なんだか難しそうな名前ですね。具体的にどういうことなんですか?」

先生

「一言で言うと『データのコピー』を渡しているんです。それでは、図解するように分かりやすく解説していきますね!」

1. 値渡し(あたいわたし)の正体は「コピー」

1. 値渡し(あたいわたし)の正体は「コピー」
1. 値渡し(あたいわたし)の正体は「コピー」

プログラミングの世界で関数にデータを与えるとき、一番基本となるのが値渡し(あたいわたし)です。英語では「pass by value」と呼びます。パソコンを全く触ったことがない方でも、学校の宿題を想像すればすぐに理解できます。

あなたが持っているノートの宿題を、友達に見せてあげるとしましょう。このとき、自分のノートそのものを渡すのではなく、コピー機でコピーした紙を渡すのが「値渡し」です。友達がそのコピーされた紙に落書きをしたり、答えを書き換えたりしても、あなたの手元にある「元のノート」は綺麗なままですよね。これと同じことが、C++のプログラムの中でも起きているのです。

値渡しを行うと、関数の中でどんなにデータを加工しても、呼び出し元の元のデータには一切影響を与えません。これは、プログラムの安全性を高めるためにとても重要な仕組みなのです。

2. 変数と引数の役割を整理しよう

2. 変数と引数の役割を整理しよう
2. 変数と引数の役割を整理しよう

ここで少し、難しい言葉の整理をしましょう。プログラムでデータを一時的に保存しておく箱のことを変数(へんすう)と呼びます。そして、その箱の中身を関数に放り込むときの入り口のことを引数(ひきすう)と言います。漢字が難しいですが、「引く数」と書いて、関数に引き込むための材料だとイメージしてください。

値渡しでは、メインの処理で使っている変数の「中身」だけを、関数の入り口にある新しい箱にコピーします。つまり、箱そのものを共有しているわけではなく、全く同じ見た目の「別々の箱」が二つ存在することになります。この「別々である」という感覚が、C++をマスターするための第一歩です。

3. 値渡しのプログラムを見てみよう

3. 値渡しのプログラムを見てみよう
3. 値渡しのプログラムを見てみよう

実際に、関数の中で数字を書き換えても元の数字が変わらない様子を、コードで確認してみましょう。以下の例では、レベルアップという関数を作っていますが、元のレベルはそのまま維持されます。


#include <iostream>

// レベルを増やす関数(値渡し)
void levelUp(int lv) {
    lv = lv + 1; // 箱の中身を1増やす
    std::cout << "関数の中のレベル: " << lv << std::endl;
}

int main() {
    int currentLevel = 10;
    
    // 関数を呼び出す(コピーが渡される)
    levelUp(currentLevel);
    
    // 元のレベルはどうなっているか?
    std::cout << "元の場所のレベル: " << currentLevel << std::endl;
    
    return 0;
}

関数の中のレベル: 11
元の場所のレベル: 10

実行結果を見て驚いたかもしれません。関数の中でレベルは「11」になりましたが、メインの処理(main関数)に戻ってくると、元の「10」のままです。これが「コピーを渡している」証拠です。

4. メモリとコピーの仕組み(専門用語解説)

4. メモリとコピーの仕組み(専門用語解説)
4. メモリとコピーの仕組み(専門用語解説)

ここで、少しだけ専門的なお話をします。パソコンの中にはメモリという、作業用の机のような場所があります。プログラムが動くとき、変数はこのメモリの上に「場所」を確保します。専門用語で、この場所の番地のことを「アドレス」と呼びます。

値渡しが行われるとき、コンピュータは「新しい机のスペース」を確保し、そこに元のデータをせっせと書き写します。新しい場所で何が起きても、古い場所には関係ありません。この「新しく場所を作る」という作業があるため、あまりにも巨大なデータ(例えば何千ページもある百科事典のようなデータ)を何度も値渡しすると、コピーに時間がかかり、パソコンの動作が少し重くなることがあります。しかし、数字や短い文字であれば、全く気にする必要はありません。

5. 複数の値を渡すパターンの例

5. 複数の値を渡すパターンの例
5. 複数の値を渡すパターンの例

関数には、一つの材料だけでなく、たくさんの材料(引数)を渡すことができます。次の例では、初期の体力と受けたダメージを渡して、計算を行うプログラムを作成します。もちろん、これも値渡しなので、元の体力が勝手に削られることはありません。


#include <iostream>

// ダメージ計算をする関数(二つの値をコピーして受け取る)
void calculateDamage(int hp, int damage) {
    hp = hp - damage;
    std::cout << "計算後の体力(関数内): " << hp << std::endl;
}

int main() {
    int myHp = 100;
    int enemyAttack = 30;

    calculateDamage(myHp, enemyAttack);

    std::cout << "現在の残り体力(元の変数): " << myHp << std::endl;
    
    return 0;
}

計算後の体力(関数内): 70
現在の残り体力(元の変数): 100

このように、複数の引数を使っても、それぞれの変数が個別にコピーされる仕組みは変わりません。関数の中でどんなに激しいバトルが行われても、元のmyHpという箱は守られているのです。

6. 文字列(文章)の値渡しに挑戦

6. 文字列(文章)の値渡しに挑戦
6. 文字列(文章)の値渡しに挑戦

数字だけでなく、文字の塊である文字列(string)も値渡しが可能です。文字列を扱うときは、C++ではstd::stringという型を使います。名前を少し加工して表示する関数を作ってみましょう。元の名前が書き換わらない安心感を確認してください。


#include <iostream>
#include <string>

// 名前に敬称をつける関数
void addSan(std::string name) {
    name = name + "さん";
    std::cout << "呼び出し中: " << name << std::endl;
}

int main() {
    std::string myName = "太郎";

    addSan(myName);

    std::cout << "登録されている名前: " << myName << std::endl;

    return 0;
}

呼び出し中: 太郎さん
登録されている名前: 太郎

「太郎さん」という新しい文字列が関数の中で作られましたが、元のmyNameは「太郎」のままです。このように、データの「原本」を守りたいとき、値渡しは非常に心強い味方になります。

7. 値渡しを使うメリットとデメリット

7. 値渡しを使うメリットとデメリット
7. 値渡しを使うメリットとデメリット

最後に、なぜわざわざコピーなんて面倒なことをするのか、その理由を整理しましょう。プログラミングにおいて、メリットとデメリットを知ることは非常に大切です。

メリット:
何といっても「安全」であることです。関数を作った人と、それを使う人が別人だった場合、勝手に元のデータを変えられてしまうとトラブルの元になります。値渡しなら、関数がどんなに暴走しても元のデータは無事です。また、仕組みがシンプルなので、初心者でもバグ(プログラムのミス)を出しにくいのが特徴です。

デメリット:
「コピーのコスト」がかかることです。先ほど百科事典の例を出しましたが、非常に大きなデータを扱う場合、コピーを作るだけでパソコンのメモリやパワーを消費してしまいます。将来的に、より高度なプログラムを書くようになると「参照渡し」というコピーしない方法も学びますが、まずはこの「安全なコピー」の感覚をしっかりと身につけましょう。

8. 応用編:計算結果を戻り値で受け取る

8. 応用編:計算結果を戻り値で受け取る
8. 応用編:計算結果を戻り値で受け取る

「元の変数が変わらないなら、どうやって計算結果を反映させればいいの?」と思うかもしれません。その答えは、前回の記事でも触れた「戻り値(もどりち)」を使うことです。値渡しでコピーをもらい、計算した結果をまたコピーして返してあげる。これが一番綺麗な流れです。


#include <iostream>

// 値渡しで受け取り、結果を「戻り値」として返す
int doubleScore(int score) {
    return score * 2;
}

int main() {
    int myScore = 50;

    // 関数の結果を、元の変数に上書きする
    myScore = doubleScore(myScore);

    std::cout << "最新のスコア: " << myScore << std::endl;

    return 0;
}

最新のスコア: 100

このプログラムでは、一度コピーされた値を計算し、その答えをmyScoreという箱に「入れ直して」います。これなら、値渡しの安全性を保ちつつ、データを更新することが可能になります。C++の基本は、この「渡して、返してもらう」のキャッチボールにあるのです。

カテゴリの一覧へ
新着記事
New1
C++
C++の値渡し(pass by value)とは?仕組みと使い方を初心者向けに徹底解説
New2
C++
C++とポインタ・参照の重要性をやさしく解説!初心者でも理解できる仕組みと使い方
New3
C++
GCCでC++開発を始める方法!初心者向け完全ガイド
New4
Rust
Rustの式(Expression)と文(Statement)の違いを徹底解説!初心者が迷うセミコロンの秘密
人気記事
No.1
Java&Spring記事人気No1
C言語
C言語を学ぶ初心者におすすめの環境構築手順【2025年版】
No.2
Java&Spring記事人気No2
C++
MinGWとMSYS2でWindowsにC++環境を構築する方法を徹底解説!初心者でもできるセットアップガイド
No.3
Java&Spring記事人気No3
C言語
LinuxでC言語開発環境を構築する方法【GCCとMakefileの基本】
No.4
Java&Spring記事人気No4
C言語
C言語のソースコードとヘッダファイルの役割とは?初心者向けにわかりやすく解説!
No.5
Java&Spring記事人気No5
C言語
Visual Studio CodeでC言語を実行する方法【拡張機能の設定と実行手順】
No.6
Java&Spring記事人気No6
C言語
C言語開発でよく使われるエディタとIDEランキング【初心者向け完全ガイド】
No.7
Java&Spring記事人気No7
C++
C++の主要な実装をわかりやすく解説!GCC・Clang・MSVCの違いと特徴
No.8
Java&Spring記事人気No8
C言語
C言語のデータ型まとめ(int,float,char,double)初心者でもわかる入門ガイド