わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

初心者がポインタの使用にあたり最も注意すべきことがSoftware Designの特集記事に書かれていなかった

演習そして講義で,Cのプログラム例を学生に紹介したり,学生の書いたコード(しばしば「うまく動きません」の相談とともに)を見て指導したりしてきた者として,第1特集の第1部「C言語ポインタの克服編」の内容をひととおり読み,ある一つの情報が書かれていないことを,残念に感じました.
それは,「ポインタの初期化をしていない状態で,参照先の値へ参照や代入をしてはいけない」です.例を挙げると,

  int *p;

と宣言し,pへの代入をすることなく

  *p = 1;

などと書くのはいけません.実行時エラーとなるのが容易に想像できます.
実行時エラーとならずに,おかしな挙動をする可能性や,エラーも何も起こらず,期待どおりに動作する可能性も,あります.ですが答案として提出する前に,インデントや空白・空行の見直しと合わせて,このようなポインタの使い方をしていないか,チェックする習慣をつけることを,この記事を読んでくれた,Cのプログラミングをこれからしていく学生には,持ってもらいたいものです.
初期化なしの参照・代入をしないための,王道と言うべき心がけは,「メモリ状態を常に意識する」ですが,授業を通じた経験により,また別のアドバイスをすることができます.思わぬ動作をし,その原因がどうやらポインタを使った処理であるというときには,その変数名(pとします)に着目し,*pを含む参照や代入の式を指差して,まず「pの値は?」,次に「*pの値は?」と自問してみてください.
上の「*p = 1;」だと,「pの値は?」の答えは「どこか分からないアドレス」,「*pの値は?」の答えは「その,どこか分からないアドレスを先頭に,intの領域として,そこに1を代入しようとしている*1」と言うことができます.


余談ですが,初期化なしの参照・代入は,GCCであれば-Wallオプションをつけてコンパイルすることでも,検出してくれます.手元で適当にコードを書き,コンパイルしたところ,"warning: 'p' is used uninitialized in this function [-Wuninitialized]",「警告: ‘p’ はこの関数内で初期化されずに使用されています [-Wuninitialized]」と出てきました.なのですが,そのポインタ変数を関数の外に出してみる(グローバル変数にする)と,コンパイル時の警告がなくなりました.内外いずれであれ,初期化なしの代入をしたコードを含む実行ファイルを走らせると,"segmentation fault (core dumped)"が表示されました.

*1:代入すなわちメモリ上のそのアドレスへの書き込みを,OSが認めないとなれば,実行時エラーとなるわけです.