わさっきhb

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

戻り値に配慮すべき関数

ライブラリ関数の中で,期待する処理ができなかったとき,そのことが戻り値に含まれている,というものがあります.
例えばfopenはファイルを開いてファイルポインタを返すのですが,ファイルを開くのに失敗したら,NULLを返します*1
なので,fopenを呼び出す側では,「ファイルを開いた,では使おう」ではなく,「ファイルを開いた,うまく開けた(NULLではない)ね,では使おう」という処理をします.
典型的には

FILE *fp;
if ((fp = fopen(filename, "r")) == NULL) {
  エラー処理
}
fpを用いてファイルアクセス…

と書きます.ifの条件判定に,代入と比較の両方を書くのはイディオムで,その事情については,Cプログラミングの秘訣のPart2が参考になります.
同様に,戻り値をifやwhileの中でチェックすべきライブラリ関数(かつ授業で取り上げたもの)として,malloc, fgets, getchar, scanfが挙げられます.
mallocもfgetsも,失敗したらNULLが得られます.
getcharやfgetcなど,1文字読み出すライブラリ関数では,読み出せなくなったらEOFが返りますので,逆に言うと,EOFと比較すれば,読み出せたか否かが分かります.
scanf系のライブラリ関数では,失敗したらEOFを返すという仕様になっていますが,これを使うのは安全でないと考えます.むしろ,読み出せた個数を返すことに着目して,scanfの呼び出しに関する戻り値と,「何個の変数に値を格納してほしいか」の値とを比較すればいいのです.こうすれば,入力の終わりである場合でも,入力はあったが値と変数の型が合わないため格納できなかった場合でも,情報の獲得に失敗したことが分かります.
「何個の変数に値を格納してほしいか」は,scanfの呼び出しの引数を見れば分かります.美しくないですが,その個数は,ソースコードに手作業で書いておきましょう.

*1:本日のエントリは,主語が「ライブラリ関数」だったり,「ライブラリ関数を呼び出すところ」だったりするので,注意してください.