C言語における局所変数とグローバル変数のメモリにおける格納位置を深く検討する

7772 ワード

C言語における局所変数とグローバル変数の格納カテゴリ(static,extern,auto,register)
1.ローカル変数およびグローバル変数は、関数のパラメータ変数について議論する際に言及したように、呼び出された期間にのみメモリユニットが割り当てられ、呼び出しが終了するとすぐに解放される.この点は,パラメトリック変数が関数内でのみ有効であり,この関数を離れると二度と使用できないことを示している.この変数の有効性の範囲を変数の役割ドメインと呼ぶ.パラメトリック変数だけでなく、C言語のすべての量には独自の役割ドメインがあります.変数の説明の仕方が異なり、その役割ドメインも異なります.C言語の変数は、役割ドメインの範囲によって2つに分けられます.すなわち、ローカル変数とグローバル変数です.
1.1ローカル変数
ローカル変数は内部変数とも呼ばれます.ローカル変数は、関数内で定義されます.その役割ドメインは関数内に限られており,その関数を離れてからこの変数を使用するのは違法である.
【例1.1】
 
  
    int f1(int a)        /* f1*/
    {
        int b,c;    
    }
a,b,c
    int f2(int x)        /* f2*/
    {
          int y,z;
   }
x,y,z
    int main(void)
    {
         int m,n;
    }
m,n

関数f 1内には3つの変数が定義され、aはパラメータ、b、cは一般変数である.f 1の範囲内でa,b,cが有効である、あるいはa,b,c変数の作用域はf 1内に限られる.同様に,x,y,zの役割ドメインはf 2内に限られる.m,nの役割ドメインはmain関数内に限られる.ローカル変数の役割ドメインについて
以下の点を説明します:1)主関数で定義された変数も主関数でのみ使用でき、他の関数では使用できません.また、主関数では他の関数で定義された変数も使用できません.主関数も関数であるため、他の関数と平行関係にあります.この点は他の言語とは異なり、注意しなければならない.
2)パラメトリック変数は被変調関数に属する局所変数であり,実パラメトリック変数は主変調関数に属する局所変数である.
3)異なる関数で同じ変数名を使用することを許可し、それらは異なるオブジェクトを表し、異なるユニットを割り当て、互いに干渉せず、混同も起こらない.前例のように、パラメータと実パラメータの変数名はnであり、完全に許容される.
4)複合文に変数を定義することもでき、その役割ドメインは複合文の範囲内のみである.
【例1.2】
 
  
int main(void)
{
       int s,a;
      {
              int b;
              s=a+b;
             /*b */
       }
/*s,a */
}

