変数の寿命と有効範囲、関数と引数
最初に、先週の未消化分ということで、switch – case 文を説明。 caseラベルにジャンプする概念と、break 文の必要性を解説。
大域変数・動的局所変数・静的局所変数
変数には、寿命と有効範囲という概念が重要であり、 局所変数であれば、宣言されたブロックの中でのみ有効。 大域変数は、どこからでも使える変数で便利だけど、危険な使い方。 局所変数は、一般的に動的変数であり、ブロックに入った時に作られ、 ブロックを抜けると消滅する。 しかし、static キーワードを付けた局所変数は、静的変数となり、 プログラム起動時に作られ、プログラム終了まで生き残る。
int x = 123 ; // 静的大域変数 void foo() { int x = 234 ; // 動的局所変数 x++ ; printf( "%d" , x ) ; } void bar() { static int x = 345 ; // 静的局所変数 x++ ; printf( "%d" , x ) ; } void baz() { x++ ; printf( "%d" , x ) ; } void main() { foo() ; // 235 bar() ; // 346 baz() ; // 124 foo() ; // 235 bar() ; // 347 baz() ; // 125 }
関数と引数
関数と引数の説明として、実引数のコピーが仮引数に渡されて、局所変数の仮引数は 関数処理と同時に消滅するという解説を行う。 これにより、関数での副作用が呼び出し側に伝わらないようにすることを説明。 一方で、関数の副作用を伝えたい場合は、値渡しではなく、ポインタ渡しをすることを説明。
// 値渡し(副作用が無い) void foo( int x ) { x++ ; printf( "%d" , x ) ; } void main() { int x = 123 ; foo( x ) ; // main::x とfoo::xは別の入れ物 foo( x ) ; } // ポインタ渡し(ポインタ経由で副作用) void foo( int* p ) { (*p)++ ; printf( "%d" , *p ) ; } void main() { int x = 123 ; foo( &x ) ; foo( &x ) ; }
説明において、間違い・勘違いを防ぐためのテクニックとして、 switch-caseでは、最後の行にも breakを書くとか、次のcaseになだれ込みでも、/*no break*/ コメントを入れるとかのテクニックを紹介。 大域変数では、一時的な変数と間違われないように、使用目的が分かるような長い名前をつけるとか、大域変数は単語先頭を大文字、#define 定数は名前をすべて大文字とするといったような、 誤解されないテクニックも紹介する。