変数のスコープ

関数の中の変数は外から見えない

関数を分けはじめると、ほぼ全員が一度は次のコードを書きます。

void show_total(void) { printf("合計は%d点です\n", total); /* total は main のもの */ } int main(void) { int total = 255; show_total(); return 0; }

コンパイルすると use of undeclared identifier 'total' と怒られます。main の中に確かに total はあるのに、show_total からは見えません。

変数が使える範囲のことを スコープ と呼びます。関数の中で宣言した変数は ローカル変数 で、そのスコープは宣言した波カッコの中だけです。main も1つの関数なので、main で宣言した変数も main 専用です。特別扱いはありません。

直し方は、見せたい値を引数として渡すことです。

void show_total(int total) { printf("合計は%d点です\n", total); } int main(void) { int total = 255; show_total(total); return 0; }

関数が必要とする値を引数リストに並べておくと、その関数だけを読めば「何を材料にしているか」が分かります。外の変数を勝手に読める仕組みだと、遠くの行を書き換えた影響がどこに出るか追えなくなります。見えないのは不便な制限ではなく、追跡できる範囲を狭く保つための仕組みです。

同じ名前でも別の変数

スコープが分かれているということは、違う関数で同じ名前を使っても衝突しないということです。

int add_bonus(int score) { int total = score + 5; return total; } int main(void) { int total = 0; total = total + add_bonus(70); printf("%d\n", total); /* 75 */ return 0; }

add_bonustotal と main の total は、名前が同じだけの完全に別の変数です。add_bonus の中で total を 75 にしても、main の total は 0 のままで、変わるのは return された値を足したときだけです。

これは第2章で学んだ、引数が値のコピーで渡されるという話とつながっています。関数どうしは値のやりとりだけでつながっていて、変数そのものを共有してはいません。

生まれて消えるタイミング

ローカル変数は、関数が呼ばれたときに作られ、関数が終わると消えます。add_bonus を3回呼べば、total は3回作られて3回消えます。前の呼び出しの値が残ることはないので、関数の頭で初期化を忘れても前回の続きから、ということは起きません。逆に言えば、値を次の呼び出しへ持ち越したいなら、戻り値で返して呼び出し元が持っておく必要があります。

なお、for のカウンタのように波カッコの中で宣言した変数は、その波カッコを抜けた時点で見えなくなります。スコープの単位は関数ではなく波カッコだ、と覚えておくと正確です。

では、同じ名前の変数を2つの関数に持たせて、混ざらないことを確かめましょう。

要件

  1. add_bonus は点数を受け取り、5 を足した値を返す関数にする
  2. add_bonus の中では total という名前のローカル変数に計算結果を入れてから return する
  3. main でも total という名前の変数を用意し、0 で初期化して補正後の点数を足していく
  4. for 文で3人分の点数を scanf で読み込み、1人目 75点 の形で1行ずつ表示する
  5. 最後の行に 合計は255点です の形で main の total を表示する

入出力例

main("70 80 90") → "1人目 752人目 853人目 95合計は255点です" main(40, 55, 60) → "1人目 452人目 603人目 65合計は170点です"

ヒント

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

メモ

変数のスコープ

⌘S で保存