わさっきhb

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

fopenの引数はいずれも文字列

今週から授業再開.私の授業も明後日です.そのときレポートを受け取って,週末には,その採点が待っています.
授業ですが,年明け最初は例年「前処理指令preprocessing directive」をテーマとして,#define,#include,#ifなどを説明していました.ですが今年は,ライブラリ関数の関連して#includeをすでにやってしまったので,前処理指令の説明を減らす分,ファイル入出力を少し入れることにしました.
これまた昨年度までの反省なのですが,ファイルを「読む」プログラムしか作っていなかったのはバランスを欠くなあ,と感じていました*1
今回,またプログラムを創りました.あらかじめ指定されたファイルを読み込んで,数値を獲得して出力.そして数値を1増やして,ファイルの中身を書き換えます.なのですがこのプログラムで,「そのプログラムを何回実行したか」がファイルに保存されることになります.
やっとタイトルのことですが,ファイル入出力のプログラミングに慣れていない人は,こんな間違いをすることがあります.

FILE *f;
f = fopen("count.txt", 'r');

正しくは

FILE *f;
f = fopen("count.txt", "r");

です*2
fopenの第1引数は,ファイル名です.上の書き方だと,実行するカレントディレクト*3の「count.txt」を開こうとします.
第2引数は,どのような形態でファイルを開くかを示します.「ファイルモード」と呼ばれます."r"なら読み出し専用で開きます."w"なら書き出し専用で開きます.他にも,"a","r+","w+" などが指定可能です.このように,ファイルモードは2文字から構成されることがあり得るので,文字列となります.
ライブラリ関数のfopenで引数を受け取る際には,どちらの引数も,文字列の先頭アドレスをポインタで取得します.呼び出す側も,文字列を指し示すポインタであればよく,文字列リテラルで書く必要はありません.すなわち,

char filename[32];
char *filemode = "r";
FILE *f;

strcpy(filename, "count.txt");
f = fopen(filename, filemode);

と書いても,問題なく動作します.

*1:実用的には,演習課題では「読む」プログラムを書くほうが多いですし,授業を離れても,読むほうは何らかのファイル処理関数が必要ですが,書くほうはprintfとリダイレクションを組み合わせてもファイルに書くことができるので,そういう点で,「書く」ファイル処理関数の重要性は下がることになります.

*2:さらに実用性を追求すると,ファイルを開けなかったとき,fにはNULLが代入されるので,if文で検出して別途処理する必要もあるでしょう.

*3:実行ファイルがあるディレクトリでもホームディレクトリでもありません…それらと一致することはあるかもしれませんが.