static

静的変数

変数にはローカル変数とグローバル変数のふたつがあるとすでに説明しました。
(変数のスコープ参照)

ローカル変数は、関数内で宣言される変数です。
ローカル変数はその関数内からのみアクセスができ、その関数の処理が終了すると消滅します。

グローバル変数は、関数の外で宣言される変数です。
グローバル変数はどの関数からもアクセスができ、プログラムの開始から終了までメモリ上に存在します。

この両方の特徴を合わせたような変数も存在します。
それが静的変数(static変数)です。

#include <stdio.h>

void Func()
{
    //静的変数
    static int num = 0;
    num++;

    printf("%d\n", num);
}

int main()
{
    Func();
    Func();
    Func();

    getchar();
}
1
2
3

静的変数は通常の変数宣言の前に「static」というキーワードを付加して宣言します。
静的変数は、プログラムの開始から終了まで存在し、宣言した関数内からのみアクセス可能という特徴があります。

関数Func内の静的変数numはプログラムの開始時に宣言と初期化が行われます。
実際の関数呼び出し時にはこの行は無視されます。

静的変数numは関数Funcが呼び出されるたびに「num++」で数値がひとつづつ増えていきます。
変数の寿命はプログラムの終了までなので、関数が終了しても値は消えません。

「static int num = 0;」があるからといって、関数の呼び出しごとに0で初期化されるわけではないことに注意してください。
static変数はどこに記述しようと、初期化が行われるのはプログラムの実行直後に一度だけです。
(グローバル変数も同様です)

まるでグローバル変数のような特徴を持ちますが、グローバル変数ではないので静的変数numにアクセスできるのは関数Func内からだけです。

#include <stdio.h>

void Func()
{
    static int num = 0;
    num++;

    printf("%d\n", num);
}

int main()
{
    Func();

	//エラー
    printf("%d\n", num);

    getchar();
}

静的変数を使用せずとも、同じことはグローバル変数で代用することは可能です。
しかしグローバル変数はどこからでもアクセスが出来てしまいますから、どこからでも値が書き換えられる危険性があります。

特定の関数内でのみ必要になる値は、その関数内からのみアクセスできるようになっているのが望ましいです。
「関数の実行ごとに値が消えては困る」「しかしどこからでもアクセスできるようにはしたくない」という場合には静的変数を使用するといいでしょう。

static変数の初期化

static変数はグローバル変数と同じく、初期化しない場合は自動的に0で初期化されます。

void Test()
{
    static int numA;      //0
	static int numB = 0;  //0
}

初期化はプログラムの実行直前に一度だけ行われますが、以下のコードは変数の初期化ではなく「代入」です。
そのため関数Testを呼ぶたびにstatic変数numの値は「5」になってしまい、staticを使用する意味がなくなってしまいます。

void Test()
{
    static int num;
	num = 5;
}

また、通常の変数は他の変数の値で初期化が可能ですが、static変数は定数でしか初期化はできません。

void Test(int x)
{
    //これはエラー
    static int numA = x;
}

static変数は「プログラムの開始時から生存する」ため、プログラムの実行途中に生成される値では初期化できないためです。

C言語では定数以外で初期化はできませんが、C++では変数でも初期化が可能です。
C++では関数呼び出しなどで最初にstatic変数にアクセスがあった時に初めて初期化処理が行われます。
(一度だけしか初期化されないのは同じです)

静的グローバル変数、静的関数

staticには、静的グローバル変数静的関数を作る機能もあります。

静的グローバル変数は、そのソースコード内からのみアクセスできるグローバル変数を作ります。
上で説明した関数内の静的変数は、正しくは「静的ローカル変数」というわけです。

静的関数は、そのソースファイル内からのみアクセスが可能な関数を作ることができます。

これらはソースコードを複数に分割してプログラムを作成するときに有効です。
ファイルの分割に関しては詳しく説明していませんので、ここでは説明は省きます。
詳しくはソースコードの分割で改めて説明します。