第34回
変数の通用範囲~自動変数と静的変数/局所変数と広域変数

自動変数と静的変数

関数内で宣言された変数で、関数の処理が終わってからもその値を保持していたい場合があります。そのような場合には、変数を静的変数として宣言します。

関数終了後も値を保持する変数

たとえば、長いテキストファイルの中から指定した単語を探し出す関数があったとします。探したい単語へのポインタtと改行までの1行の文字列へのポインタstrを引数とし、先頭から何バイト目に目的の単語があったかを返す──という仕様になるでしょう。
int search(const char t, const char *str)
{
        :
}

単に単語を見つけるだけではなく、見つけた単語の数を数える必要があったとします。関数の戻り値は1つしか設定できないので、関数内に『見つけた単語の数を数えるための変数』を用意しなければなりません。

変数名をcountとした場合、これを以下のように宣言しても期待する結果は得られません。
int search(const char t, const char *str)
{
  int count;
        :
  (str内にtが見つかった場合)
    count++;
}

static修飾子

countは自動変数となるため、関数search内の処理が終了したら消滅します。そして次にsearch関数が呼び出されたときには新たに変数countが生成されるため、これまでの値は保持されていません(宣言された直後には、変数の値は不定となっています)。

関数内で宣言された変数の値を、関数の終了後にも保持しておきたい場合には、変数にstatic修飾子を付けて宣言します。
int search(const char t, const char *str)
{
  static int count = 0;
        :
  (str内にtが見つかった場合)
    count++;
}

静的変数の初期化

以下のように宣言と同時に初期値を代入しておけば、変数countは関数searchの最初の呼び出し時に0で初期化され、それ以降の呼び出し時にはそれ以前の値を保持し続けます。
static int count = 0;

宣言と初期化を別の処理にしてしまうと、関数が呼び出されるたびに0で初期化されるため、staticで宣言した意味がなくなります。
int search(const char t, const char *str)
{
  static int count;
  count = 0; ------------ 関数が呼び出されるたびにこの処理が実行されてしまう
        :

プログラムで試す

自動変数と静的変数の違いを、プログラムで確認してみましょう。リスト1ではmainからcount関数を10回呼び出しています。count関数の中では自動変数aと静的変数bを宣言してそれぞれ0で初期化して両者の値をprintf関数で表示し、その後インクリメント演算子++で値を1増加します。

実行すると画面1のようになります。自動変数aの値はcount関数が呼び出されるたびに初期化されるため常に0であるのに対し、静的変数bは前回呼び出されたときの値が保持されているため、1ずつ増加していきます。

リスト1:自動変数と静的変数の違いを調べる(ex3401.c)
#include <stdio.h>

void count(void);

int main(void)
{
  int i;

  /* countを10回呼び出す */
  for (i = 0; i < 10; i++) {
    printf("%d : ", i+1);    /* 呼び出し回数 */
    count();
  }
  return (0);
}

void count(void)
{
  auto int a = 0;   /* 自動変数 */
  static int b = 0; /* 静的変数 */

  printf("auto -- %d / static -- %d\n", a, b);
  /* 呼ばれるたびに1増加 */
  a++;
  b++;
}

画面1:ex3401.exeの実行結果
C:\CLANG\EXE>ex3401
1 : auto -- 0 / static -- 0
2 : auto -- 0 / static -- 1
3 : auto -- 0 / static -- 2
4 : auto -- 0 / static -- 3
5 : auto -- 0 / static -- 4
6 : auto -- 0 / static -- 5
7 : auto -- 0 / static -- 6
8 : auto -- 0 / static -- 7
9 : auto -- 0 / static -- 8
10 : auto -- 0 / static -- 9
C:\CLANG\EXE>