ローカル変数ローカル変数(局所変数、英: local variable)とは、プログラムの一部分でしか利用できない変数のことである。一般的にグローバル変数(大域変数)と対比される。ローカル変数の定義はプログラミング言語によって異なるので、詳細な説明は言語別の項に譲る。 C言語C言語およびC++の標準規格の文面では「ローカル変数」という用語は使われていないが、関数内の同じ「ブロック」という領域内からのみ参照可能な変数のことを便宜上ローカル変数と呼ぶことが多い。C99よりも前の規格ではブロックの先頭部分でのみ定義可能だったが、C99からはC++同様に任意の位置で定義可能である。 ある関数 #include <stdio.h>
void g(void); /* 関数 g の前方宣言 */
void f(void) {
/* 関数 f のローカル変数 */
int a, b;
a = 1;
b = 2;
g(); /* 関数 g の呼び出し */
/* 関数 f のローカル変数は、他の関数内のローカル変数とは別物であり、影響を受けない */
printf("%d, %d\n", a, b);
}
void g(void) {
/* 関数 g のローカル変数 */
int b;
/* 以下はコンパイルエラーとなる */
/*a = -1;*/
/* 他の関数内の同名のローカル変数には影響を与えない */
b = -2;
}
同じ関数内でも、属するブロックによってローカル変数のスコープ(および寿命)が異なる。下記の例において、2行目で宣言されているローカル変数 void Function(void) {
int i = 1; /* スコープの広いローカル変数 */
{
int j = 1; /* スコープの狭いローカル変数 */
}
}
C言語のローカル変数の寿命 (lifetime) は、デフォルトではそのローカル変数を定義したブロックを抜けるまでである。ローカル変数は宣言により自動的にメモリ割り当てが行なわれるが、ブロックを抜けて寿命が尽きると自動的にメモリ割り当てが解除される。また、ローカル変数が定義された関数の制御フローが呼び出し元に返り、コールスタック領域が解放されると、そのローカル変数のメモリ領域は自動的に解放される。したがって「自動変数」[注釈 1]とも呼ばれる。未初期化の自動変数の内容は不定 (indeterminate) である[1]。 ローカル変数宣言に C99の例を示す。なお、下記(1)はC言語およびC++03規格までのC++では #include <stdio.h>
int Function1(void) {
int a = 0; // (1) 通常のローカル変数(自動変数)の宣言と定義。初期化は関数を呼び出すたびに毎回行なわれる。
a += 1;
return a;
}
int Function2(void) {
static int s = 0; // (2) 静的ローカル変数の宣言と定義。初期化は一度だけ行なわれる。
s += 1;
return s;
}
int main(void) {
for (int i = 0; i < 5; ++i) {
printf("auto(%d) = %d\n", i, Function1());
printf("static(%d) = %d\n", i, Function2());
}
return 0;
}
以下のコードはC++ではコンパイル可能だが、C言語では静的ローカル変数はコンパイル時定数で初期化されなければならないため、コンパイル不可能である。 #include <stdio.h>
int Func(int x) {
if (x > 0) {
static int firstPositive = x;
return firstPositive;
} else if (x < 0) {
static int firstNegative = x;
return firstNegative;
}
return 0;
}
int main(void) {
printf("%d\n", Func(1)); // 1
printf("%d\n", Func(5)); // 1
printf("%d\n", Func(-5)); // -5
printf("%d\n", Func(-1)); // -5
printf("%d\n", Func(0)); // 0
return 0;
}
C++ではSingleton パターンの実現に静的ローカル変数が利用されることがある。 また、C++では変数の寿命が尽きるときにデストラクタが呼ばれる。この性質を利用したデザインパターンがRAIIである。特に静的でないローカル変数(自動変数)の場合は、関数を抜けるときに必ず寿命が尽きるため、関数の脱出経路を問わずに確実に実行したい後始末処理(動的確保したメモリの解放やファイルのクローズなど)を記述するのによく使われる。 Java配列の要素は「インスタンス変数」に分類される。メソッド、コンストラクタ、catch節の引数は「仮引数」に分類される。 Javaにおいては、メソッド内で宣言されている変数をローカル変数と呼ぶ。スコープの概念およびブロックの構文はC/C++とほぼ同様だが、C/C++と異なり、静的ローカル変数は定義できない。フィールド(インスタンス変数とクラス変数)に関しては、コンパイラが型に応じて適切な既定値を割り当てるが、ローカル変数に関しては既定値は割り当てられない[3]。 下記の例において、3行目で宣言されているローカル変数 class Foo {
void bar() {
int i = 1; // スコープの広いローカル変数
{
int j = 1; // スコープの狭いローカル変数
}
}
}
以下のような未初期化のローカル変数にアクセスするコードは、C/C++では未定義動作を引き起こすものの、コンパイルは通ってしまう。一方、Javaではコンパイルエラーとなる。 int x;
if (x == 0) {
}
Javaのメモリ解放はガベージコレクションによって行なわれる。Javaのローカル変数はスタック領域に確保されるが、クラスや配列などの参照型の場合、オブジェクト本体はヒープ領域に作成される。ローカル変数の寿命が尽きて、その変数が指していたオブジェクトがまったく参照されなくなったとしても、そのオブジェクトのメモリ領域が直ちに解放されるとは限らない。 {
int[] a = new int[100];
}
// ブロックを抜けると変数 a は削除されるが、a が指していた配列オブジェクト本体の削除はガベージコレクタが担当する。
脚注注釈出典
関連項目 |