Level 3:関数 3.1 局所変数の宣言 |
※資料は自著より引用
■3.1局所変数の宣言
まずは,C言語とC++の局所(ローカル)変数の宣言場所について説明しておく。
●局所変数の宣言の位置
実は,C言語では局所変数の宣言位置が「 { } で囲まれたブロック範囲の前半」に制限されていたのだが,
C++では,局所変数の宣言位置は「 { } で囲まれたブロック範囲のどこでも良い」 となっている(下図)。
C言語では, 実は「宣言(名前と型を関連付ける)」と「文(具体的な処理を行う)」は,区別され,
「宣言」は { } で囲まれたブロック範囲の前半,「文」は最後の宣言の後に書かなければならない,
と区別されていた(下図Fig. 3-1)。
しかし,C++の文法では「宣言」 は「文」の一種として扱われるようになったので,「宣言」も「文」
も,「 { } で囲まれたブロック範囲のどこでも良い」ということになった(下図Fig. 3-2)。
例えば,C++では,下の例のように6行目で文(文字列を出力する)の後の7行目で局所変数digitsの宣言を
行うことができる。
List 3-1 localv.cpp
今までも,C言語の学習で同じ様に「文」に後に「宣言」が書かれている例を見てきたかもしれない。
実は,ソースファイルの拡張子が「.cpp」となっていて,C++のプログラムとしてコンパイルされて
いたので,エラーにならなかったのである。
●ポインタ変数宣言と動的確保
変数の作成には,静的確保(変数宣言)と動的割り当てがあるわけだが,すでに紹介したオブジェクトの生成・初期化
についてまとまると下図Fig. 3-3 のようになる。
※もちろん,動的にオブジェクト生成するより先に,ポインタ変数だけ宣言する必要がある場合には
T* ポインタ変数名 = 0;
として空ポインタ値0で初期化しておくこと。
●for文専用の局所変数
for文では,よく繰返し回数を管理する「カウンタ変数」を利用する(List 3-2のi)。C言語では,List 3-2
のように,あらかじめfor文の前で「カウンタ変数」を宣言する必要があった。
List 3-2 for1.cpp
しかし,C++では,Javaと同じ様に,そのfor文専用の局所変数をfor文の頭部で宣言できるようになった(List 3-3)。
List 3-3 for2.cpp
C++でのfor文専用の局所変数の宣言方法を下図Fig. 3-4 に示す。このような書き方が可能になったのは,
C言語ではfor文頭部の丸カッコの最初のパートが「式;」だったのが,C++ではfor初期化文というものに
置き換えられたため(Fig. 3-5)。
●for文頭部で宣言した変数のスコープ
for文専用の局所変数の有効範囲は,そのfor文の中だけに限定される。確認用のプログラムを List 3-4
に示す。
List 3-4 for3.cpp
List 3-4 の実行結果
8行目で宣言されたfor文専用の局所変数iの有効範囲はそのfor文の中に限られる。12行目で
使われて
いる変数iは,for文の前(4行目)で宣言されたiの方である。
●宣言位置の流儀
局所変数の宣言場所については,以下の方針を目安にするといいだろう。
このようにある程度有効な
方針に従っているとプログラミングの際に混乱が少なくなる。
●大域識別子の参照
C言語では,大域変数と同じ名前の局所変数が有効な範囲の中では,大域変数を利用できなかった(同じ名前の
局所変数の方が優先されるため)。
変数だけでなく,大域領域(関数の外)で宣言・定義された名前(識別子)は,局所領域(関数の中)で宣言・定義さ
れた同じ名前に隠されてしまう。
C++では,すでに学習した::演算子を使って,
::大域識別子 // ::演算子を大域識別子の頭につける
と書けば,たとえ同名の局所識別子が有効な範囲からでも大域識別子を利用できるようになった。
むしろ,::演算子を使わずにC言語時代と同じ様に
大域識別子 // 素のまま大域識別子を使うのはC++では危険
と素のまま大域識別子を使ってしまうと,
・間違って同名の局所識別子の方を参照してしまう
・いずれ書き加えられた同名の局所識別子に隠され,同名の局所識別子の方を参照してしまう
という危険性があるので,
大域の名前を使うときは常に::演算子を付けて ::大域識別子 と書くべきである
ということになる。
使用例を List 3-5 に示す。4行目で宣言された大域変数gは,11行目で宣言されたmain関数の局所変数gによって
11〜26行目の範囲で隠されてしまう。また,19〜23行目では大域変数gと11行目で宣言されたgも,19行目で宣言
された「より内側」の局所変数gで隠されることになる。
大域変数gが局所変数gに隠されていても,::g として参照してい16行目と22行目では,大域変数利用することに
成功している。
List 3-5 scopeop.cpp
以下は,自著より該当箇所を引用。このように,以降のサンプルプログラムでは見やすさ優先で大域の名前に
::演算子をつけない場合もあるが,実際のプログラミングではつけるようにしましょう。