- ベストアンサー
fscanfについて
ファイルの中身が例えば 600 0.6 3.5 となっているとき, fscanfで読み込むと改行\nを読み込んでくれる場合と読み込まない場合がありませんか? また,これだったら,経験から fscanf(fp,"%d",&a); fscanf(fp,"%f",&b); fscanf(fp,"%c",&c); // \nの読み飛ばし fscanf(fp,"%f",&d); fscanf(fp,"%c",&e); // \nの読み飛ばし でやるとできそうですが,fscanf(fp,"%d",&a);のあとの\nの読み飛ばしがいらないのは何故ですか?
- みんなの回答 (8)
- 専門家の回答
質問者が選んだベストアンサー
#1です。 scanf()系は、 空白文字(スペース、改行、タブなど)の前まで読み込む ↓ 最後の改行文字はバッファの中に残っている ↓ 読み込む ↓ 空白文字はスペースとして扱われるため、 書式が"%c"以外なら読み込むが無視して次の行のものを読み込む。 書式が"%c"ならば、残っている改行文字を変数に入れてしまう ということです。 #3の補足のソースで言えば、 fscanf( fp, "%d", &a ); //1行目の600を変数aに格納 //→バッファに最後の改行が残る fscanf( fp, "%f", &b ); //書式が"%f"なので、バッファに残った改行を無視 //→2行目の0.6を変数bに格納 //→バッファに最後の改行が残る fscanf( fp, "%f", &c ); //書式が"%f"なので、バッファに残った改行を無視 //→3行目の3.5を変数cに格納 //→バッファに最後の改行が残る fscanf( fp, "%c", &d ); //書式が"%c"なので、バッファに残った改行を変数cに格納 fscanf( fp, "%c", &e ); //4行目の"XYZ"の"X"を変数eに格納 //→バッファに"YZ"と改行コードが残る fscanf( fp, "%c", &f ); //バッファに残っている"YZ"と改行コードから //最初の"Y"を変数fに格納 ということです。 http://www9.plala.or.jp/sgwr-t/c/sec05.html#s5-4 も参考にしてください。 > C++の入門書にコアダンプっていうことばがあったんですけどこれはどんな意味かご存知ですか? 下のURLが参考になるかと。 http://www.atmarkit.co.jp/icd/root/39/63458339.html http://e-words.jp/w/E382B3E382A2E38380E383B3E38397.html
その他の回答 (7)
- manayu
- ベストアンサー率53% (79/148)
#5です。 #5の補足のソースを拝見しました。 まず、最初に言っておきますが、Cでは、変数を宣言した時点では、 変数は初期化されておらず、ごみが入っています。 #5の補足のソースのfscanf()の4行目から説明しますと、 (3行目までは、#5と同じです) fscanf( fp, "%s", d );//書式が"%s"なので、バッファに残った改行を無視 //→ファイル4行目の"XYZ"を変数dに格納 //→バッファに最後の改行が残る fscanf( fp, "%s", e );//書式が"%s"なので、バッファに残った改行を無視 //→ファイルがEOF(ファイルの終わり) //まで達したので読み込まない //変数eには何も入らない(ごみが入ったまま) fscanf( fp, "%s", f );//ファイルがEOFまで達したので読み込まない //変数fには何も入らない(ごみが入ったまま) ですから、実行結果のeとfについては、たまたま変数に入っていたごみのデータ を表示していることになります。 このことは、変数を初期化するなり、 最初にprintf()で変数の中身を表示するなりで確認できるかと思います。 ちなみに、私の環境では実行結果がこうなりました。(コンパイラ bcc) a 600 b 0.600000 c 3.500000 d XYZ e 漾 f
お礼
%sも改行を無視してくれるんですね。 XYZを読み込んだあとEOFとなることを見落としていました。それでごみが残ったままになってしまっていたんですね。よく分かりました!! 長々と本当にありがとうございました。今まで抱いていた疑問が一気に解消できました!またC言語の事で分からない事があったらよろしくお願いします。
- tatsu99
- ベストアンサー率52% (391/751)
#3です。 >「fscanfで読み込むと改行\nを読み込んでくれる場合と読み込まない場合がありませんか?」 と最初の質問で言ったできごとをちゃんと起こす事ができました。 >補足回答よろしくお願いします。 うーむ。再現しましたね。私の環境でも再現しました。 >このようにどうやら%cで読み込む時になんか変なことが起こってしまうようなんです。 >何故なのでしょうか?? #3で「たぶん、正常なデータが入ってなかったのだと思います。」と回答しましたが、これは誤りでした。 #5の方が回答を書かれていますが、まさしくその通りです。お詫びして、訂正致します。
お礼
再現してくださってありがとうございました。真剣に答えて頂きとても嬉しく思います。
- manayu
- ベストアンサー率53% (79/148)
#1、5です。 #5で訂正があります。 #3の補足のソースのfscanf()の4行目は、 fscanf( fp, "%c", &d ); //書式が"%c"なので、バッファに残った改行を変数dに格納 です。 (変数cに格納 ではありません・・・)
お礼
迅速な訂正ありがとうございます。
- kmb01
- ベストアンサー率45% (63/138)
scanf系で%c以外の書式指定ではデータの前の空白文字(スペース、タブ、改行)を読み込むが無視するという処理をします。データの後の空白文字は読み込まず次のscanf実行に持ち越されます。 対して%c書式指定では空白文字であっても読み込みます。
お礼
回答ありがとうございました。なるほどこの問題は%cかそうでないかが決め手だったのですね。
- tatsu99
- ベストアンサー率52% (391/751)
>ダンプって何ですか? ファイルの内容を文字列ではなく、文字列のコードで出力することです。 たとえば、先頭の行は 600改行 ですので、文字列のコードを16進数で表示すると 3630300d0a と表示されるはずです。 このことにより、格納されている文字がなんなのかを正確に判断することができます。 空白の文字は見た目では半角のスペースか全角のスペースかタブなのか改行なのかが判りません、このような時に16進数で文字列のコード表示すると違いがはっきりと判ります。 このような表示が出来るエディタを「バイナリエディタ」と読んでいますので、そのエディタを使用して見てください。(無償でダウンロード可能なものが、たくさんあります) >でも他のプログラムではそうならないときがあったんだけ>どなぁ? >どうしてでしょうか? たぶん、正常なデータが入ってなかったのだと思います。(例えばデータの後に全角のスペースがあると正しく動作しません) そのファイルが、まだあれば、バイナリエディタで内容を参照してみてください。
お礼
補足回答ありがとうございました。 なんかC++の入門書にコアダンプっていうことばがあったんですけどこれはどんな意味かご存知ですか? 正常なデータが入っているにもかかわらず, 問題を発生させることに成功しました! 補足回答のプログラムをご覧下さい!!
補足
このようにどうやら%cで読み込む時になんか変なことが起こってしまうようなんです。 何故なのでしょうか?? 「fscanfで読み込むと改行\nを読み込んでくれる場合と読み込まない場合がありませんか?」 と最初の質問で言ったできごとをちゃんと起こす事ができました。 補足回答よろしくお願いします。 ○問題発生のテストプログラム #include<stdio.h> #include<stdlib.h> int main() { int a; float b, c; char d, e, f; FILE* fp; fp = fopen( "datafile.txt", "r" ); fscanf( fp, "%d", &a ); fscanf( fp, "%f", &b ); fscanf( fp, "%f", &c ); fscanf( fp, "%c", &d ); fscanf( fp, "%c", &e ); fscanf( fp, "%c", &f ); printf( "a %d\n", a ); printf( "b %f\n", b ); printf( "c %f\n", c ); printf( "d %c\n", d ); printf( "e %c\n", e ); printf( "f %c\n", f ); fclose(fp); return 0; } ●注;datafile.txtの中身 600 0.6 3.5 XYZ ○実行結果 a 600 b 0.600000 c 3.500000 d e X f Y
- tatsu99
- ベストアンサー率52% (391/751)
通常は、全て正常データであれば、 fscanf(fp,"%d",&a); fscanf(fp,"%f",&b); のあと fscanf(fp,"%c",&c); // \nの読み飛ばし を行う必要はありません。 但し、 600のデータが 600Xとか600の後に全角スペース とかになっていると、次のデータを正しく読み込めません。 1.各データは全て正常なデータであること。 2.各データの後は改行だけであること。 上記の2条件が必ず成立するデータでも、\nの読み飛ばしが必要でしょうか。 また、このテスト環境は、windowsでしょうかunixでしょうか。windowsの場合、正しい改行になってますか。(16進ダンプで0x0d0aが表示されますか) 上記の点をチェックしてみて下さい。
お礼
回答ありがとうございました。 >また、このテスト環境は、windowsでしょうかunixでし>ょうか。windowsの場合、正しい改行になってますか。>(16進ダンプで0x0d0aが表示されますか) Windowsです。 ダンプって何ですか?
補足
○#1から\n読み飛ばしをなくしたテストプログラム #include<stdio.h> #include<stdlib.h> int main() { int a; float b, d; FILE* fp; fp = fopen( "datafile.txt", "r" ); fscanf( fp, "%d", &a ); fscanf( fp, "%f", &b ); fscanf( fp, "%f", &d ); printf( "a %d\n", a ); printf( "b %f\n", b ); printf( "d %f\n", d ); fclose(fp); return 0; } ●注;datafile.txtの中身 600 0.6 3.5 ○実行結果 a 600 b 0.600000 d 3.500000 あらら?? ちゃんと綺麗になっています。読み飛ばしがいらない!?ということを意味している!? ?????? でも他のプログラムではそうならないときがあったんだけどなぁ? どうしてでしょうか?
- manayu
- ベストアンサー率53% (79/148)
参考になりそうなURL。 http://www.bohyoh.com/CandCPP/C/Library/fscanf.html http://homepage2.nifty.com/tenk/cgokai/scanf.htm ※scanfとfscanfは標準入力かファイル入力かが違うだけで、2つは等価です。 http://www9.plala.or.jp/sgwr-t/c/sec05.html#s5-4 http://www.catnet.ne.jp/kouno/c_faq/c12.html#20 基本的には、fscanf()ではなく、fgets()を使った方がいいです。
お礼
回答ありがとうございました。 簡単なテストプログラムを作成しました。 補足にそのプログラムと結果を示しました。
補足
○作成したテストプログラム #include<stdio.h> #include<stdlib.h> int main() { int a; float b, d; char c, e; FILE* fp; fp = fopen( "datafile.txt", "r" ); fscanf( fp, "%d", &a ); fscanf( fp, "%f", &b ); fscanf( fp, "%c", &c ); // \n fscanf( fp, "%f", &d ); fscanf( fp, "%c", &e ); // \n printf( "a %d\n", a ); printf( "b %f\n", b ); printf( "c %c\n", c ); printf( "d %f\n", d ); printf( "e %c\n", e ); fclose(fp); return 0; } ●注;datafile.txtの中身 600 0.6 3.5 ○実行結果 a 600 b 0.600000 c d 3.500000 e フ
お礼
丁寧な回答ありがとうございました。とても分かりやすく理解できました!!原因がすっきりしました。 コアダンプについてもURLを載せて頂きありがとうございました。
補足
%c以外で%sのときはどうなるのかと思い、下のテストプログラムを試しました。変な結果になっています。これはどのように説明がつくのでしょうか? ○テストプログラム #include<stdio.h> #include<stdlib.h> int main() { int a; float b, c; char d[10], e[10], f[10]; FILE* fp; fp = fopen( "datafile.txt", "r" ); fscanf( fp, "%d", &a ); fscanf( fp, "%f", &b ); fscanf( fp, "%f", &c ); fscanf( fp, "%s", d ); fscanf( fp, "%s", e ); fscanf( fp, "%s", f ); printf( "a %d\n", a ); printf( "b %f\n", b ); printf( "c %f\n", c ); printf( "d %s\n", d ); printf( "e %s\n", e ); printf( "f %s\n", f ); fclose(fp); return 0; } ●注;datafile.txtの中身 600 0.6 3.5 XYZ ○実行結果 a 600 b 0.600000 c 3.500000 d XYZ e フフフフフフフフフフフフXYZ f フフフフフフフフフフフフフフフフフフフフフフフフXYZ