配列を関数に渡す

配列は写しが渡らない

第6章で作った点数の配列を、関数に渡してみます。書き方はこうです。

int sum_scores(const int scores[], int n) { int total = 0; for (int i = 0; i < n; i++) { total += scores[i]; } return total; } int total = sum_scores(scores, 5); // & は付けない

呼ぶときに & を付けないのは、前々回に見たとおり、配列名がすでに先頭要素の番地だからです。そして渡っているのも、配列全部の写しではなく 先頭の番地だけ です。要素が 1000 個あっても渡るのは番地 1 個なので、大きな配列でも呼び出しは軽く済みます。

引数の int scores[] は、実は int *scores と書いても完全に同じ意味になります。角カッコの書き方は「配列を受け取るつもりです」と読む人に伝えるための見た目で、コンパイラにとっては両方ともポインタです。

個数は自分で渡す

番地しか渡らないということは、関数の中では要素が何個あるか分からないということです。呼び出し元で sizeof(scores) / sizeof(scores[0]) が使えても、関数の中の scores はポインタなので同じ計算は成り立ちません。

だから配列を渡す関数は、必ず 要素数を第 2 引数で一緒に渡す 形にします。C の標準ライブラリも同じ作りになっています。個数を間違えると配列の外まで読み書きしてしまい、静かに壊れるので、渡す数には気をつけてください。

中で書き換えると呼び出し元も変わる

番地が渡っているので、関数の中で scores[i] を書き換えると、呼び出し元の配列がそのまま変わります。前回のポインタ引数と同じ仕組みです。

void add_bonus(int scores[], int n, int bonus) { for (int i = 0; i < n; i++) { scores[i] += bonus; } }

書き換えるつもりがない関数には const int scores[] と書いておくと、うっかり代入したときにコンパイラが止めてくれます。読むだけの関数には付ける習慣にしておくと安全です。

まとめると、配列の受け渡しで押さえるのは 3 点です。呼ぶときに & は付けない、要素数は別の引数で渡す、関数の中の書き換えは呼び出し元に届く。この 3 つが分かっていれば、第6章で書いた成績管理の処理は、そのまま関数へ移せます。

では、点数の配列を関数に渡して、合計と加点をやってみましょう。

要件

  1. 5つの点数を読み込んで配列に入れる
  2. int sum_scores(const int scores[], int n) で合計を返す
  3. void add_bonus(int scores[], int n, int bonus) で全員に加点する
  4. 加点前の合計を 「合計は405点です」 の形で表示する
  5. 5点加点してから 「加点後の合計は430点です」 と 「加点後の平均は86.0点です」 を表示する

入出力例

main("80 95 70 60 100") → "合計は405点です 加点後の合計は430点です 加点後の平均は86.0点です" main("60", "60", "60", "60", "60") → "合計は300点です 加点後の合計は325点です 加点後の平均は65.0点です"

ヒント

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

メモ

配列を関数に渡す

⌘S で保存