変数のスコープについては以前説明したとおりですが、少し補足しておきます。
/*01*/ #include <stdio.h>
/*02*/
/*03*/ int x;
/*04*/
/*05*/ main()
/*06*/ {
/*07*/ void Func(void);
/*08*/
/*09*/ x = 10;
/*10*/ Func();
/*11*/
/*12*/ return 0;
/*13*/ }
/*14*/
/*15*/ void Func(void)
/*16*/ {
/*17*/ printf("x=%d\n", x);
/*18*/ }
このリストのように、変数は関数の外側で宣言することもできます。この場合、プログラム中のどこからでもこの変数にアクセスできます。このような変数を
こうすると一見便利なように見えますが、その変数がどこで使われているのかはっきりしなくなり、時には同じ変数名の変数を関数内で宣言してしまって思わぬ結果になるなどの不都合もあります。この例の場合なら、Func 関数で表示させる値は引数で与えるなどして独立性を保つほうがよいでしょう。
次は記憶クラスというものについてです。
/*01*/ #include <stdio.h>
/*02*/
/*03*/ main()
/*04*/ {
/*05*/ int x;
/*06*/
/*07*/ for(x = 0; x < 10; x++){
/*08*/ int y = 1;
/*09*/
/*10*/ printf("%d\n", y);
/*11*/ y++;
/*12*/ }
/*13*/
/*14*/ return 0;
/*15*/ }
まずこの例を実行してみてください。for 文では、毎回 y がインクリメントされて、1から10まで順に表示されることを期待したいのですが、実際には「1」が10回表示されるだけとなります。なぜでしょう?これは、for 文の各ループが終了するたびに、そのブロックから1度抜けてしまっているからです。概念としては、for 文以下のブロックが、for 文で指定された回数だけ並んでいる、という感じでしょうか。ただし、for 文で使われている変数 x は各ブロックから見てグローバルということになります。つまり、上の例なら次のような感じでしょうか。
x = 0;
{
int y = 1;
printf("%d\n", y);
y++;
}
x = 1;
{
int y = 1;
printf("%d\n", y);
y++;
}
x = 2;
{
int y = 1;
printf("%d\n", y);
y++;
}
:
:
この現象は、これまで使ってきた変数の記憶クラスと呼ばれるものが
これに対して、記憶クラスが
1: int x; 2: auto int x; 3: static int x; /* [記憶型] [変数型] [変数名]; として宣言 */
まず、1番目は今までどおりと同じ宣言のし方です。1番目のように宣言された変数は、自動的に「auto」変数とみなされます。これに対し、2番目は auto 変数であることを明示しています。しかし、1番目と2番目とでは何の違いも無いので、普通は今までどおり1番のように宣言することのほうが多いでしょう。そして3番目は、その変数を「static」として宣言しています。
さて、auto 型と static 型ではメモリ上の取られ方が違います。auto 型は上で説明したとおり、宣言したブロックを抜けるとメモリ上から消去されてしまいます。これに対し、static 型で宣言された変数はそのブロックを抜けても、同じメモリ上に居座りつづけ、同じブロックが再び実行された場合はそれが使われます。(これらの型を
では実際に例を見て見ましょう。
/*01*/ #include <stdio.h>
/*02*/
/*03*/ main()
/*04*/ {
/*05*/ int x;
/*06*/
/*07*/ for(x = 0; x < 10; x++){
/*08*/ static int y = 1;
/*09*/
/*10*/ printf("%d\n", y);
/*11*/ y++;
/*12*/ }
/*13*/
/*14*/ return 0;
/*15*/ }
1回目のループ
変数 y が宣言され「1」に初期化。
(y を使った操作など。)
1回目のループ終了
2回目のループ
変数 y の値は、1回目のループ終了時のまま。
(y を使った操作など。)
2回目のループ終了
:
:
static int x; x = 1;
static 変数を使うときの注意として、次のような疑問が湧くと思います。「static 変数はそのブロックを抜けても値が保持されるんでしょ?それなら、そのブロックの外でもその変数が使えるんじゃない?」これは大きな間違えです。変数の有効範囲はあくまでも上で書いたとおりなので、その変数が宣言されたブロックの外では有効ではありません。
/*01*/ #include <stdio.h>
/*02*/
/*03*/ main()
/*04*/ {
/*05*/ int i;
/*06*/
/*07*/ for(i = 0; i < 10; i++){
/*08*/ static int x = 1;
/*09*/
/*10*/ x++;
/*11*/ }
/*12*/ printf("%d\n", x); /* x を参照できない */
/*13*/
/*14*/ return 0;
/*15*/ }
/*01*/ #include <stdio.h>
/*02*/
/*03*/ main()
/*04*/ {
/*05*/ void Func(void);
/*06*/ int i;
/*07*/
/*08*/ for(i = 0; i < 10; i++)
/*09*/ Func();
/*10*/
/*11*/ return 0;
/*12*/ }
/*13*/
/*14*/ void Func(void)
/*15*/ {
/*16*/ static int x = 1; /* int x;(auto 型)でも試してみてください */
/*17*/
/*18*/ printf("%d\n", x);
/*19*/ x++;
/*20*/ }
さて、static に関する性質は関数の呼び出しについても同じことが言えます。必要に応じて使い分けてください。(ただし、static はプログラムの終了までメモリ上に居座るので、メモリを無駄に占拠する可能性があります。)