最初に、先週の未消化分ということで、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 定数は名前をすべて大文字とするといったような、 誤解されないテクニックも紹介する。