【例1.3】
 
  
int main(void)
{
    int i=2,j=3,k;
    k=i+j;
    {
       int k=8;
       printf("%d
",k);
    }
    printf("%d
",k);
}

このプログラムはmainでi,j,kの3つの変数を定義し,kは初期値を与えていない.複合文には変数kが定義され、初期値は8である.この2つのkは同じ変数ではないことに注意してください.複合文外ではmainによって定義されたkが機能し、複合文内では複合文内で定義されたkが機能する.したがって、プログラム4行目のkはmainで定義され、その値は5であるべきである.7行目はk値を出力し、この行は複合文内で複合文内で定義されたkによって機能し、その初期値は8であるため、出力値は8、9行目はi、k値を出力する.iはプログラム全体で有効であり、7行目はiに3を付与するので、出力も3とする.9行目が複合文の外にある場合、出力されたkはmainで定義されたkであるべきであり、このk値は4行目から5に得られるため、出力も5である.
1.2グローバル変数
グローバル変数は外部変数とも呼ばれ、関数の外部で定義された変数です.どの関数に属していません.ソース・プログラム・ファイルに属します.その役割ドメインはソースプログラム全体です.関数にグローバル変数を使用するには、一般的にグローバル変数の説明を行う必要があります.関数内で説明されているグローバル変数のみが使用できます.グローバル変数の説明子はexternです.ただし、1つの関数の前に定義されたグローバル変数は、この関数内で使用すると説明しなくてもよい.
【例1.4】
 
  
   int a,b;          /* */
    void f1()         /* f1*/
    {
      ……
    }
   float x,y;         /* */
    int fz()          /* fz*/
    {
      ……
    }
    Int main(void)           /* */
    {
      ……
    }

上記の例から,a,b,x,yはいずれも関数の外部で定義された外部変数であり,いずれもグローバル変数であることが分かる.しかし、x,yは関数f 1の後に定義され、f 1内にはx,yの説明がないため、f 1内では無効である.a,bはソースプログラムの先頭に定義されているので,f 1,f 2およびmain内では説明を加えずに使用できる.
【例1.5】正方体の長さと幅の高さl,w,hを入力し、体積と3つの面x*y,x*z,y*zの面積を求める.
 
  
int s1,s2,s3;
int vs( int a,int b,int c)
{
    int v;
    v=a*b*c;
    s1=a*b;
    s2=b*c;
    s3=a*c;
    return v;
}
int main(void)
{
    int v,l,w,h;
    printf("
input length,width and height
");
    scanf("%d%d%d",&l,&w,&h);
    v=vs(l,w,h);
    printf("
v=%d,s1=%d,s2=%d,s3=%d
",v,s1,s2,s3);
}

【例1.6】外部変数は局所変数と同名である.
 
  
int a=3,b=5;     /*a,b */
max(int a,int b) /*a,b */
{
    int c;
    c=a>b?a:b;
    return(c);
}
 int main(void) 
{
    int a=8;
    printf("%d
",max(a,b));
}

同じソースファイルで外部変数がローカル変数と同じ名前の場合、ローカル変数の範囲内で外部変数は「マスク」され、つまり機能しません.
2.変数の格納カテゴリ
2.1動的記憶方式と静的動的記憶方式
前述したように,変数の役割ドメイン(すなわち空間)の観点から,グローバル変数と局所変数に分けることができる.
別の角度から、変数値が存在する作時間(すなわち生存期間)の観点から、静的記憶方式と動的記憶方式に分けることができる.
静的記憶方式:プログラムの実行中に一定の記憶空間を割り当てる方式を指す.
動的記憶方式:プログラムの実行中に必要に応じて動的に記憶空間を割り当てる方式である.
ユーザーのストレージスペースは、次の3つのセクションに分けられます.
1)プログラム領域;2)静的記憶領域;3)動的記憶領域;
グローバル変数はすべて静的記憶領域に格納され、プログラムの実行開始時にグローバル変数に記憶領域が割り当てられ、プログラム行が完了すると解放される.プログラム実行中に固定された記憶ユニットを占有し、動的に割り当てられ、解放されない.
ダイナミックストレージには、次のデータが格納されます.
1)関数形式パラメータ;2)自動変数(static宣言のない局所変数);3)関数は実の現場保護と戻りアドレスを呼び出す;
以上のデータに対して、関数呼び出し開始時に動的記憶領域が割り当てられ、関数終了時にこれらの空間が解放される.
c言語では、各変数と関数には、データ型とデータの格納カテゴリの2つの属性があります.
2.2 auto変数
関数内のローカル変数は、staticストレージカテゴリとして特に宣言されない場合、動的にストレージスペースを割り当て、データは動的ストレージ領域に格納されます.複合文で定義された変数を含む関数内のパラメータと、関数で定義された変数はこのようなもので、関数を呼び出すと記憶領域が割り当てられ、関数呼び出しの終了時に自動的に記憶領域が解放されます.これらのローカル変数は自動変数と呼ばれます.自動変数はキーワードautoを記憶カテゴリの宣言として使用します.
【例1.7】
 
  
int f(int a)         /* f ,a */
{
    auto int b,c=3;     /* b,c */
}

