□演習 10.7 (三角形が出来るかどうかの判定) 3つの実数 a, b, c をパラメータとして受 け取り、a, b, cを3辺の長さとする三角形が存在するかどうかの判定結果を返す関数を定 義せよ。
10.2. 名前の有効範囲,局所変数, 大域変数 143
複合文/ブロックは、1つの文が書ける所であればどこにでも置くことが出来るので、ブ ロックの中により小さなブロックが入り、その内側のブロックの中にまた別のブロックが 入り、... という入れ子構造 も可能である。プログラムの中に出来るこの「ブロックの 入れ子構造」に基づいて、変数等に付けた名前の有効範囲が次の様に決まる。
(規則1) どの名前(の領域)も、それが宣言されたブロックの中だけでアクセスできる。
(規則2) 外側のブロックで宣言された名前を内側のブロックで再定義すると、外側の名
前の領域(i.e.その名前を持った外側の変数)は内側のブロックからはアクセスできな
くなる。 '
&
$
% (規則1)の理由:
ブロック内で宣言された変数や配列の領域は、ブロック内の宣言の場所に制御が 移ると自動的に確保され、ブロックの出口に制御が移ると解放される。
ブロックの中で宣言され局所的に使われるこれらの変数を自動変数という。
大域的な名前:
• 関数名はそのファイルのどの場所からでもアクセスできる。
• 関数の外で宣言された変数や配列はそのファイルのどの場所からでもアクセスでき
る。 (外部変数, 外部配列という。)
=⇒ ファイル全体をブロックの一種と見なすことも出来る。
'
&
$
% 注意:
外部変数を使い過ぎると、副作用のために関数同士の独立性が なくなり、分かりにくいプログラムになる恐れがあります。
次の例題は、C言語における名前の有効範囲の規則を例示するものである。
例題 10.8 (名前の有効範囲, 外部変数) 次のCプログラムを実行するとどういう出力 が得られるか? 下の の部分に予想される出力文字列を入れよ。但し、
ここでは空白は と明示せよ。
[motoki@x205a]$ nl scope-of-name.c Enter
1 /* 名前の有効範囲、外部変数の理解のためのプログラム例 */
2 #include <stdio.h>
3 void sub(void);
4 int a = 1; /* 外部変数 */
5 int main(void) 6 {
7 int a = 22; /* 自動変数 */
8 printf("(1) %d\n", a);
9 { /* ブロックの始まり */
10 int a = 333;
11 printf("(2) %d\n", a);
12 } /* ブロックの終わり */
13 printf("(3) %d\n", a);
14 sub();
15 return 0;
16 }
17 void sub(void) 18 {
19 int b = 4444;
20 printf("(4) %d\n", a);
21 printf("(5) %d\n", b);
22 }
[motoki@x205a]$ gcc scope-of-name.c Enter [motoki@x205a]$ ./a.out Enter
[motoki@x205a]$
(文法上の注意)
• プログラム3行目 の1つ目の void は関数sub() の戻り値がないことを明示し、2つ
目の voidは関数 sub() の引数がないことを明示している。
• プログラム4行目 は、int型外部変数a を確保しその初期値を1とすることを指示し ている。
(考え方) プログラム9〜12行目,および6〜16行目, 18〜22行目 がブロックとなってい るから、このプログラムの中に出来る「ブロックの入れ子構造」 を明示すると次の様に なる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/* 名前の有効範囲、外部変数の理解のためのプログラム例 */
#include <stdio.h>
void sub(void);
int a = 1; /* 外部変数 */
int main(void) {
int a = 22; /* 自動変数 */
printf("(1) %d\n", a);
{ /* ブロックの始まり */
int a = 333;
printf("(2) %d\n", a);
} /* ブロックの終わり */
printf("(3) %d\n", a);
sub();
return 0;
}
void sub(void) {
int b = 4444;
printf("(4) %d\n", a);
printf("(5) %d\n", b);
}
それゆえ、
10.2. 名前の有効範囲,局所変数, 大域変数 145
• プログラムの4行目 で宣言された外部変数a は、同じ名前の変数が宣言された内側 の6〜15行目のブロックの外側で有効である。
• プログラムの7行目 で宣言された自動変数a は6〜16行目のブロックの入口で宣言 されており、また同じ名前の変数が更に内側の9〜12行目のブロックでも宣言されて いる。従って、7行目のa は6〜8行目, 13〜16行目で有効となる。
• プログラムの10行目 で宣言された自動変数a は、9〜12行目のブロックの入口で宣 言されており、またこのブロックは別のブロックを含まない。従って、10行目の a は 9〜12行目のブロック内で有効となる。
• プログラムの19行目 で宣言された自動変数b は、18〜22行目のブロックの入口で宣 言されており、またこのブロックは別のブロックを含まない。従って、19行目の b は
18〜22行目のブロック内で有効となる。
(実行結果) 結局、プログラムの
8行目の a は 7行目で確保された a として、
11行目の a は 10行目で確保された a として、
13行目の a は 7行目で確保された a として、
20行目の a は 4行目で確保された a として、
21行目の b は 19行目で確保された b として 解釈されることになるから、実行結果は次の様になる。
[motoki@x205a]$ ./a.out Enter (1) 22
(2) 333 (3) 22 (4) 1 (5) 4444
[motoki@x205a]
□演習 10.9 (名前の有効範囲) 次のCプログラムを実行するとどういう出力が得られる
か? 下の の部分に予想される出力文字列を入れよ。但し、ここでは空白 は と明示せよ。
[motoki@x205a]$ nl scope-of-name-lab.c Enter 1 #include <stdio.h>
2 int a=-1;
3 int main(void) 4 {
5 int b=2;
6 printf("(1)a=%3d b=%3d\n", a, b);
7 {
8 int a=33;
9 float b=50;
10 printf("(2)a=%3d b=%3.0f\n", a, b);
11 {
12 int b=777;
13 printf("(3)a=%3d b=%3d\n", a, b);
14 }
15 printf("(4)a=%3d b=%3.0f\n", a, b);
16 {
17 int b=999;
18 printf("(5)a=%3d b=%3d\n", a, b);
19 }
20 printf("(6)a=%3d b=%3.0f\n", a, b);
21 }
22 printf("(7)a=%3d b=%3d\n", a, b);
23 return 0;
24 }
[motoki@x205a]$ gcc scope-of-name-lab.c Enter [motoki@x205a]$ ./a.out Enter
[motoki@x205a]$