C言語の静的変数staticを完全ガイド!初心者でもわかる仕組みと使い方
生徒
「C言語の変数にstaticって書いてある例を見ました。これって何をしているんですか?」
先生
「staticは静的変数を宣言するためのキーワードで、値が関数を抜けても消えないように保存しておく仕組みを作ります。」
生徒
「関数が終わっても覚えているってことですか?どんな時に便利なんでしょう?」
先生
「呼び出し回数のカウントや前回の値の保持などに使えます。まずは基本を一緒に見ていきましょう。」
1. 静的変数staticとは?基礎の基礎
静的変数は、プログラムの実行中ずっと記憶領域を保ち続ける変数です。C言語では、スコープと記憶期間という考え方で変数を整理します。スコープは見える範囲、記憶期間は生きている時間のことです。普通のローカル変数は関数を出ると消えますが、静的変数は関数を出ても値が残ります。まるで机の引き出しにメモを入れておき、あとでまた取り出せるようなイメージです。プログラムが終了するまで片付けられない専用の引き出しを作る、と考えると覚えやすいでしょう。
初心者がつまずきやすい点は、staticは二種類の場面で登場することです。ひとつは関数の中で使う静的なローカル変数、もうひとつはファイルの先頭で使う静的なグローバル変数や関数の宣言です。前者は値を保持する目的、後者は他のファイルから見えなくする目的が中心で、どちらも「静的」という言葉でまとめられています。
2. 関数内で使うstatic:値を覚えるローカル変数
関数の中でstaticを付けると、その変数は初期化が一度だけ行われ、関数を呼び直しても前回の値が残ります。例えば呼び出し回数を数える用途が典型例です。ゲームの得点や、前回の温度を覚えて差を計算する場面など、身近な処理で役立ちます。
#include <stdio.h>
void hello(void)
{
static int count = 0; // 一度だけ初期化。関数を抜けても値が残る
count++;
printf("こんにちは 回数 %d\n", count);
}
int main(void)
{
hello();
hello();
hello();
return 0;
}
実行すると、呼ぶたびに数が増えます。
こんにちは 回数 1
こんにちは 回数 2
こんにちは 回数 3
ここでのポイントは、関数の外からはcountが見えないことです。スコープは関数の中だけ、でも記憶期間はプログラムの終了まで続きます。見える範囲と生きている時間が別々に決まる、というのが静的変数を理解する鍵になります。
3. ファイル先頭で使うstatic:外部公開を防ぐファイル内限定
ファイルの先頭でstaticを付けると、その変数や関数は同じファイル内だけで有効になります。これはリンケージというつながりの範囲を制御する機能です。大きなプロジェクトでは、名前の衝突を防ぎ、内部実装を隠すために使われます。家庭内のメモを部屋の扉の内側に貼るようなもので、別の部屋からは見えません。
/* ファイルの先頭に置く例 */
static int cache_value = 0; // このファイル内だけで使う内部データ
static int twice(int x) // この関数もファイル内限定
{
return x * 2;
}
int public_api(int x) // これは外部から呼べる
{
if (cache_value == 0) {
cache_value = twice(x);
}
return cache_value;
}
この書き方により、他のファイルから間違って内部の変数や関数を触られることを防げます。初心者の段階でも、後でプログラムを分割する時に役立つ基礎として覚えておくと安心です。
4. 初期化のルールとデータ型の基本
静的変数は、初期化を書かなくてもゼロで初期化されます。数値はゼロ、ポインタは空を表す特別な値になります。これはC言語の記憶領域の決まりで、プログラムの開始時に準備されます。型はintやcharなどの基本型でも構造体でも使えます。学習の初期は、intやdoubleなど馴染みやすい型から試すと理解が進みます。
#include <stdio.h>
void counter(void)
{
static int n; // ここは自動的に0になる
n += 5;
printf("合計 %d\n", n);
}
int main(void)
{
counter();
counter();
return 0;
}
合計 5
合計 10
この例では明示的な初期化を書いていませんが、最初の呼び出し時にゼロから計算が進みます。毎回新しく作られる普通のローカル変数と違い、静的変数は一度作って使い回す点が重要です。
5. よくある用途:回数計測 前回値の保持 キャッシュ
静的変数は、呼び出し回数の記録、前回の入力の保存、計算結果のキャッシュなどに向いています。たとえば温度計の差分や平均を段階的に求めたいときに便利です。初心者が最初に試すなら、合計と件数を覚えて平均を出す小さな関数がおすすめです。
#include <stdio.h>
double moving_average(double x)
{
static double sum = 0.0; // 合計を保持
static int count = 0; // 件数を保持
count++;
sum += x;
return sum / count;
}
int main(void)
{
printf("%.2f\n", moving_average(10.0));
printf("%.2f\n", moving_average(20.0));
printf("%.2f\n", moving_average(30.0));
return 0;
}
10.00
15.00
20.00
毎回の計算に前回の情報が自然につながるので、簡単な学習データの処理や小さなゲームの記録などに応用できます。
6. staticとグローバルの違いを図解イメージで整理
グローバル変数はどこからでも見える広い掲示板、関数内staticは部屋の引き出しにしまった個人メモ、ファイル先頭staticは部屋の内壁に貼った限定掲示、と考えると違いがはっきりします。見える範囲が違っても、静的という言葉が示すのは「長く残る記憶領域」です。用途に合わせて範囲を狭めれば、プログラムは安全で読みやすくなります。
7. 注意点:再初期化できない 多用しすぎない テストしやすさ
静的変数は一度初期化された後、プログラムが終わるまで同じ領域を使い続けます。途中で関数の外から簡単にリセットできないため、動作確認や単体テストでは扱いに注意が要ります。大きな処理で多用すると、状態が隠れて読みにくくなることがあります。小さく目的を絞り、外部から渡せる値は引数で受け取る、といった設計を心がけると学習がスムーズです。
8. データ型と初期値の実践ポイント
整数で数えるだけならint、精度が必要ならdouble、真偽で分岐なら整数で扱う、というように目的に合う型を選びます。静的変数は初期化を書いた時点の値で固定されます。たとえば日付や乱数の種を状況に合わせて変えたい場合は、最初の一回だけ初期化する構成を用意しておくと扱いやすくなります。
#include <stdio.h>
int next_id(void)
{
static int id = 100; // 開始番号を一度だけ設定
id++;
return id;
}
int main(void)
{
printf("%d\n", next_id());
printf("%d\n", next_id());
return 0;
}
101
102
このように静的変数は連番を発行する処理とも相性が良く、番号管理や簡単な識別に役立ちます。
9. ファイル内限定の関数と変数で安全に分割
プログラムを複数ファイルに分けるときは、外部に見せる必要のない関数と変数にstaticを付けます。これにより、同じ名前を別ファイルでも安心して使えます。内部実装が外から見えないため、後で変更しても影響範囲を小さく保てます。学習段階からこの習慣を持っておくと、保守や拡張がぐっと楽になります。
10. ありがちなつまずきとシンプルな回避策
ひとつ目は、静的変数の値が残ることを忘れて「前と同じ結果にならない」と戸惑うパターンです。学習用の確認では、表示に回数や現在値を必ず一緒に出すと動きが追いやすくなります。ふたつ目は、外から触れないのに別の関数で同じ名前を使ってしまう混乱です。スコープの範囲を短くとり、必要最低限の名前を付けるだけで多くの問題が解決します。三つ目は、初期化の書き方を忘れることです。静的変数の初期化は一度だけ、という合言葉で覚えておきましょう。
11. ミニ練習:前回との差を出す小さな関数
最後に、前回の値を覚えて差を表示する小さな練習を示します。連続する入力の変化を見る道具として役立ちます。
#include <stdio.h>
void diff_print(int x)
{
static int prev = 0; // 前回値を保持
int d = x - prev;
printf("入力 %d 差 %d\n", x, d);
prev = x;
}
int main(void)
{
diff_print(3);
diff_print(7);
diff_print(4);
return 0;
}
入力 3 差 3
入力 7 差 4
入力 4 差 -3
前回値を保持することで、流れのあるデータの変化を簡単に追いかけられます。静的変数の強みがよく分かる定番練習です。
12. この記事のポイントをもう一度
- 関数内staticは値が消えないローカル変数。スコープは狭いが記憶期間は長い。
- ファイル先頭staticは内部限定の公開範囲。外から見えない設計で安全性が上がる。
- 初期化は一度だけ。書かなくてもゼロになるため基本が扱いやすい。
- 用途は回数計測 前回値 キャッシュ 連番など。小さく使うと効果的。
- 多用しすぎると状態が見えにくくなるため、必要な場面に限定する。