static付きローカル変数が関数呼び出しをまたいで値を保持し続ける
関数内でstaticを付けて宣言した変数は、関数を抜けても値が消えません。次回その関数が呼ばれたときも、前回の値から処理が続きます。
なぜエラーが出ないのか
出力: 1
(エラーなし)- Cは何も報告しません。コンパイルも実行も正常に完了するためです
出力: 1- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 #include <stdio.h> 2 3 int nextId(void) { 4 int id = 0; ^ 5 id++; 6 return id; 7 } 8 9 int main(void) { 10 printf("%d\n", nextId()); 11 printf("%d\n", nextId()); 12 printf("%d\n", nextId()); 13 return 0; 14 }
staticを付けないと、呼ばれるたびにid=0から初期化されるため常に1が返ります。staticを付けると前回の値が保持され、呼ぶたびに増加していきます。
直し方: (空) を static にします。
パターン2
1 #include <stdio.h> 2 3 int counter(void) { 4 int count = 10; ^ 5 count += 5; 6 return count; 7 } 8 9 int main(void) { 10 printf("%d\n", counter()); 11 printf("%d\n", counter()); 12 return 0; 13 }
初期化式(count = 10)は最初の1回だけ実行されます。staticを付けなければ毎回10からやり直しになるため、常に同じ結果になります。
直し方: (空) を static にします。
パターン3
1 #include <stdio.h> 2 3 int total(void) { 4 int sum = 0; ^ 5 sum += 3; 6 return sum; 7 } 8 9 int main(void) { 10 printf("%d\n", total()); 11 printf("%d\n", total()); 12 printf("%d\n", total()); 13 return 0; 14 }
普通のローカル変数だと思い込んでいると、カウンタや合計値が意図せず積み上がらない原因になります。
直し方: (空) を static にします。
パターン4
1 #include <stdio.h> 2 3 int ticket(void) { 4 int num = 100; ^ 5 num++; 6 return num; 7 } 8 9 int main(void) { 10 printf("%d\n", ticket()); 11 printf("%d\n", ticket()); 12 return 0; 13 }
staticが無いと呼ぶたびに100から初期化されるため、常に同じ値が返ります。
直し方: (空) を static にします。
パターン5
1 #include <stdio.h> 2 3 int balance(void) { 4 int amount = 1000; ^ 5 amount -= 100; 6 return amount; 7 } 8 9 int main(void) { 10 printf("%d\n", balance()); 11 printf("%d\n", balance()); 12 return 0; 13 }
初期化式は最初の1回だけ実行されます。staticが無ければ毎回1000からやり直しになります。
直し方: (空) を static にします。
よくある誤解
普通のローカル変数と同じ感覚で「呼ばれるたびに初期値に戻る」と思ってしまうと、カウンタや合計値が意図せず積み上がっていく原因になります。初期化式(例: static int count = 0;)は最初の1回だけ実行され、2回目以降の呼び出しでは無視されます。
実務での勘所
static付きのローカル変数が値を保持し続けるのは、スタック(関数を抜けると消える領域)ではなく、グローバル変数と同じ静的データ領域に配置されるためです。名前のスコープだけがその関数の中に限定されている、という点を除けば、実質的にグローバル変数と同じ寿命を持ちます。この性質は意図して使えば便利な道具にもなり、関数が呼ばれるたびに一意なIDを発行するカウンタや、一度計算した結果を次回以降使い回すキャッシュのような用途で、グローバル変数を汚さずに状態を持たせる目的で使われます。