• ベストアンサー

csvファイルをfscanfで読み込むと変な文字が出てきます

csvファイルをfscanfで読み込もうとしているのですが どうしてもおかしな文字が混じってしまいます 例えばcsvファイルのデータが abc,efg となっているとします これを読み込みprintfで表示すると abc"" efg"" というように表示されてしまいます csvファイルを普通に開いてもこのような文字はありません 一体どこから沸いて出てくるのでしょうか? %[^]を使って不要な文字を読み込まないように %[^"]と記述しましたが エラー番号c2143とc2059が出てしまいます 何か解決方法はございませんでしょうか? よろしくお願いします。

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

  • ベストアンサー
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.4

まずは、scanfの仕様をマニュアルなどでよく確認しましょう。 > while( ( ret = fscanf( fp, "%[^,],%[^,],%[^,],%[^,],%s", s, &n1, &n2, &f1, &f2 ) ) != EOF ){ 最初の%[^,]に対して 「char型の配列」s で受けている(正解)のに、2番目以降が 「char型の配列へのポインタ」&n1, &n2 ...で受けています。これらに&は必要ありません。 手元のgccの実装では、配列のアドレスと、その配列へのポインタのアドレスがたまたま同じだったため、「正常」に動作しました。しかし、これがmalloc等で確保した領域への「char型へのポインタ」と、「『char型のポインタ』へのポインタ」だった場合は違うアドレスになり、正常に動作しません。 次にfscanfの取り込み方に関してです。 [^,]とした場合、**改行文字も取り込みの対象になります**。なので、2行目以降のsには、前入力行で取り込まれなかった改行文字が先頭に付くことになります。 また、1行にカンマが4つ無かった場合は、n1,n2,f1で「その行の改行文字まで+次の行の最初のカンマまで」を取り込みます。 sに改行コードを入れないために「fscanf( fp, " %[^\n,]....」と%の前にスペースを置いて、0個以上の空白文字(改行文字も含む)を読み飛ばします。カンマが足りないときのn1,n2,f1の方は[^\n,]として改行も含まない文字に追加します。 最後に、fscanfの戻り値です。 scanf系では、最終的に取り込んだ値の数を返します。 今回の場合、最後の行のあとに、残った改行がsに入るので、ret=1になります。EOFになるのは、その次のループになります。 一応、上の書式変更で「最後の行の後の改行文字をsに取り込む」ということはなくなりますが、ret==5でない時は正常な取り込みではないので、なんらかのエラー処理が必要でしょう。 fscanfは結構やっかいです。 上の改行もそうです。 取り込みエラーでもファイルの読み込み位置が変わらないので、次のループでまたエラーになる、といったこともあります。 1行単位で処理したい場合は、fgetsで1行読み込み→sscanfで処理 というのが常套手段です。 確認に使ったファイルを貼り付けておきましたので、修正前と修正後でどんな風に動いているか、ご自身で確認してみてください 入力:abc.csv ab1,ef2,ab3,af4,ab5 bb1,bf2,bb3,bf4 cb1,cf2,cb3,cf4,cb5 zb1,zf2,zb3,zf4,zb5 #include <stdio.h> #include <stdlib.h> int main(void) { FILE *fp; char *fname = "abc.csv"; /*char s[100];*/ char *s = (char*)malloc(100); /* 比較のため、mallocでの領域確保 */ char n1[100]; char n2[100]; char f1[100]; char f2[100]; char buf[600]; /* fgets用 */ int ret; int i=0; fp = fopen( fname, "r" ); if( fp == NULL ){ printf( "%sファイルが開けません\n", fname ); return -1; } printf( "s=%p:&s=%p\nn1=%p:&n1=%p\nn2=%p:&n2=%p\nf1=%p:&f1=%p\nf2~%p:&f1=%p\n", s, &s, n1, &n1, n2, &n2, f1, &f1, f2, &f2 ); /*↓ 1: 修正前, 0:修正後 */ #if 0 while( ( ret = fscanf( fp, "%[^,],%[^,],%[^,],%[^,],%s", s, n1,n2,f1,f2 ) ) != EOF ){ #else while( fgets( buf,600, fp ) != NULL ) { ret = sscanf( buf, " %[^,],%[^\n,],%[^\n,],%[^\n,],%s", s, n1,n2,f1,f2 ) ; #endif if ( ret != 5) {/* エラー処理 */ } i ++ ; printf( "No.%d::\nret=%d\n", i,ret ); printf( "s =%s\nn1=%s\nn2=%s\nf1=%s\nf2=%s\n", s, n1, n2, f1, f2 ); } fclose( fp ); free(s); return 0; }

master817199
質問者

お礼

長文に渡る丁寧なご回答に感謝します 早速実行して自分好みに色々手を加え、結果に大満足です 本当にありがとうございました。

その他の回答 (3)

回答No.3

問題解決に直接結びつくか否かはわかりませんが、 fscanf( fp, "%[^,],%[^,],%[^,],%[^,],%s", s, &n1, &n2, &f1, &f2 ) で、n1,n2,f1,f2には&をつける必要はないのでは(sに&をつけないのと同じ理由で)

master817199
質問者

お礼

全くその通りですね! 貴重なご指摘に感謝します!

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.2

その現象を起こしているソースコードを貼り付けることが、 解決への第一歩です。

master817199
質問者

補足

大変失礼致しました まだ初心者ですのでコードは見よう見まねで打ちました、 初歩的な間違いが多いでしょうがよろしくお願いします。 #include <stdio.h> int main(void) { FILE *fp; char *fname = "abc.csv"; char s[100]; char n1[100]; char n2[100]; char f1[100]; char f2[100]; int ret; fp = fopen( fname, "r" ); if( fp == NULL ){ printf( "%sファイルが開けません\n", fname ); return -1; } while( ( ret = fscanf( fp, "%[^,],%[^,],%[^,],%[^,],%s", s, &n1, &n2, &f1, &f2 ) ) != EOF ){ printf( "%s %s %s %s %s", s, n1, n2, f1, f2 ); } fclose( fp ); return 0; }

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

あなたがどのようなプログラムについて話をしているのか分からないので, 「一体どこから沸いて出てくるのでしょうか」と聞かれても「きっとあなたのプログラムから沸いて出てくる」としか言いようがない. もちろんプログラムが分かればそれに応じてより詳しく答えることができるかもしれない.

関連するQ&A