変数のスコープ
前回まで関数の基本的な構造などについて説明してきました。
前回のコードを見てもらうとmain関数とfunc関数内で同じ名前を使用していましたが問題ありませんでした。
今回はその辺りのことを説明しようと思います。
スコープ
まず以下のコードを見てください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #include <stdio.h> void sum( int num); int main( void ){ int num; printf ("数を入力して下さい。n"); scanf ("%d", &num); sum(num); printf (“mian-numは%dですn“, num); return (0); } void sum( int num){ num *= 2; printf (“func-numは%dですn“, num); } |
実行結果
1 2 3 4 | 数を入力して下さい。 10 func-numの値は20です。 main-numの値は10です。 |
前のページのコードにはnumという変数がmain関数とsum関数の仮引数の両方で使用されています。
しかしプログラム的には問題はありません。
というのも変数には、スコープというものがあります。スコープというのは有効範囲です。
関数内で宣言された変数の有効範囲は関数内だけ、つまり「{」から「}」の間ということになります。
そのため同じ名前の変数であっても別の領域に保存されているために別物という扱いになります。
こういったブロック内の先頭で宣言され関数内でのみ有効な変数のことをローカル変数といいます。
先ほどのプログラムではmain関数内のnumはmain内でのみ有効なローカル変数となります。
またsum関数内のnum変数はsum内でのみ有効なローカル変数となります。
結果を見てみると実際に入力した数は10となるためnumには10が入ります。
これを実引数としてfunc関数に渡しているため、func内の仮引数num内には10が
格納されています。
func内ではこのnumを2倍していますが、あくまでfunc内ローカル変数numを2倍にしているだけなので
main側のnumが2倍されるわけではありません。前回すこし説明したように変数を引数として渡した場合は
それぞれの変数が異なるメモリ領域に格納されます。
そのため表示結果がfunc関数内でnumを表示させた場合とmain関数内で表示させた場合で
異なる結果となります。
このようにローカル変数は関数内だけで有効な変数であるため、今回のプログラムのように実引数と仮引数の
変数名が被ってしまっても特に問題はありません。
逆に呼び出しもとの変数に対して何か操作する場合は、呼び出された関数側でreturn文により値を返して
戻り値を処理するか、のちに出てくるポインタというものを使用する必要があります。
ポインタに関しては後に取り上げますので、今のところは値を受け取って何かしたい場合は
戻り値で処理する必要があるという認識で構いません。
スコープを超えて変数を利用することはできません。
ブロック内の有効範囲
次にブロック内の有効範囲を見るために以下のコードを確認してください。
1 2 3 4 5 6 7 8 9 10 11 | #include <stdio.h> int main( void ){ int i; for (i = 0; i < 5; i++){ int i = 0; printf (“ for 内部%dn",i); } printf (“ for 外部%dn",i); return (0); } |
実行結果は以下のようになります。
1 2 3 4 5 6 | for 内部0 for 内部0 for 内部0 for 内部0 for 内部0 for 外部5 |
このコードではまずmain関数の最初にint型変数iを宣言しています。
そしてfor文の内部でもint型変数iを宣言しています。
実行結果を見るとforの内部で変数iを表示させた場合はすべて0となっています。
最後にforの外部で変数iを表示させていますが、そこでは5となっています。
ローカル変数の有効範囲は先ほど述べたように「{」「}」の間です。
今回最初のiの有効範囲は水色の部分です。for内部で宣言されたiの有効範囲は赤の部分です。
内部のprintf文では「i」を表示させていますが、このiはどちらの有効範囲にも当てはまっています。こういった場合は
最内のブロック内の変数と判断されます。そのためすべて0と表示されます。実際は紛らわしいので避けた方がよいです。
グローバル変数
先ほどまでローカル変数のスコープに関して述べましたが、
ローカル変数以外にもグローバル変数というものがあります。グローバル変数というのはブロックを超えて
参照可能な変数のことです。このグローバル変数は定義したファイル内で有効となるため、ファイル内の関数からで
あればどこからでも扱うことができる変数となります。
ただしどこからでも扱えるということはどこからでも書き換え可能ということであり、
間違えて意図せず書き換えてしまうという危険性もあるためそのあたりを意識して使用する必要があります。
次のコードを確認してください。
1 2 3 4 5 6 7 8 9 10 11 12 | #include <stdio.h> void func( void ); int num; int main( void ){ num=10; func(); printf ("numの値は%dn", num); return (0); } void func( void ){ num+=10; } |
実行結果は以下のようになります。
1 | numの値は20 |
今回3行目の部分がグローバル変数の宣言をしている部分となります。
関数のブロック内ではなくブロックの外で宣言しています。こうすることでこのファイル内の関数全域で有効と
なります。
そのため今回のコードではmain関数内でnum変数は宣言してません。またfunc関数内でもnum変数を
宣言していませんが、numという変数に対して代入や加算を行うことができるようになっています。
このように関数全体で共通な変数として使用できるのがグローバル変数となります。
グローバル変数はローカル変数では初期化に関して違いがあり、初期化していないと不定となるローカル変数に
対して、グローバル変数は初期化を行っていない場合、0で自動的に初期化されます。
実践力が身につくC言語講座 連載リンク
競技プログラミングをイメージしたライブラリ活用講座
競技プログラミング風-標準Cライブラリ入門 連載
アルゴリズムをマスターして技術力アップ!
実践アルゴリズム講座 連載
パズルゲームの解析をテーマにしたC++講座
ゲーム解析プログラミング 連載