aはパラメータ,b,cは自動変数であり,cに初期値3を与える.f関数を実行した後、a,b,cが占めるメモリセルを自動的に解放する.
キーワードautoは省略でき、autoは書かないと「自動記憶カテゴリ」と暗黙的に定められ、動的記憶方式に属する.
2.3 staticでローカル変数を宣言する
関数内のローカル変数の値が関数呼び出し終了後に消えずに元の値を保持する場合は、ローカル変数を「静的ローカル変数」と指定し、キーワードstaticで宣言する必要があります.
【例1.8】静的局所変数の値を考察する.
 
  
f(int a)
{
    auto b=0;
    static c=3;
    b=b+1;
    c=c+1;
    return(a+b+c);
}
int main(void)
{
    int a=2,i;
    for(i=0;i<3;i++)
         printf("%d",f(a));
}

静的ローカル変数の説明:
1)静的局所変数は静的記憶カテゴリに属し、静的記憶領域内に記憶ユニットを割り当てる.プログラムの実行中は解放されません.自動変数(すなわち動的ローカル変数)は動的記憶カテゴリに属し、動的記憶空間を占め、関数呼び出しが終了すると解放される.
2)静的局所変数はコンパイル時に初期値を付与し、すなわち一度だけ初期値を付与する.一方、自動変数の初期値の付与は、関数呼び出し時に行われ、呼び出されるたびに初期値が再付与され、割り当て文が実行されることに相当します.
3)ローカル変数を定義するときに初期値を付与しない場合、静的ローカル変数では、コンパイル時に0(数値型変数)または空の文字(文字変数)が自動的に付与されます.自動変数では、初期値を付与しない場合、その値は不確定な値です.
【例1.9】1〜5の乗算値を印刷する.
 
  
int fac(int n)
{
    static int f=1;
    f=f*n;
    return(f);
}
int main(void)
{
    int i;
    for(i=1;i<=5;i++)
        printf("%d!=%d
",i,fac(i));
}

2.4 register変数
効率化のため、C言語では、ローカル変数の値をCPUのレジスタに置くことができます.この変数を「レジスタ変数」と呼び、キーワードregisterで宣言します.
【例2.0】レジスタ変数を使用する.
 
  
int fac(int n)
{
    register int i,f=1;
    for(i=1;i<=n;i++)
        f=f*I;
     return(f);
}
int main(void)
{
    int i;
    for(i=0;i<=5;i++)
        printf("%d!=%d
",i,fac(i));
}

説明:1)ローカル自動変数と形式パラメータのみがレジスタ変数として使用できる.
2)1つのコンピュータシステムにおけるレジスタ数は限られており、任意の複数のレジスタ変数を定義することはできない.
3)局所静的変数はレジスタ変数として定義できない.
2.5 externで外部変数を宣言する
がいぶへんすう(つまりグローバル変数)は、関数の外部で定義されており、その役割ドメインは変数定義から本プログラムファイルの末尾までである.外部変数がファイルの先頭で定義されていない場合、その有効な役割範囲は定義からファイル終了までに限られる.定義点より前の関数がその外部変数を参照したい場合は、参照する前にキーワードexternでその変数を量は「外部変数宣言」とします.この変数が定義された外部変数であることを示します.この宣言があれば、「宣言」から外部変数を合法的に使用できます.
【例2.1】externで外部変数を宣言し、プログラムファイル内の役割ドメインを拡張する.
 
  
int max(int x,int y)
{
    int z;
    z=x>y?x:y;
    return(z);
}
int main(void)
{
    extern A,B;
    printf("%d
",max(A,B));
}
int A=13,B=-8;

説明:本プログラムファイルの最後の1行で外部変数A,Bが定義されていますが、外部変数定義の位置は関数mainの後なので、本来main関数では外部変数A,Bを参照することはできません.ここでmain関数でexternでAとBを「外部変数宣言」すると、「宣言」からこの外部変数AとBを合法的に使用できます.