I - 1.08.変数のスコープ /

Time Limit: 0 msec / Memory Limit: 0 KB

前のページ | 次のページ

キーポイント

  • { }で囲われた部分のところをブロックという
  • 変数が使える範囲のことをスコープという
  • 変数のスコープは「変数が宣言されてからそのブロックが終わるまで」
  • スコープが重なっている場合は最も内側のブロックで宣言された変数が選ばれる

変数のスコープ

今までmain関数やif文の後には{ }を書いてきました。この{ }で囲った部分のところをブロックといいます。

あるブロックの中で宣言した変数は、それより内側のブロックでしか使えないというルールがあります。そして、その変数が使える範囲のことをスコープといいます。
具体例を見てみましょう。

#include <bits/stdc++.h>
using namespace std;

int main() {
  int x = 5; // xのスコープはこの行からmain関数のブロックの終わりまで

  if (x == 5) {
    int y = 10; // yのスコープはこの行からif文のブロックの終わりまで
    cout << x + y << endl;
  }

  cout << x << endl;
  cout << y << endl;
}
コンパイルエラー
In function ‘int main()’:
14:13: error: ‘y’ was not declared in this scope
   cout << y << endl;
       ^

「14:13: error: ‘y’ was not declared in this scope(14行13文字目 エラー: 'y'はこのスコープでは宣言されていません)」というコンパイルエラーが出ています。

変数yは7行目からはじめるif文のブロックで宣言されています。

  if (x == 5) {
    int y = 10; // yのスコープはこの行からif文のブロックの終わりまで
    cout << x + y << endl;
  }

しかし、13行目の

cout << y << endl;

yを宣言したブロックよりも外側にあるので、yを使うことができません。

なお、変数yのスコープ、つまり変数yが使える場所は、「変数が宣言されてからそのブロックが終わるまで」なので、8行目から10行目の間ということになります。

    int y = 10; // yのスコープはこの行からif文のブロックの終わりまで
    cout << x + y << endl;
  }

同じ名前の変数

変数を宣言するブロックが異なれば、同じ名前の変数を宣言することができます。

#include <bits/stdc++.h>
using namespace std;

int main() {
  int x = 10;

  if (x == 5) {
    int y = 10;
    cout << x + y << endl;

    // string y = "hello" 同じブロックに変数yがあるので宣言できない
  }

  if (x == 10) {
    string y = "hello"; // ブロックが違うので変数yを宣言できる
    cout << x << y << endl;
  }
}
実行結果
10hello

スコープがある理由

スコープがある理由はいくつかありますが、その中から一つ説明します。

スコープがない場合、一度宣言した変数等の名前は別の場所で使えなくなってしまいます。
プログラムの規模が大きくなってくると、その分多くの変数が用いられます。そのため、新しく変数を宣言しようとしたとき、まだ使われていない名前を考えることに手間がかかってしまいます。

スコープがあることで、プログラムの別の部分でどのような名前が使われているかをあまり考えること無く、変数等の名前を決められるようになります。

細かい話

細かい話なので、飛ばして問題を解いても良いです。

スコープが重なっている場合

変数を使える条件は次の2つです。

  1. 変数を使っている場所より前で宣言されている
  2. 変数を使っている場所と同じか、より外側のブロックで宣言されている

同じ名前の変数のスコープが重なっていて、候補が複数考えられる場合は次の条件で使う変数が決められます。

  1. 候補の変数のうち最も内側で宣言されている

例を見てみましょう。

#include <bits/stdc++.h>
using namespace std;

int main() {
  int x = 5;
  cout << x << endl; // 5

  if (x == 5) {
    cout << x << endl; // 5

    string x = "hello"; // int x = 5;のスコープと重なっている
    cout << x << endl; // hello
  }

  cout << x << endl; // 5
}
実行結果
5
5
hello
5

次の図はこのプログラムの動作を説明したものです。

スコープが重なっている変数のイラスト

上のプログラムの8行目のxにおいて、条件1.と条件2.に当てはまるxint x = 5;だけなので、出力は5になります。

9行目のxにおいて、条件1.と条件2.に当てはまるxint x = 5;だけなので、出力は5になります。

12行目のxにおいて、条件1.と条件2.に当てはまるのはint x = 5;string x = "hello";の2つがありますが、条件3.からstring x = "hello";が選ばれ、出力はhelloになります。

15行目のxにおいて、条件1.と条件2.に当てはまるのは再びint x = 5;だけになるなので、出力は5になります。

この挙動はしばしばバグの原因になります。注意してください。


問題

リンク先の問題を解いてください。