ローカル変数

**ローカル変数**（**局所変数**、）とは、プログラムの一部分でしか利用できない変数のことである。一般的にグローバル変数（大域変数）と対比される。ローカル変数の定義はプログラミング言語によって異なるので、詳細な説明は言語別の項に譲る。

## C言語
C言語およびC++の標準規格の文面では「ローカル変数」という用語は使われていないが、関数内の同じ「ブロック」という領域内からのみ参照可能な変数のことを便宜上ローカル変数と呼ぶことが多い。C99よりも前の規格ではブロックの先頭部分でのみ定義可能だったが、C99からはC++同様に任意の位置で定義可能である。

ある関数`f`におけるローカル変数`a`のスコープ (scope) すなわち可視性は、その関数`f`内において、その変数`a`が宣言された場所から、その変数`a`が定義されたブロックを抜けるまでである。スコープ外からは参照することができない。ローカル変数`a`を定義したブロック内で別の関数`g`を呼び出すと、関数`g`からはその変数`a`が見えなくなるが、メモリ上には依然として存在しており、関数`g`が終了して関数`f`に戻り、変数`a`のスコープに入ると再び見えるようになる。異なる関数（異なるブロック）で同じ名前のローカル変数を定義してもよく、お互いに影響を与えないので、名前の衝突を回避する必要がない。


```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行目で宣言されているローカル変数`i`のスコープは2行目から6行目の中括弧までであり、4行目で宣言されているローカル変数`j`のスコープは4行目から5行目の中括弧までである。


```c
void Function(void) {
    int i = 1; /* スコープの広いローカル変数 */
    {
        int j = 1; /* スコープの狭いローカル変数 */
    }
}
```


C言語のローカル変数の寿命 (lifetime) は、デフォルトではそのローカル変数を定義したブロックを抜けるまでである。ローカル変数は宣言により自動的にメモリ割り当てが行なわれるが、ブロックを抜けて寿命が尽きると自動的にメモリ割り当てが解除される。また、ローカル変数が定義された関数の制御フローが呼び出し元に返り、コールスタック領域が解放されると、そのローカル変数のメモリ領域は自動的に解放される。したがって「」とも呼ばれる。未初期化の自動変数の内容は不定 (indeterminate) である。

ローカル変数宣言にキーワード（静的記憶域クラス指定子）を付加すると、「静的ローカル変数」となり、変数寿命はプログラムの生存期間と同一となる。C言語では静的ローカル変数はグローバル変数と同じくプログラム開始処理以前に一度だけ初期化されるが、C++では制御フローが静的ローカル変数の定義箇所に到達した際にその初期化式が一度だけ評価され、その値によって変数は一度だけ初期化される。

C99の例を示す。なお、下記(1)はC言語およびC++03規格までのC++では
```c
auto int a = 0;
```
と等価だが、C++11以降はキーワードの意味が変更され、型推論の機能に利用されるようになったため、等価ではなくなった。

```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言語では静的ローカル変数はコンパイル時定数で初期化されなければならないため、コンパイル不可能である。

```cpp
#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
Javaにおける変数は大別して4種類ある。
* インスタンス変数 - クラスの各インスタンスに対して1つ存在
* クラス変数 - クラスに対して1つ存在
* ローカル変数 - メソッド内で宣言されている変数
* 仮引数 (parameters)

配列の要素は「インスタンス変数」に分類される。メソッド、コンストラクタ、catch節の引数は「仮引数」に分類される。

Javaにおいては、メソッド内で宣言されている変数をローカル変数と呼ぶ。スコープの概念およびブロックの構文はC/C++とほぼ同様だが、C/C++と異なり、静的ローカル変数は定義できない。フィールド（インスタンス変数とクラス変数）に関しては、コンパイラが型に応じて適切な既定値を割り当てるが、ローカル変数に関しては既定値は割り当てられない。

下記の例において、3行目で宣言されているローカル変数`i`のスコープは3行目から7行目の中括弧までであり、5行目で宣言されているローカル変数`j`のスコープは5行目から6行目の中括弧までである。


```java
class Foo {
    void bar() {
        int i = 1; // スコープの広いローカル変数
        {
            int j = 1; // スコープの狭いローカル変数
        }
    }
}
```


以下のような未初期化のローカル変数にアクセスするコードは、C/C++では未定義動作を引き起こすものの、コンパイルは通ってしまう。一方、Javaではコンパイルエラーとなる。

```java
int x;
if (x == 0) {
}
```


Javaのメモリ解放はガベージコレクションによって行なわれる。Javaのローカル変数はスタック領域に確保されるが、クラスや配列などの参照型の場合、オブジェクト本体はヒープ領域に作成される。ローカル変数の寿命が尽きて、その変数が指していたオブジェクトがまったく参照されなくなったとしても、そのオブジェクトのメモリ領域が直ちに解放されるとは限らない。

```java
{
    int[] a = new int[100];
}
// ブロックを抜けると変数 a は削除されるが、a が指していた配列オブジェクト本体の削除はガベージコレクタが担当する。
```


## 脚注
### 注釈

### 出典

## 関連項目
* グローバル変数
* スコープ (プログラミング)
* ブロック (プログラミング)