• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:fscanfの書式について)

C言語でのファイル読み込み方法についての質問

このQ&Aのポイント
  • C言語で特定の形式のファイルを読み込む方法について質問です。具体的には、a[n][n]という形式で並んでいるファイルをどのように読み込むかが知りたいです。
  • Fortranには、DOループを使って特定の形式のファイルを読み込む方法がありますが、C言語ではどのように書けばいいのか分からないです。
  • 現在、C言語を初めて学んでおり、Fortranの経験がありますが、C言語のファイル読み込み方法が分からないです。改行の問題もあります。

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

  • ベストアンサー
回答No.1

取得するデータの数が不定だったり、多過ぎる場合はfscanfを用いるのは妥当ではありません。 fgets等で1行全体を読み込んだ上で、個々のデータを区切って取得していくのが妥当でしょう。 データが「,」区切りなら「,」をセパレータとしてstrtokなどを用いて個々のデータを取り出して行きます。 double a[n][n]; char buf[1024]; int i, j; char *datp; i = 0; while (fgets(buf, 1024, fp) != NULL) { j = 0; while(1) { if (j == 0) { datp = strtok(buf, ","); } else { datp = strtok(NULL, ","); } if (datp == NULL) { break; } a[i][j] = atof(datp); j++; } i++; }

knock123
質問者

お礼

出来ました!! フォートランに比べて長いのが難点ですが。 ちなみに、私がもっているC言語の解説本、柴田著の明解C言語入門編と中級編にはなんとstrtokが載っていませんでした…。もっとちゃんとした本を買わないといけないですね。

その他の回答 (4)

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

test.txt----- 1,2,3, 11,12,13, 21,22,23, ------------- test.c------- #include <stdio.h> #define n 1 int main(){ float a[n+2][n+2] ; int i,j ; FILE* fp ; fp = fopen("test.txt","r"); if ( fp == NULL ) { fprintf( stderr, "File Open Error\n" ); return 1 ; } for(i=0;i<=n+1;i++){ for(j=0;j<=n+1;j++){ if ( 1 != fscanf(fp,"%f %*[,] ",&a[i][j]) ) { fprintf( stderr, "Error\n" ); return 1; } } } fclose(fp) ; for(i=0;i<=n+1;i++){ for(j=0;j<=n+1;j++){ printf( "%7.2f,", a[i][j] ); } printf( "\n"); } return 0; } ------------- 実行結果:スペースを_に置き換えてあります ___1.00,___2.00,___3.00, __11.00,__12.00,__13.00, __21.00,__22.00,__23.00, ------------- と、こちらではまったく問題ありませんが。 やりそうな間違いとしては、aをdouble型の配列で宣言している、というのがあります。 補足等もaの大きさは書いてあるのですが、型が書いてないのが気になります。 scanfの変換指定子と変数の型は一致している必要があります。 %fはfloatへのポインタを要求します。他のポインタを入れてもfloatへのポインタだと勝手に解釈します。 doubleとfloatでは内部表現が違うので、doubleの領域にfloatの内部表現が書き込まれても、数値としてはまったく別のものになります。 aの型をfloatにするか、fscanf(fp,"%lf %*[,] ",&a[i][j]) とdouble型を要求する lfを使用するかです。 floatを使う積極的な理由がなければ、後者をお勧めします。

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

「だめ」というときには, 「どう」ダメなのかをちゃんと書いてほしい. あと, fgets や strtok にもそれなりに「くせ」があるので, きわどい状況だといろいろ困難があったりします.

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

