Function arguments by reference


ポインタと関数について理解した上で、関数の引数は値渡し、つまり関数間でコピーされて渡されることをご存知でしょう。 しかし、値そのものではなく、値へのポインタを渡したらどうなるでしょうか? こうすることで、関数は親関数の変数や構造体をコピーではなく制御できるようになり、元のオブジェクトを直接読み書きできるようになります。

例えば、addone という、数値を1ずつ増やす関数を記述するとします。これはうまくいきません。

void addone(int n) {
    // nは関数スコープ内にのみ存在するローカル変数です
    n++; // そのため、nを増やしても、関数の外からは影響を与えません
}

int n;
printf("Before: %d\n", n);
addone(n);
printf("After: %d\n", n);

しかし、これはうまくいきます。

void addone(int *n) {
    // nは関数スコープ外のメモリアドレスを指すポインタです
    (*n)++; // これにより、nの値が実質的に増加します。
}

int n;
printf("Before: %d\n", n);
addone(&n);
printf("After: %d\n", n);

違いは、addone の 2 番目のバージョンは変数 n へのポインタを引数として受け取り、それがメモリ内のどこにあるかを知っているため、それを操作できるという点です。

addone 関数を呼び出す際は、変数 n 自体ではなく、変数への参照を渡す必要があることに注意してください。これは、関数が変数のアドレスを認識し、変数のコピーを受け取らないようにするためです。

構造体へのポインタ

点を x 方向と y 方向の両方に移動する、move という関数を作成するとします。2つのポインタを引数として渡す代わりに、点構造体の関数へのポインタを1つだけ渡すことができます。

void move(point * p) {
    (*p).x++;
    (*p).y++;
}

構造体を逆参照して内部メンバーにアクセスしたいときのために、簡略化された構文があります。それほど、この操作は構造体データで広く使用されているのです。この関数は、次の構文を使って書き換えることができます。

void move(point * p) {
    p->x++;
    p->y++;
}

Exercise

personageに1を加算するbirthdayという関数を書いてください。


Copyright © learn-c.org. Read our Terms of Use and Privacy Policy