- ベストアンサー
配列の読み込み
タブ又はカンマ、又はスペースで区切られた配列が書かれたテキストを、配列として読み込みたいのですが、どのようプログラムしたらいいのでしょうか。 つまりは、下の例みたいに書かれたテキストを、そのまま3行4列の配列として読み込みたいのです。 例) 1222,2337,593,3488 2338,384,34,2229 534,23333,234,444 ちなみに、私は下のような1列で書かれたものなら読み込めます。 例) 123 343 23 253
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
こんにちは。 ご自身の勉強のために、あえてヒントだけを書きますと、 for fgets strtok を使用すればできます。ヘルプを見て下さい。 strtokの使い方がポイントです。 これで分からなければ、再度投稿します。
その他の回答 (5)
- hero1000
- ベストアンサー率29% (114/390)
既に解決なさってるようですが一応・・・ No.2の補足に対する回答です。 >こんなかんじでいいでしょうか? いいと思いますよ。 >列が非常に長いときは、strtokを使うしかないのでしょうか? あまり長いと、sscanfで指定するフォーマットが長くなってしまうので、 よくないですね。("%d,%d,%d,%d,・・・"という感じになってしまうので) strtokの方がスマートに書けると思います。 (No.3の補足に書いてあるとおりです)
- L_E_D
- ベストアンサー率48% (36/74)
方法としては、No.4の回答でほとんど問題はないと思います。 実際にコードを書く場合には、ループの回数=配列の大きさを #define で定義して 使用すると、間違いが少なくなるでしょう。 また、fscanfではなく、fgetsとstrtokの組合せを勧めたのもミスを防ぎ、配列の 大きさに柔軟に対応させるためです。 たとえば、読み込むファイルをExcelで作成し、CSV形式で保存すれば、上の例に あるファイルを作成できますが、行末にもカンマが付くことがあります。 例) 1222,2337,593,3488, fscanfを使用すると、書き方によっては最後のカンマのために、2行目以降の データが全てずれる可能性がありますが、No4の回答の例では、カンマがあっても 無くても正確に読み込めます。 どのようなフォーマットにしろ、テキスト(ascii)形式のファイルは、1行ずつ fgetsで読み込んでから処理する事をお勧めします。
- leaz024
- ベストアンサー率75% (398/526)
# No.3お礼より こんな感じでどうでしょうか? for (i = 0; i < 3; i++) { a[i][0] = atoi( strtok( fgets(str,50,fp),"," ) ); for (j = 1; j < 4; j++) a[i][j] = atoi( strtok( NULL,"," ) ); } # 括弧の対応に要注意! # データを間違えて読むことより、不正な配列アクセスをする方が危険なので、確実に3行4列を超えないようにループを組む必要があります。 ↑非常に大事! またfscanfループの1つの解として、こんなのもあります。が、、、 for (i = 0; i < 3*4; i++) fscanf(fp, "%d,", *a + i); これは必ずしも「よいプログラム」ではありません。 なぜなら「理解しにくい」からです(笑) # 理解しやすいコーディングというのはとても大切なことなのですが、プロでもできてない人が大勢いるんです。 # こういうことをやる人に限って、自分のコードは素晴らしいと思ってる人が多くって・・・ # 素直なプログラムを書けるように頑張りましょう。 leaz愚痴モードでした。
- leaz024
- ベストアンサー率75% (398/526)
# No.1の補足に対して strtokは癖の強い関数なので、最初は悩みますよね。 この関数は内部に参照ポインタを持っていて、前回どこまで調べたかを覚えていてくれるのです。 2回目以降調べる場合は、第1引数にNULLを指定します。 最後まで調べ尽くすとNULLを返します。まぁ今回は数が分かっているので使いませんが。 以上を参考に改良をしてみてください。 # ただ、このような単純なフォーマットのテキストファイルならば、普通はfscanfのループで十分だと思いますが。
お礼
ありがとうございます。 なるほど、下のように書けばうまくいきました。 for(i=0;i<3;i++) { fgets(str,50,fp); j=0; a[i][j]=atoi(strtok(str,",")); while(1) { j++; if((a[i][j]=atoi(strtok(NULL,",")))==NULL)break; } } この書き方でうまくいきますが、もっと効率のいい書き方ないでしょうか。 また、fscanfのループでうまくいくってのが分かりません。毎回先頭の数字を読み込みそうな気がしますが。
補足
fscanfの方法も分かりました。どうもありがとうございます。 単純なフォーマットならfscanfかsscanfが便利で、複雑なフォーマットや列が長い場合は、strtokを使えばいいことが分かりました。
- hero1000
- ベストアンサー率29% (114/390)
1列のデータは4つの数字がカンマで区切られたものですので、 sscanf を用いればできると思います。 1列のデータを読み込んで、sscanfで数字を取り出して・・・。 と、ここまでにしておきます。 頑張って下さいね。
お礼
ありがとうございます。下のように書いたところ、うまくいきました。 こんなかんじでいいでしょうか。 列が非常に長いときは、strtokを使うしかないのでしょうか? for(i=0;i<3;i++) { fgets(str,50,fp); sscanf(str,"%d,%d,%d,%d",&a[i][0],&a[i][1],&a[i][2],&a[i][3]); }
補足
ありがとうございました。とりあえず、こうやってみました。でも無理でした。 int a[3][4]; char str[50]; FILE *fp; if((fp=fopen("test","r"))==NULL)exit(0); for(i=0;i<3;i++) { fgets(str,50,fp); for (j=0;j<4;j++) { a[i][j]=atoi(strtok(str,",")); } } 上の例で試したところ、配列aは以下のようになってしまいました。 1222,1222,1222,1222 2338,2338,2338,2338 534,534,534,534 strtokが、forループの中で毎回初めの数字を読み込んでいます。