まずは、マニュアルをよく読むことです。 fscanfのマニュアルには、フォーマット文字列の書式について詳しくかかれています。 その前に > a[n][n]が、 > a11,a12,a13---a1n, とありますが、 a[n][n]はどのような変数宣言していますか? Cでは float a[n][n] ; と宣言すると a[0][0]~a[n-1][n-1]のn×n個の配列が用意されます。0から始まることと、「0からn個の整数」はn-1になることは、よく間違える点なので注意してください。 > a11,a12,a13---a1n, というデータを入れる際には、 ・a[1-1][1-1] = a11, a[1-1][2-1]=a12 .... とCの配列に添字を合せる方法と ・float a[n+1][n+1] ;と宣言しておいて a[1][1]=a11, a[1][2]=a12.... と1から始めて、0を使わない方法があります。 どちらにするかは、設計段階で決めておいてください。 以下の例では、0から始まるものを使用します。 さて >for(i=0;i<=n+1;i++){ >for(j=0;j<=n+1;j++){ このループでは、 i,jそれぞれ、0からn+1の n+2 回ループします。 > a11,a12,a13---a1n, この例示が正しいなら、n行n列のデータですから、行も列も2つも多いです。 Cでは、配列の添字が正しいかどうかを『確認しません』。 [n-1]までの配列に[n+1]を入れても、何事もなかったように、コンパイルが成功します。 しかし、大抵は実行時に誤動作を起こし、致命的なエラーになることがあります。 むしろ、エラーになるだけましで、『正常に終了』したかに見えることもあります。 この場合では、ループは for(i=0;i<n;i++){ for(j=0;j<n;j++){ です。この書き方はCではよく見掛けます。 あるいは、FortranのDOループを意識するなら for(i=0;i<=nー1;i++){ for(j=0;j<=nー1;j++){ です > fscanf(fp,"%f7.6 %1s ",&a[i][j],kama); 書式の基本形は %[最大フィールド幅(省略可能)][修飾文字(省略可能)]変換指定文字 です。 これと空白文字以外は「書かれた通りの文字列に一致するパターン」となります。 そこで、この文を見ると %f : floatへのポインタを要求。小数点付きの数字列をfloat型の数値に変換 空白: 0個以上の空白文字 7.6: 「書かれたままの『7.6』という文字列に一致」 空白: 0個以上の空白文字 %1s: charへのポインタを要求。最大1文字の空白でない文字列を、charへのポインタから始まる領域に終端文字'\0'付きで読み込み という書式になっています。 ・%f7.6は %7.6fのつもりなのでしょうが、数値を読み込むなら%fだけで十分です。 小数点以下の数字にはそもそも対応していません。 #ついでに。 printfでは%7.6fとして小数点以下の桁数を指定できます(この場合6桁)が、その前のフィールド幅は #整数部:少なくとも1桁 #小数点:一桁 #を含むため、最低でも8桁必要であり、7と指定しても意味がありません。 ・%1sでカンマを取り込んでいるのでしょう。これは > a11,a12,a13---a1n, と、行末にも必ずカンマが付いているときには有効ですが、もし、カンマが無いと、次の行の先頭の「文字列の先頭1文字」(おそらく a21の最上位の数字か正負の符号)が「カンマのかわり」の取り込まれてしまいます。 確実にカンマを取り込むなら %[,] が使えますし、カンマ無し改行するのなら %[,\n] としてカンマか改行を取り込むようにするのがよいです。 また、取り込んでも使わないのでしょうから、「ただ読むだけ」の*を使って%*[,] %*[,\n] とすると、KAMAなどとダミーの変数を用意する必要もありません。 あと書かれていませんが、 KAMAの宣言はどうなってますか? Cでは文字列は charの配列を使い、必ず終端文字'\n'で終わります。つまり、1文字の文字列を入れるには char KAMA[2]と終端文字の分も含めた大きさにする必要があります。 あと、fscanfを使ったら、戻り値でエラーが無かったかどうかを確認することを強くお勧めします。

knock123
質問者

補足

丁寧にありがとうございます。 宣言はa[n+2][n+2],KAMAはKAMA[2]で宣言しています。混乱させてすみません。正しくは a00,a02,a03---a0n+1, a10,----------a1n+1, . . an+10,----------an+1n+1, 配列には必ずカンマが付いています。 N=1の時、例えば以下の様な形です。 Nは実際には100~5000の間の整数です。この数字データをaに読み込みたいという感じです。 1.0,2.0,3.0, 1.0,2.0,3.0, 1.0,2.0,3.0, (数字とカンマの間にスペースはありません) お話をまとめると、以下でこれで良いのかな?と思えたのですが、 これでも駄目です。私は何を誤解しているのでしょうか? for(i=0;i<=n+1;i++){ for(j=0;j<=n+1;j++){ fscanf(fp,"%f %*[,] ",&a[i][j]); } } ご教授下さい。どうぞよろしくお願いいたします。

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

kama って何のことだろうと思ったら、 comma のことだったんですね。 腑に落ちてよかった。

knock123
質問者

補足

すいません。 人に見せるプログラムで無いので、日英ごっちゃで短くなる配列名を付けてます。

関連するQ&A