関数で値を書き換える

関数の中で書き換えても戻らない

前回、scanf は番地を受け取るから呼び出し元を書き換えられる、という話をしました。同じことを、自分で書く関数でもできます。

まず、できない書き方から見ます。

void add_bonus(int score) { score = score + 5; // 写しを書き換えているだけ } int main(void) { int score = 80; add_bonus(score); printf("%d\n", score); // 80 のまま }

add_bonus が受け取る score は、呼び出し元とは別の変数です。名前が同じでも中身は写しなので、関数から抜けた瞬間に捨てられます。

番地を渡せば書き換えられる

引数の型をポインタにして、呼び出すときに & を付けます。

void add_bonus(int *score) { *score = *score + 5; // 指している先を書き換える } int main(void) { int score = 80; add_bonus(&score); printf("%d\n", score); // 85 になる }

関数の中では score はポインタなので、値を触るときは必ず * を付けます。score = score + 5; と書くとポインタの番地のほうを動かしてしまうので、コンパイラに叱られるか、書いた本人の意図と違う動きになります。

この渡し方を 参照渡し と呼びます。正確に言えば C にあるのは値渡しだけで、番地という値を渡すことで参照渡しの効果を作っている、という理解が正しい形です。

結果を 2 つ以上返したいとき

return で返せる値は 1 つだけです。ところが実際には、合計と最高点を一度に知りたい、といった場面がよくあります。ポインタの引数を使えば、必要な数だけ結果を持ち帰れます。

void swap_score(int *a, int *b) { int tmp = *a; *a = *b; *b = tmp; }

入れ替えは、片方を先に上書きすると元の値が消えるので、一時変数 tmp に逃がしてから交換します。この 3 行の型は、これから先どの言語でも出てくる基本形です。

呼び出し側が & を付け忘れると、int を int * の引数に渡すことになるので、コンパイラが型の食い違いを教えてくれます。前回の scanf と違って気づきやすい部類のミスなので、素直に直してください。

では、2 人の点数を入れ替える関数を書いてみましょう。

要件

  1. 点数を2つ読み込む
  2. void swap_score(int *a, int *b) を定義して、指している先の値を入れ替える
  3. 入れ替える前を 「入替え前は80点と95点です」 の形で表示する
  4. 入れ替えたあとを 「入替え後は95点と80点です」 の形で表示する

入出力例

main("80 95") → "入替え前は80点と95点です 入替え後は95点と80点です" main("60", "100") → "入替え前は60点と100点です 入替え後は100点と60点です" main("77 77") → "入替え前は77点と77点です 入替え後は77点と77点です"

ヒント

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部
main.c
学習モード

メモ

関数で値を書き換える

⌘S で保存