
C言語基礎|ブロック有効範囲
同じ名前でも、別モノとして安全に使える仕組み
C言語でコードを書いていると、「あれ、この変数名どこまで使えるんだっけ?」ってなる瞬間があります。
とくに関数を増やしたり、if や for の中で変数を宣言し始めると、名前の衝突が気になってきますよね。
そこで大事なのが 有効範囲(scope)。
今回はその中でも、いちばん身近で登場回数が多い ブロック有効範囲(block scope) をやさしく押さえます。

有効範囲とは何か
有効範囲は一言でいうと、
その名前(識別子)が「通用する」範囲
です。
同じ tmp という名前でも、通用する範囲が別なら、別の変数として扱われます。
識別子に関する用語の整理
| 用語 | 意味 | 例 |
|---|---|---|
| 識別子 | 変数名・関数名などの名前 | total, tmp, power |
| 有効範囲 | その識別子が使える範囲 | ブロック内だけ等 |
| ブロック | { と } で囲まれたまとまり(複合文) | if { ... }, for { ... } |
| ブロック有効範囲 | ブロック内で宣言した名前が通用する範囲 | 宣言位置〜対応する } |
この表は「scopeの話」をするときに混ざりやすい言葉を、最初に整理して迷子を防ぐためのものです。
サンプルプログラム
同じ名前 total を、別ブロックで使っても問題ないことを、出力の違いで体感できるプログラムです。
プロジェクト名:chap6-10-1 ソースファイル名:chap6-10-1.c
Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。
#include <stdio.h>
int main(void)
{
int total = 0; // main全体で使うtotal
puts("買い物の合計金額を計算します。");
// ブロック1:飲み物コーナー
{
int total = 0; // ここで別のtotal(mainのtotalとは別物)
int price;
puts("【飲み物】3つの値段を入力してください。");
for (int i = 1; i <= 3; i++) {
printf("%dつ目の値段:", i);
scanf("%d", &price);
total += price;
}
printf("飲み物の小計:%d円\n", total);
}
// ブロック2:お菓子コーナー
{
int total = 0; // これも別のtotal
int price;
puts("【お菓子】2つの値段を入力してください。");
for (int i = 1; i <= 2; i++) {
printf("%dつ目の値段:", i);
scanf("%d", &price);
total += price;
}
printf("お菓子の小計:%d円\n", total);
}
printf("全体の合計(mainのtotal):%d円\n", total);
return 0;
}実行例
買い物の合計金額を計算します。
【飲み物】3つの値段を入力してください。
1つ目の値段:120
2つ目の値段:150
3つ目の値段:130
飲み物の小計:400円
【お菓子】2つの値段を入力してください。
1つ目の値段:200
2つ目の値段:180
お菓子の小計:380円
全体の合計(mainのtotal):0円最後が 0円 なのがポイントです。
ブロックの中の total は、main の total とは完全に別の変数なので、外には影響しません。
ブロック有効範囲は「宣言位置から } まで」
コードだけだと見落としやすいので、範囲を表にまとめます。
total が通用する範囲(イメージ)
| 変数 | 宣言場所 | 通用する範囲 |
|---|---|---|
| mainのtotal | mainの先頭 | mainの末尾まで(ただし内側で同名が出ると隠れる) |
| 飲み物ブロックのtotal | 飲み物の { の中 | そのブロックの } まで |
| お菓子ブロックのtotal | お菓子の { の中 | そのブロックの } まで |
この表は「宣言された場所から、その宣言を囲むブロック終端の } まで」というルールを、範囲として見える化したものです。
“同名が出ると隠れる”という感覚(シャドーイング)
ブロックの中で同じ名前を宣言すると、外側の同名は一時的に見えなくなります。
これを 隠蔽(シャドーイング) と呼びます。
同名があるとき、どれが使われる?
| 場所 | total と書いたら、どれ? |
|---|---|
| ブロックの外(main直下) | mainのtotal |
| 飲み物ブロックの中 | 飲み物ブロックのtotal |
| お菓子ブロックの中 | お菓子ブロックのtotal |
つまり、同じ名前を使っても動くけど、読み手が混乱しやすいので、実務では「わざと同名」は避けることが多いです(ただし学習では仕組みを理解するのに超有効です)。
登場する命令の書式と「何をする命令か」
この記事で出てきたものを、ブロック有効範囲の理解につながる形でまとめます。
複合文(ブロック)の書式
- { 文の並び }
何をする?
複数の文をひとまとまりにするための構文です。
この中で宣言した変数は、そのブロックの中だけで使えるのがポイントです。
変数宣言の書式
- 型 変数名;
- 型 変数名 = 初期値;
何をする?
変数を作ります。ブロック内で宣言すると、その変数名はブロック内だけに限定されます。
for 文の書式
- for (初期化; 条件; 更新) 文
何をする?
繰り返し処理をします。
今回の例では「入力を複数回読む」ために使っています。
補足:C99以降だと for の初期化で int i を宣言できます。
この i も for の中(正確にはそのブロック)だけで通用します。
printf / puts / scanf の書式
- printf(書式文字列, 値…)
- puts(文字列)
- scanf(書式文字列, 変数のアドレス…)
何をする?
表示と入力です。ブロック有効範囲そのものを作る命令ではないですが、結果を観察するために使います。
演習問題
演習6-7
画面に「こんにちは。」と表示する関数を作成せよ。
仕様:引数なし、返却値なし
- 関数プロトタイプ:void hello(void);
解答例
プロジェクト名:chap6-10-2 ソースファイル名:chap6-10-2.c
Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。
#include <stdio.h>
void hello(void)
{
puts("こんにちは。");
}
int main(void)
{
hello();
return 0;
}解説
- hello は値を返さないので返却値型は void
- 引数を受け取らないので (void) と書く
- main から hello() として呼び出す
重要ポイントのまとめ(ここだけ覚えればOK)
ブロック有効範囲の要点
| ルール | ひとこと |
|---|---|
| ブロック内で宣言した名前はブロック内だけ | 外に出ると使えない |
| 使えるのは宣言した行から } まで | 宣言より前では使えない |
| 内側で同名を宣言すると外側は隠れる | どっちの変数か注意 |
