C言語のグローバル変数・スコープ・変数の寿命・static変数を解説。
static でファイル外から隠すextern で別ファイルから参照int main(void) { int a = 10; // main内で有効 if (a > 0) { int b = 20; // このブロック内だけで有効 printf("%d\n", a+b); // OK } // printf("%d\n", b); ← エラー!bはスコープ外 }
| 種類 | 宣言場所 | 生成タイミング | 消滅タイミング |
|---|---|---|---|
| auto(ローカル) | 関数・ブロック内 | ブロックに入ったとき | ブロックを抜けたとき |
| グローバル | 関数の外 | プログラム開始時 | プログラム終了時 |
| static | 関数内(static付き) | プログラム開始時 | プログラム終了時 |
void example(void) { int a = 1; // auto: 呼ぶたびに生成→抜けると消滅 static int b = 1; // static: 一度だけ生成。値は次回も残る a++; b++; printf("a=%d b=%d\n", a, b); } int main(void) { example(); // a=2 b=2 example(); // a=2 b=3 ← aはリセット、bは保持 example(); // a=2 b=4 }
example() を3回呼んだときに各変数がどう変化するかアニメーションで確認できます。#include<stdio.h> int counter = 0; // グローバル変数(main等の外) void increment(void) { counter++; // 引数なしでも触れる } int main(void) { increment(); increment(); increment(); printf("%d\n", counter); // → 3 }
staticをつけるとプログラム終了まで残ります。void count(void) { static int n = 0; // 初回のみ0で初期化。以降は保持 n++; printf("呼ばれた回数: %d\n", n); } int main(void) { count(); // → 1 count(); // → 2 count(); // → 3 }
#include <stdio.h> #include <stdlib.h> int g_init = 100; // 💾 データ領域(初期値あり) int g_uninit; // 🌐 BSS領域(初期値なし → 自動的に0) void func(void) { int local = 5; // 📚 スタック領域(呼び出しごとに生成) static int s = 0; // 💾 データ領域(1度だけ生成) int *heap = malloc(sizeof(int)); // 🧱 ヒープ領域 *heap = 42; free(heap); } int main(void) { func(); return 0; }
| 変数の種類 | 宣言場所 | メモリ領域 | 生成タイミング | 初期値 |
|---|---|---|---|---|
| ローカル(auto) | 関数内 | 📚 スタック | 関数呼び出し時 | 不定(ゴミ値) |
| ローカル(static) | 関数内(static付き) | 💾 データ / BSS | プログラム開始時 | 0 または指定値 |
| グローバル(初期化あり) | 関数の外 | 💾 データ領域 | プログラム開始時 | 指定値 |
| グローバル(初期化なし) | 関数の外 | 🌐 BSS領域 | プログラム開始時 | 0(自動) |
| malloc で確保 | 関数内で動的 | 🧱 ヒープ | malloc呼び出し時 | 不定(callocなら0) |
| 文字列リテラル | ソース内の "..." | 📜 テキスト | プログラム開始時 | 書き換え不可 |
void b(void) { int y = 20; } // b のスタックフレーム void a(void) { int x = 10; b(); } // a のスタックフレーム int main(void) { a(); return 0; }
static ローカル変数で呼び出し回数を記録const int のグローバル定数を定義この講座の理解度をチェックしましょう!
グローバル変数は宣言時に自動的に 0 で初期化されます。ローカル変数は初期化しないと未定義値になります。
static ローカル変数は関数を抜けても値が消えず、次回呼び出し時に前の値が残っています。
グローバル変数はプログラムのどこからでも変更可能なため、意図しない変更によるバグが発生しやすくなります。