C言語

変数とスコープ

C言語では、変数が使える範囲(スコープ)と、変数が存在している期間(寿命)が決まっています。
この2つはセットで理解するとわかりやすいです。
 スコープ(有効範囲):その変数を「使える範囲」
 寿命(ライフタイム):その変数が「メモリ上に存在する期間」
今回は、この2つについて説明します。

関数内で定義した変数(ローカル変数)

関数の中で定義された変数は「ローカル変数」と呼ばれます。
今まで使ってきた変数はすべてローカル変数でした。

ローカル変数の特徴

定義された関数の中だけで使えます。他の関数からは見えません。
関数が呼ばれるたびに新しく作られ、関数を抜けると消えてしまいます。

このため、次のように、同じ変数名を他の関数で使用しても、別の変数名として扱われます。

#include <stdio.h>

void showNumber(void)
{
    int num = 10;  // ローカル変数
    printf("%d\n", num);
}

int main(void)
{
    int num = 5;  // ローカル変数
    
    showNumber();
    
    printf("%d\n", num);  // ← showNumber関数内の変数numとは別の変数として扱われる
    
    return 0;
}

関数の外で定義した変数(グローバル変数)

関数の外で定義された変数は「グローバル変数」といいます。

グローバル変数の特徴

プログラム全体で共通の変数として使用できます。
このため、プログラムの開始から終了するまで消えることはありません。(プログラムが終了するまで値は保持されます。)

#include <stdio.h>

int count = 0;  // グローバル変数

void add(void)
{
    count++;  // どの関数からでも使える
}

int main(void)
{
    add();
    add();
    printf("%d\n", count);  // → 2 と表示される
    return 0;
}

プログラム全体で共通の変数とは
プログラムの書かれたファイルは複数のファイルに分割することができます。
プログラム全体で共通の変数とは、分割された各ファイルで共通に使える変数ということです。
ファイル分割については、別の記事にする予定で、そこで詳しく説明します。

static(スタティック)変数

static変数を使用するには、変数定義する際に、型指定の前に static を付けます。
static は、「静的」という意味で、いくつかの使い方があります。
ここでは「変数」に使った場合の2つの意味を紹介します。

関数内で使うstatic変数

ローカル変数は、関数が呼ばれるたびに新しく作られ、関数を抜けると消えてしまいました。
しかし、関数内でstaticを付けると、ローカル変数のように見えても、寿命がプログラム終了まで続くようになります。
つまり、関数内でのみ使用可能というのは、ローカル変数と同じです。
ですが、関数を抜けても、変数は消えず、値は保持されます。次に関数が呼ばれたときに、前の値が使えるという働きをします。

#include <stdio.h>

void counter(void)
{
    static int num = 0;  // 初回だけ初期化される
    num++;
    printf("%d\n", num);
}

int main(void)
{
    counter();  // 1
    counter();  // 2
    counter();  // 3
    return 0;
}

このプログラムを実行すると次のような結果になります。

1
2
3

counter関数を3回呼び出していますが、変数numの値は、前回呼び出した値からインクリメントされていることがわかります。

counter 関数で、初めて呼び出しされたときにのみ、numが新しく作られて、初期化が行われます。
このため、2回目以降にcunter 関数が呼び出されたときは、変数numが新しく作られることはありません。

関数の外で使うstatic変数

関数の外で定義された変数に static を付けると、その変数は「そのファイル内でのみ有効」になります。
グローバル変数は、複数のファイルで共通して使用できるのに対して、static変数は、そのファイル内でのみで使用できます。
ファイルが1つしかない場合は、グローバル変数とstatic変数は、ほぼ同じです。
※厳密な違いについては、別で記事にします。

#include <stdio.h>

static int count = 0;  // static変数

void add(void)
{
    count++;  // どの関数からでも使える
}

int main(void)
{
    add();
    add();
    printf("%d\n", count);  // → 2 と表示される
    return 0;
}


このプログラムは、「グローバル変数の特徴」で使用したプログラムの変数定義にstatic を付けただけです。
このため、グローバル変数とstatic変数の違いが分かりづらいかもしれません。

グローバル変数とstatic変数の違いの詳細は、ファイル分割の記事の中で説明します。
今は、グローバル変数は、複数ファイルで共通に使える。と覚えておけば十分です。

同じ名前の変数があった場合

グローバル変数とstatic変数が同名の場合

もし、同じ名前のグローバル変数とローカル変数が存在した場合、ローカル変数が優先されます。

#include <stdio.h>

int value = 100;  // グローバル変数

void show(void)
{
    int value = 10;  // ローカル変数(グローバルと同名)
    printf("%d\n", value);  // → 10 が表示される
}

int main(void)
{
    show();
    printf("%d\n", value);  // → 100 が表示される
    return 0;
}

実行結果は、

10
100

グローバル変数 value は、100だが、ローカル変数が優先されるため、show関数のローカル変数 value の10が表示されて、main関数のprintf関数では100が表示されます。

グローバル変数と static変数(関数外)が同名の場合

グローバル変数と static変数(関数外)が同名の場合は、コンパイルエラーになります。

int value = 100;     // グローバル変数
static int value = 10;  // ❌ コンパイルエラー

static変数(関数内)とグローバル変数が同名の場合

ローカル変数と同じ扱いで、関数内staticが優先されます。

static変数(関数外)とローカル変数が同名の場合

グローバル変数とローカル変数の場合と同じ挙動です。ローカル変数が優先されます。

まとめ

  • スコープは「変数を使える範囲」
  • 寿命は「変数が存在する期間」
  • ローカル変数:関数の中だけ・関数が終わると消える
  • グローバル変数:全体で共有・プログラム終了まで残る
  • static変数
    • 関数内で定義した場合:関数内でのみ使用可能で、関数を抜けても、変数は消えず、値は保持されます。次に関数が呼ばれたときに、前の値が使えるという働きをする
    • 関数外で定義した場合:「そのファイル内でのみ有効」になる
  • 同じ名前なら「より内側(ローカル)」が優先される

-C言語