自動・静的

◆記憶クラス

 久々、変数の宣言に戻ります。すでに配列をやったのでこれからは変数と配
列をまとめてオブジェクトと呼びます。後に出てくる構造体などもオブジェク
トに含まれます。

 さて、いままでの変数の宣言の仕方について、

[修飾子] [データ型] [オブジェクト名] = [初期化値] ;

または、

[修飾子] [データ型] [オブジェクト1], [オブジェクト2] ... ;

という形でした。修飾子とはunsignedなどの型を拡張する接頭語です。

…で、この修飾子についてまだ、やってないものがあります。

上のようにオブジェクトを宣言するとメモリにそのオブジェクト用の領域を確
保します。

そして、プログラムが終了するとそれらの領域はすべて開放されてしまいます。

しかし、プログラム中でほんの一部分でしか使わないオブジェクトが多ければ
メモリは領域を確保して使わない時間が長くて無駄になります。(ほかのプログ
ラムにとって迷惑)

ということで、使用頻度の低いオブジェクトや(特に記録の必要のないもの)は
必要時にだけメモリを確保すればいいことになります。

これらのメモリの領域確保の方法を記憶クラスで設定します。

記憶クラスには次のようなものがあります。

自動(auto)
静的(static)
レジスタ(register)
外部(extern)

宣言するときは修飾子よりも前につけます。

auto unsigned int a;
static const int b;
register volatile int c;
extern signed long int d;

という感じです。


◇自動・静的

まずは、自動記憶域期間(auto)

通常、関数の中で記憶クラスを省略して宣言するとautoになります。

この記憶クラスはある関数中で宣言されたときにオブジェクトの領域をメモリ
に確保し、その関数の終了と同時にメモリから開放されます。
なお、初期化を忘れたときの値は不定です。

void fn()
{
auto int i;
i = 3;
}

1.ある関数 fn() の実行
2.auto int i; によって整数型変数iがメモリに確保される(図1)
3.i = 3; によってiの初期化(3を代入:図2)
4.関数fn()の終了と同時に変数iを開放(図3)

  ┌──────┐  ┌──────┐  ┌──────┐
  │      │  │      │  │      │
  │      │  │      │  │      │
  │      │  │      │  │      │
  ├──────┤  ├──────┤  ├‐‐‐‐‐‐┤
 i│ (確保) │ i│    3 │  │ (開放) │
  ├──────┤  ├──────┤  ├‐‐‐‐‐‐┤
  │      │  │      │  │      │
  │      │  │      │  │      │
  │      │  │      │  │      │
  └──────┘  └──────┘  └──────┘
     図1        図2        図3   

autoの場合この繰り返しでfn()が使用されるたびに1〜4の処理をします。
なお変数iの値ですが、fn()の終了と同時に消えてしまいます。


次に静的記憶域期間(static)です。

こちらは宣言されている場所にかかわらずプログラムの開始直前にメモリを確
保し初期化します。初期化を忘れた場合値は0になります。
また、確保された領域はプログラムが終了するまで保持されるので関数の終了
時に値が消えることがありません。2回目以降関数内のstaticオブジェクトを
利用するときは前回の値から始まります。

void fn()
{
static int i;
i = 3;
}

1.プログラムの開始と同時に確保&初期化(図4)
  ただし初期化はこの1回限りになる。
2.i = 3; によって i に3を代入(図5)
3.fn()の終了、値は保持(図6)

  ┌──────┐  ┌──────┐  ┌──────┐
  │      │  │      │  │      │
  │      │  │      │  │      │
  │      │  │      │  │      │
  ├──────┤  ├──────┤  ├──────┤
 i│    0 │ i│    3 │ i│(保持)3 │
  ├──────┤  ├──────┤  ├──────┤
  │      │  │      │  │      │
  │      │  │      │  │      │
  │      │  │      │  │      │
  └──────┘  └──────┘  └──────┘
     図4        図5        図6   


自動記憶域期間と静的記憶域期間の比較ができるプログラムを示します。

#include

void fn();

main()
{
int i;
for(i=0;i<10;i++)fn();
}

void fn()
{
auto int a=0;
static int b=0;

a++; b++;

printf("a=%d, b=%d\n",a,b);
}

結果:
a=1, b=1
a=1, b=2
a=1, b=3
a=1, b=4
a=1, b=5
a=1, b=6
a=1, b=7
a=1, b=8
a=1, b=9
a=1, b=10

このように自動変数のaはfn()が呼び出されるたびに0に初期化されfn()の終了
とともに値を失うので毎回1になります。

それに引き換え静的変数bは最初0で初期化されますが、初期化はこれっきりで
fn()が終了しても値は保持しています。よって2回目以降fn()が呼び出された
ときは前回の値を保持しているのでそれに1を足して表示していきます。


※今回のプログラムについて

 main以外の関数を使って呼びだしをしていますがプログラミングについての
解説はここではいたしません。とりあえず、結果の表示より自動と静的の違い
を比較してご理解願いたいと思います。


http://c-production.com/contents/c/sec04.html