本文へスキップ
BecomeCoder

C++コース · 第6章 ポインタとメモリ · レッスン26

ポインタと関数 ― 値を書き換えてもらう

ブラウザで完結

導入

関数に「値」を渡すと、関数の中で書き換えても呼び出し元は変わりません(コピーが渡るため)。ポインタ(住所)を渡すと、呼び出し元の変数そのものを書き換えられます。

説明

まず、ふつうに値を渡した場合。関数には値のコピーが渡るので、中の変更は呼び出し元に届きません。

#include <iostream>
using namespace std;

void tryChange(int x) {
    x = 100;       // これはコピー(別の箱)を変えているだけ
}

int main() {
    int a = 5;
    tryChange(a);
    cout << a << endl;   // 5(変わらない)
    return 0;
}

a と、関数の中の x は、メモリ上の別々の箱です。だから x をいくら変えても a には影響しません。

flowchart LR
  a["main の a = 5<br/>(3000番地)"] -->|"値をコピー"| x["tryChange の x = 5→100<br/>(別の箱 5000番地)"]
  x -.->|"元の a には届かない"| a

ポインタ(住所)を渡すと、* を通じて呼び出し元の変数を直接書き換えられます。住所を渡す=「本物の場所を教える」ので、関数はその場所を直接いじれます。

#include <iostream>
using namespace std;

void addOne(int *x) {
    *x = *x + 1;    // 住所の先=呼び出し元の変数を書き換える
}

int main() {
    int a = 5;
    addOne(&a);          // a の「住所」を渡す
    cout << a << endl;   // 6(変わった!)
    return 0;
}
flowchart LR
  a["main の a = 5→6<br/>(3000番地)"] -->|"&a で住所を渡す"| x["addOne の x = 3000<br/>(a を指すポインタ)"]
  x -->|"*x で書き換え"| a

2つの変数の中身を入れ替える swap も、ポインタを使えば作れます。値渡しでは絶対にできない処理です。

#include <iostream>
using namespace std;

void swap(int *a, int *b) {
    int t = *a;
    *a = *b;
    *b = t;
}

int main() {
    int x = 1, y = 2;
    swap(&x, &y);
    cout << x << " " << y << endl;   // 2 1
    return 0;
}

やってみよう

addOne*x = *x + 10; に変えたり、swap に渡す値を変えたりして、呼び出し元が書き換わることを確かめましょう。tryChange(値渡し)と addOne(ポインタ渡し)を見比べると、違いがはっきりします。

演習

int n をポインタで受け取り、その値を2倍にする関数 doubleIt を定義してください。int a = 8; doubleIt(&a); のあと a を表示すると 16 になります。

ヒント1を見る

void doubleIt(int *x) { *x = *x * 2; }、呼び出しは doubleIt(&a);

実際に動かしてみよう

下のエディタにC++を書いて「実行」を押すと、ブラウザ内のインタプリタで出力が表示されます。本文の例をそのまま試したり、書き換えたりしてみましょう(cin を使う回は「標準入力」欄に値を入れてから実行します)。

C/C++ — ブラウザ内で実行

ブラウザ内でC/C++を動かす学習用インタプリタ(JSCPP)を読み込みます(入門向けのサブセットです)。
スクロールして表示された時点でも自動で読み込まれます。