• ベストアンサー

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の読み飛ばしがいらないのは何故ですか?

質問者が選んだベストアンサー

  • ベストアンサー
  • manayu
  • ベストアンサー率53% (79/148)
回答No.5

#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

参考URL:
http://www9.plala.or.jp/sgwr-t/c/sec05.html#s5-4,http://www.atmarkit.co.jp/icd/root/39/63458339.html
Rossana
質問者

お礼

丁寧な回答ありがとうございました。とても分かりやすく理解できました!!原因がすっきりしました。 コアダンプについてもURLを載せて頂きありがとうございました。

Rossana
質問者

補足

%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

その他の回答 (7)

  • manayu
  • ベストアンサー率53% (79/148)
回答No.8

#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

Rossana
質問者

お礼

%sも改行を無視してくれるんですね。 XYZを読み込んだあとEOFとなることを見落としていました。それでごみが残ったままになってしまっていたんですね。よく分かりました!! 長々と本当にありがとうございました。今まで抱いていた疑問が一気に解消できました!またC言語の事で分からない事があったらよろしくお願いします。

  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.7

#3です。 >「fscanfで読み込むと改行\nを読み込んでくれる場合と読み込まない場合がありませんか?」 と最初の質問で言ったできごとをちゃんと起こす事ができました。 >補足回答よろしくお願いします。 うーむ。再現しましたね。私の環境でも再現しました。 >このようにどうやら%cで読み込む時になんか変なことが起こってしまうようなんです。 >何故なのでしょうか?? #3で「たぶん、正常なデータが入ってなかったのだと思います。」と回答しましたが、これは誤りでした。 #5の方が回答を書かれていますが、まさしくその通りです。お詫びして、訂正致します。

Rossana
質問者

お礼

再現してくださってありがとうございました。真剣に答えて頂きとても嬉しく思います。

  • manayu
  • ベストアンサー率53% (79/148)
回答No.6

#1、5です。 #5で訂正があります。 #3の補足のソースのfscanf()の4行目は、 fscanf( fp, "%c", &d ); //書式が"%c"なので、バッファに残った改行を変数dに格納 です。 (変数cに格納 ではありません・・・)

Rossana
質問者

お礼

迅速な訂正ありがとうございます。

  • kmb01
  • ベストアンサー率45% (63/138)
回答No.4

scanf系で%c以外の書式指定ではデータの前の空白文字(スペース、タブ、改行)を読み込むが無視するという処理をします。データの後の空白文字は読み込まず次のscanf実行に持ち越されます。 対して%c書式指定では空白文字であっても読み込みます。

Rossana
質問者

お礼

回答ありがとうございました。なるほどこの問題は%cかそうでないかが決め手だったのですね。

  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.3

>ダンプって何ですか? ファイルの内容を文字列ではなく、文字列のコードで出力することです。 たとえば、先頭の行は 600改行 ですので、文字列のコードを16進数で表示すると 3630300d0a と表示されるはずです。 このことにより、格納されている文字がなんなのかを正確に判断することができます。 空白の文字は見た目では半角のスペースか全角のスペースかタブなのか改行なのかが判りません、このような時に16進数で文字列のコード表示すると違いがはっきりと判ります。 このような表示が出来るエディタを「バイナリエディタ」と読んでいますので、そのエディタを使用して見てください。(無償でダウンロード可能なものが、たくさんあります) >でも他のプログラムではそうならないときがあったんだけ>どなぁ? >どうしてでしょうか? たぶん、正常なデータが入ってなかったのだと思います。(例えばデータの後に全角のスペースがあると正しく動作しません) そのファイルが、まだあれば、バイナリエディタで内容を参照してみてください。

Rossana
質問者

お礼

補足回答ありがとうございました。 なんかC++の入門書にコアダンプっていうことばがあったんですけどこれはどんな意味かご存知ですか? 正常なデータが入っているにもかかわらず, 問題を発生させることに成功しました! 補足回答のプログラムをご覧下さい!!

Rossana
質問者

補足

このようにどうやら%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)
回答No.2

通常は、全て正常データであれば、 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が表示されますか) 上記の点をチェックしてみて下さい。

Rossana
質問者

お礼

回答ありがとうございました。 >また、このテスト環境は、windowsでしょうかunixでし>ょうか。windowsの場合、正しい改行になってますか。>(16進ダンプで0x0d0aが表示されますか) Windowsです。 ダンプって何ですか?

Rossana
質問者

補足

○#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)
回答No.1

参考になりそうな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()を使った方がいいです。

Rossana
質問者

お礼

回答ありがとうございました。 簡単なテストプログラムを作成しました。 補足にそのプログラムと結果を示しました。

Rossana
質問者

補足

○作成したテストプログラム #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 フ