変数の記憶クラス、有効範囲について

最終更新日:2004-06-14.

今回は、変数の記憶クラス、有効範囲についてちょっと。
と、いきなりいわれてもなんのことだかわかりませんね。

普通、ある関数の中で変数を宣言すると、それはその関数の中だけでしか
使用できません。

例えば。

int main( )
{
int i;
return 0;
}

上記は、main()関数の中でint型の変数iを宣言しています。
この変数iに値を代入したり、その変数の値を参照できるのは
main()関数の中だけです。
その他のサブ関数の中では使用できません。
このような約束事はサブ関数の中でも同様です。

次に、

int i;

int main( )
{
return 0;
}

上記は、main()関数の外側でint型の変数iを宣言しています。
この場合、変数iに値を代入したり、その変数の値を参照することが
できます。
もし、main()関数やサブ関数で同じ変数の値を処理したいときには
この方法が便利です。

でも、これは便利な反面、複数の人たちでプログラムを開発している場合
どこからでもその変数に手を加えることができたり、
無駄にその変数の領域を確保しているなど煩雑な面があるとのこと。

そんなことから、変数は必要最小限で確保し、
関数間で値やその変数のアドレスを渡す方がよいとのこと。

サブ関数内で変数を宣言するとその変数は同じ関数の中だけで有効となり、
その関数が終了するとその変数の領域も開放されます。
これは、限られたメモリ資源の無駄遣いを防ぐことができます。

・変数の記憶クラス

変数を使用するには、変数の型と変数名を宣言します。
さらに、変数の記憶クラスとしてstaticやautoを指定することができます。

・記憶クラスと有効範囲

staticを指定すると、プログラムが実行されている間
その変数はメモリの同じ場所に固定的に確保されています。

autoを指定すると、その変数が宣言されている関数が実行されている間
だけメモリ上に確保されています。

・記憶クラスの省略

これら記憶クラスを省略すると、関数の内ではautoが、
関数の外ではstaticが指定されたものとみなされます。

static int i;
auto int j;

これ以外にも、記憶クラスにはregisterやexternがあります。

registerはautoと同じ機能をもっていますが、記憶場所がcpu内にあるので
高速な処理が可能になります。

externは、他のソースファイルにある変数を使用するときに指定します。

・変数の有効範囲

変数にはローカル変数(局所変数)と
グローバル変数(外部変数)があります。

ローカル変数は、関数の内で宣言された変数です。
static、auto、registerが指定できます。

グローバル変数は、関数の外で指定した変数です。
static、externが指定できます。

では、それらをソースで見てみましょう。
+------------------------------------------------------------+
/* filename=no009-1.c */
/* include */
#include <stdio.h>
/* 関数プロトタイプ宣言 */
int sub(int i3);
/* 外部変数 */
int i1;
/* main */
int main( )
{
int i2;
/* i1 はどこからでも使用 */
i1=1;
/* i2 はこの中だけで使用 */
i2=200;
printf("i1=%d, i2=%d <--> main()\n", i1, i2);
/* sub()関数で処理 */
i2=sub(i2);
printf("i1=%d, i2=%d <--> main()\n", i1, i2);
return 0;/* 終了 */
}
/* sub()関数 */
int sub(int i3)
{
int i4;
/* i3, i4 はこの中だけで使用 */
i4=i3*2;
/* i1 の値をかってに変えてみる */
i1=(-10);
printf("i3=%d, i4=%d <--> sub()\n", i3, i4);
return i4;/* 戻る */
}
+------------------------------------------------------------+

上記のソースをコンパイルして実行すると以下のように表示されました。
i1=1, i2=200main()
i3=200, i4=400sub()
i1=-10, i2=400main()
+------------------------------------------------------------+
/* filename=no009-2.c */
/* include */
#include <stdio.h>
#include <malloc.h>
/* 関数プロトタイプ宣言 */
void sub1(void);
void sub2(void);
/* main */
int main( )
{
char wk[1024]="";
/* main()関数内でメモリを確保 */
printf("size(char wk[])=%d -- main()\n", sizeof(wk));
/* sub関数での処理 */
sub1();
sub2();
return 0;/* 終了 */
}
/* 確保できる最大サイズ */
void sub1(void)
{
unsigned int size;
char *s;
size=1000;/* 初期値 */
while( 1 ){
/* メモリの確保 */
s=(char *)malloc(size);
/* 確保できなければ処理を抜ける */
if( s==(char *)NULL ){
size-=1000;
free(s);
break;
}
/* メモリを解放して次のサイズで */
free(s);
size+=1000;
}
printf("size(char *s)=%u -- sub1()\n", size);
return;/* 戻る */
}
/* 確保できる最大サイズ */
void sub2(void)
{
unsigned int size;
char *s;
size=1000;
while( 1 ){
s=(char *)malloc(size);
if( s==(char *)NULL ){
size-=1000;
free(s);
break;
}
free(s);
size+=1000;
}
printf("size(char *s)=%u -- sub2()\n", size);
return;/* 戻る */
}
+------------------------------------------------------------+

上記のソースをコンパイルして実行すると以下のように表示されました。
size(char wk[])=1024 -- main()
size(char *s)=59000 -- sub1()
size(char *s)=59000 -- sub2()

戻る