• ベストアンサー

すっきりかくには?

xyn[10][1000]に数値データが入っています。 それを横100個×縦100個の形に出力してカンマをつけたい。 programの一部を抜き出しました。 一応目的どおり動くのですが、もう少しすっきりした書き方を するためにはどのような方法がありますか? FILE *fp2; if( (fp2 = fopen("res.dat", "w")) == NULL) { fprintf(stderr, "出力ファイルを開けません\n"); return 1; } for(i=0;i<100;i++)fprintf(fp2,"%d ,",i);//番号 for(k=0;k<10;k++){ for(i=0;i<1000;i++){ if(i==100)fprintf(fp2,"\n"); if(i==200)fprintf(fp2,"\n"); if(i==300)fprintf(fp2,"\n"); if(i==400)fprintf(fp2,"\n"); if(i==500)fprintf(fp2,"\n"); if(i==600)fprintf(fp2,"\n"); if(i==700)fprintf(fp2,"\n"); if(i==800)fprintf(fp2,"\n"); if(i==900)fprintf(fp2,"\n"); fprintf(fp2,"%f ,",xyn[i][k]); }fprintf(fp2,"\n"); } よろしくお願いします。

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

  • ベストアンサー
  • hitomura
  • ベストアンサー率48% (325/664)
回答No.5

No.1の回答をしたhitomuraです。 最初の書き込みでは時間がなかったため、なぜそう変更したかかけませんでした。 と、いうわけで、ちょっと解説を。 あなたのコードでは、今まで書き込んだデータ個数が100の倍数かどうか判定(およびもしそうなら改行処理)をし、その後データを書き込んでいます。 しかし、書き込みの直後、今書き込んだデータが100の倍数番目かどうかを判定したほうが自然ではないでしょうか? その方針に従い、 (1)if文をデータ書き込み文の後ろに移動、 (2)今の書き込み個数を求めるため判定する数をi→i+1に変更 (3)「100の倍数」を表すため、剰余演算子を使用 という変更をしました。 …しかし、この方法にも問題がありまして… それは、(3)の変更です。この変更だと、各ループごとに必ず剰余を求めなくてはならず、その分処理が遅くなります。 #まあ、ファイルへの出力速度からすると微々たるものですが… と、いうわけで、ループ内の計算回数を極力減らす方針でもう1度書きなしてみました。 for(k=0;k<10;k++){  for(i=0;i<1000;i++){   if(i==100)fprintf(fp2,"\n");   if(i==200)fprintf(fp2,"\n");   if(i==300)fprintf(fp2,"\n");   if(i==400)fprintf(fp2,"\n");   if(i==500)fprintf(fp2,"\n");   if(i==600)fprintf(fp2,"\n");   if(i==700)fprintf(fp2,"\n");   if(i==800)fprintf(fp2,"\n");   if(i==900)fprintf(fp2,"\n");   fprintf(fp2,"%f ,",xyn[i][k]);  }fprintf(fp2,"\n"); } ↓ for(i=0;i<10;i++){  for(j=0;j<10;j++){   int k = j * 100;   int k_boundaly = k + 100;   for ( /* k:初期化済み */; k < k_boundaly; k++ ){    fprintf(fp2,"%f ,",xyn[i][k]);   }   fprintf(fp2,"\n");  } } 今度のは、100個のデータ出力および改行出力をひとまとめにして行い、それを10回行う(これで計1000個)、さらにそれらを全体で10回行う、という方針になります。

hgdream
質問者

お礼

詳しく解説していただき、ありがとうございました。

その他の回答 (4)

  • quenista
  • ベストアンサー率28% (122/425)
回答No.4

>iが0のときに改行してしまいますので、ご注意ください。 あら、ほんとですね。(^_^;;;大汗) madmanさん、ご指摘有難う御座います。m(_ _)m

  • madman
  • ベストアンサー率24% (612/2465)
回答No.3

FILE *fp2; if( (fp2 = fopen("res.dat", "w")) == NULL) {  fprintf(stderr, "出力ファイルを開けません\n");  return 1; } for(i=0;i<100;i++){  fprintf(fp2,"%d ,",i);//番号 } for(k=0;k<10;k++){  for(i=0;i<1000;i++){   if(i && !(i%100)){    fprintf(fp2,"\n");   }   fprintf(fp2,"%f ,",xyn[k][i]);  }  fprintf(fp2,"\n"); } #2の方の回答の if(i%100==0) だけでは、iが0のときに改行してしまいますので、ご注意ください。 また、プログラムはすっきりさせるだけでなく、後日変更時や後から見たときにもわかりやすくするために、if文での処理がたとえ1行であっても括弧を使うなどしたほうが良いです。バグの混入が減ります。 それと、fprintf(fp2,"%f ,",xyn[i][k]);ですが、iとkが逆になっています。転写時のミスでしょうか? 上記ソースには見栄えを整えるため、全角スペースを入れています。 コピー&ペーストする場合はご注意ください。

hgdream
質問者

お礼

ありがとうございます。

  • quenista
  • ベストアンサー率28% (122/425)
回答No.2

プログラムをすっきりさせるには、ロジックを構成する物を良く考えると良いと思います。 数学の、式を纏めるのと似てますね。 先ず、同じ値を比較する場合は、if文を使うよりも、Switchi文を使う方が良いです。 この例ですと、 if(i==100)fprintf(fp2,"\n");    ・    ・    ・ if(i==900)fprintf(fp2,"\n"); となってる部分を、 switch(i){   case 100:fprintf(fp2,"\n"); break;    ・    ・    ・   case 900:fprintf(fp2,"\n"); break; } とします。 しかし、もっと良く見てみると、全ての所でやってる事が一緒ですね? そういう場合は、 switch(i){   case 100:    ・    ・    ・   case 900:fprintf(fp2,"\n"); break; } とすれば、良いのです。 しかし、もっと良く見ると比較する値にも法則がありますね。 計算式に直して見ましょう。 if((i%100)==0)fprintf(fp2,"\n"); と1行になってしまいました。 もっとすっきりさせるには、もっと大きな範囲から纏めて見れば良いと思いますよ。

hgdream
質問者

お礼

ありがとうございます。

  • hitomura
  • ベストアンサー率48% (325/664)
回答No.1

このようにしてみては? for(k=0;k<10;k++){  for(i=0;i<1000;i++){   if(i==100)fprintf(fp2,"\n");   if(i==200)fprintf(fp2,"\n");   if(i==300)fprintf(fp2,"\n");   if(i==400)fprintf(fp2,"\n");   if(i==500)fprintf(fp2,"\n");   if(i==600)fprintf(fp2,"\n");   if(i==700)fprintf(fp2,"\n");   if(i==800)fprintf(fp2,"\n");   if(i==900)fprintf(fp2,"\n");   fprintf(fp2,"%f ,",xyn[i][k]);  }fprintf(fp2,"\n"); } ↓ for(k=0;k<10;k++){  for(i=0;i<1000;i++){   fprintf(fp2,"%f ,",xyn[i][k]);   if((i+1)%100==0)fprintf(fp2,"\n");  } }

関連するQ&A

  • ファイルをオープンするときのエラー

    C言語であるファイルにある数値を100ごとに合計して,ほかのファイルに書き出す。しかし,実行するとエラーでてきます。原因はわからないです。因みに,オープンしたいファイルをほかのディレクリに置いたら,ファイルが見付かりませんとのエラーがありました、WindowsのC言語でカレントディレクトリを探すときは何の関数を使えばいいでしょうか? int main(void) { int i,k; int num; char filename[64],fileread[64],filewrite[64]; FILE *fp0,*fp1; double sum1,sum2,sum3; int *ch[3]; sum1=sum2=sum3=0.0; printf("ファイル名を入力ください!\n"); scanf("%s",filename); fprintf(stderr,"\n%s\n",filename); sprintf(fileread,"C:\\%s.txt",filename); fprintf(stderr,"%s\n",fileread); sprintf(filewrite,"C:\\%s.csv",filename); for (i=0;i<3;i++) { if ( (ch[i]=(int *)malloc(4*30))==NULL ) { fprintf(stderr,"Cannot get memory <ch[%d]>.",i); return -1; } } fprintf(stderr,"%s\n",filewrite); if ((fp0=fopen(fileread,"rb"))==NULL) { fprintf(stderr,"Cannot open file %s\n",fileread); return 0; } fscanf(fp0,"%d", &num); if((fp1=fopen(filewrite,"wb"))==NULL) { fprintf(stderr,"Cannot open file!%s\n",filewrite); return 0; } for(i=0;i<50;i++) { fscanf(fp0,"%d %d %d",*(ch[0]),*(ch[1]),*(ch[2])); } for(i=0;i<num/100;i++) { for (k=0;k<100;k++) { fscanf(fp0,"%d %d %d",*(ch[0]),*(ch[1]),*(ch[2])); if ( feof(fp0) != 0 ) break; sum1=sum1+*(ch[0]); sum2=sum2+*(ch[1]); sum3=sum3+*(ch[2]); } fprintf(fp1,"%d %d %d\n",sum1,sum2,sum3); } fclose(fp0); fclose(fp1); return 0; }

  • ファイル

    c言語初心者です。 どなたか教えていただけませんか? これだとiが定義されないことになってしまいます。 #include<stdio.h> #include<stdlib.h> int main() { FILE *fp; fp=fopen("monai", "w"); if(fp==NULL){ fprintf(stderr,"ファイルのオープンに失敗しました。\n"); exit(0); } int i; for(i=1;i<=30;i++) { if(i<=9){ fprintf(fp," %d ",i); } else if(i%10==0) { fprintf(fp,"%d\n",i); } else { fprintf(fp,"%d ",i); } } fclose(fp); return 0; } ビルドもできません。

  • fprintfで出力するファイルのパス指定について

    cで以下のコードを書いています。 file.txtを任意の場所に作りたいのですが どうすればいいのでしょうか。 fopen("c:\file.txt", "r"))と書くとエラーになって しまいました。 void main(void) { FILE *fp; if ((fp = fopen("file.txt", "r")) == NULL) { fprintf ( stderr, "err\n" ); exit (2); } fprintf(fp,"%s\n",a);; fclose(fp); }

  • C言語でファイルを出力

    ファイルの中に変数をいれて複数のファイルをつくろうとしたのですが、 できたファイルの後に?マークがついてきます。 file = fopen("filename.txt", "w"); for(j=0; j<30; j++){ fprintf(file ,"%d.dat\n",j ); } fclose(file); file2 = fopen("filename.txt", "r"); として、ファイル名を書いたファイルをつくってから、 for(k=0; k<30; k++){ fgets(fp,sizeof(fp),file2); file_out = fopen(fp,"w"); 省略 fprintf(file_out, %e %e \n",a ,b); fclose(file_out); } fclose(file2); をして、30個のファイルを出力すると、 0.dat? 1.dat? 2.dat? . . . 29.dat? というファイルができてしまいます。 ファイルの中はしっかりできています。 なにか解決法を知っている方がおりましたら、どうか教えて下さい。

  • バイナリファイルの読み込み(C言語)

    raw(音楽ファイル)データを配列rawに読み込みたいのですが,バイナリファイルの読み込み方がわかりません. サンプルで以下のようなソース(途中略)があるのですが, ・なぜrawの型としてshortを使っているのか ・データ数の半分(file_size = ftell(fp) / 2)しか読み込んでいない ・fgetc(fp) << 8 あたりの意味がわからないので教えて下さい. -------------------------------------------------------- short *raw; if((fp=fopen(argv[1], "rb")) == NULL){ fprintf(stderr, "can't open %s.\n", argv[1]); exit(1); } fseek(fp, 0, SEEK_END); file_size = ftell(fp) / 2; fseek(fp, 0, SEEK_SET); raw = (short *)malloc((size_t)(file_size * sizeof(short))); if(raw == NULL){ fprintf(stderr, "malloc error\n"); exit(1); } for(i=0;i<file_size;i++) raw[i] = (short)((fgetc(fp) << 8) | fgetc(fp)); -----------------------------------------------------

  • 入力ファイルのデフォルトの設定

    下のソースは入力ファイルの内容が例えば、 1 2 3 4 5 6 7 8 の時にその内容を出力するものです。 入力ファイル名がinput.datの場合、プログラム実行後にinput.datと入力し、Enterを押します。 このプログラムにinput.datをデフォルトとし、空Enterで入力を実行できるようにしたいと考えています。 入力ファイル名がinput.datでない場合は従来通りファイル名を入力してEnterを押すようにします。 この場合、どのようにソースを変更すればよいでしょうか。お手数ですが、教えてください。よろしくお願いします。 #include <stdio.h> #include <stdlib.h> int main(){ int i,N=0,data[10]; char ifile[20]; FILE *fp; printf("input file name: "); scanf("%s",ifile); if((fp=fopen(ifile,"r"))==NULL){ fprintf(stderr,"input file error\n"); exit(1); } while(fscanf(fp,"%d",&data[N])!=EOF && N<10){ N++; } printf("Total Number of Data = %d\n",N); for(i=0;i<N;i++){ printf("%d\n",data[i]); } fclose(fp); return 0; }

  • ファイル入力

    1 20 2 30 3 95 4 52 5 90 3 Maximum  上記の様な入力ファイルinput.datのうち1~5行目のデータを表示するプログラムを作っています。  6行目は空白で、7行目は2列目の中で最大値をとる行の1列目の数値が入っています。  1列目の数値は最後の行を除いて重複することはありません。  入力データの行数はファイルによって最大20行まで変動します。列数は2列で固定です。  以下のプログラムのままでは6行目以降のデータも読み取ってしまい、出力がおかしくなってしまいます。  1~5行目のデータのみ出力するにはどうしたらよいでしょうか。  ご存知の方、お手数ですが教えてください。よろしくお願いします。 #include <stdio.h> #include <stdlib.h> #define row 20 #define col 2 int main(){ int i,j,data[20][2]; FILE *fp; if((fp=fopen("input.dat","r"))==NULL){ fprintf(stderr,"Cannot open file input.dat\n"); exit(1); } for(i=0;i<row;i++){ for(j=0;j<col;j++){ fscanf(fp,"%d",&data[i][j]); printf("%d ",data[i][j]); } printf("\n"); } fclose(fp); return 0; }

  • 式を変更して画像を作りたいです

    以下のプログラムはカラー画像を作成し、MAX_REPEAT回コピーした後、PPMファイルとして出力するものです。 画像作成部分の式を変更し、画像を作ろうと思いますが、アイディアがあれば参考にしたいので教えてください。 簡単でけっこうですから是非お願いします。 gcc -Wall -O2 -DCIP ファイル名でコンパイルします。 PPMファイルはdisplay tmp.ppmで表示します。 convert tmp.ppm tmp.jpgでjpg形式に変換できます。 #include <stdio.h> #include <stdlib.h> #include <math.h> //mathライブラリを利用する場合はコンパイル時に -lm #define MAX_REPEAT 1 //コピー繰り返し回数 #define SIZE 500 //画像サイズ(行=列) #ifdef CSQ #define DIM1 3 #define DIM2 SIZE #define DIM3 SIZE #endif #ifdef CIP #define DIM1 SIZE #define DIM2 SIZE #define DIM3 3 #endif typedef unsigned char UCHAR; void write_ppm_csq(UCHAR [][DIM2][DIM3],char *,int ,int); void write_ppm_cip(UCHAR [][DIM2][DIM3],char *,int ,int); void error1(char *); /* 画像のコピー */ void copy3dimg(UCHAR res[][DIM2][DIM3],UCHAR org[][DIM2][DIM3],int dim1,int dim2,int dim3) { int i,j,k; for(i=0;i<dim1;i++) for(j=0;j<dim2;j++) for(k=0;k<dim3;k++) res[i][j][k]=org[i][j][k]; } int main(void) { int repeat; UCHAR org[DIM1][DIM2][DIM3]; /* 作成画像 */ UCHAR res[DIM1][DIM2][DIM3]; /* コピー先画像 */ /* 画像の作成 */ { int i,j,k; for(i=0;i<DIM1;i++) for(j=0;j<DIM2;j++) for(k=0;k<DIM3;k++) org[i][j][k]=(UCHAR)((i*j+10*j+k*k)%256); } /* 画像のコピー */ for(repeat=0;repeat<MAX_REPEAT;repeat++) copy3dimg(res,org,DIM1,DIM2,DIM3); /* ファイルへの出力 */ #ifdef CSQ write_ppm_csq(res,"./tmp.ppm",DIM3,DIM2); #endif #ifdef CIP write_ppm_cip(res,"./tmp.ppm",DIM2,DIM1); #endif return 0; } /* ファイルへの出力(CSQ) */ void write_ppm_csq(UCHAR data_buf[][DIM2][DIM3],char *fname,int width,int height) { FILE *fp; int m, n; if((fp = fopen(fname, "wb")) == NULL) { fprintf(stderr, "file(%s) can't open\n", fname) ; exit(1) ; } fprintf(fp, "P6\n") ; /* カラー画像かつバイナリーデータの記号 */ fprintf(fp, "%d %d\n", width, height) ; /* 画像の幅(列数)と高さ(行数) */ fprintf(fp, "255\n") ; /* 最大値 */ for(m=0;m<height;m++) for(n=0;n<width;n++) { fwrite(&data_buf[0][m][n], sizeof(UCHAR), 1, fp); fwrite(&data_buf[1][m][n], sizeof(UCHAR), 1, fp); fwrite(&data_buf[2][m][n], sizeof(UCHAR), 1, fp); } fclose(fp) ; } /* ファイルへの出力(CIP) */ void write_ppm_cip(UCHAR data_buf[][DIM2][DIM3],char *fname,int width,int height) { FILE *fp; if((fp = fopen(fname, "wb")) == NULL) { fprintf(stderr, "file(%s) can't open\n", fname) ; exit(1) ; } fprintf(fp, "P6\n") ; /* カラー画像かつバイナリーデータの記号 */ fprintf(fp, "%d %d\n", width, height) ; /* 画像の幅(列数)と高さ(行数) */ fprintf(fp, "255\n") ; /* 最大値 */ fwrite(&data_buf[0][0][0], sizeof(UCHAR), width*height*3, fp); fclose(fp) ; } /* エラー処理 */ void error1(char *message) { printf("%s\n",message); exit(1); }

  • ファイルへの書込み処理が異常に遅い

    以下のファイルへの書込みを行なうプログラムの処理速度が極端に遅く困惑しています。 -------------------------------------------------------------------------------- /*  文字列"0,"をファイルに約2MB出力するプログラム  (2000文字で改行、1行毎にfopen&fclose) */ #include<stdio.h> void main( int argc, char *argv[] ) {   FILE *fp;   for( int i = 0; i < 1000; i++ )   {     if( !(fp = fopen( "C:\hogehoge.log", "a" ) ) )     {       exit( 1 );     }     for( int j = 0; j < 1000; i++ )     {       fprintf( fp "0," );     }     fprintf( "\n" );     fclose( fp );   }   exit( 0 ); } -------------------------------------------------------------------------------- 処理時間は5分程度です。 出力する文字列を"0#"に変えると5~6秒で終了します。 カンマが入ると違うのでしょうか? OSはWinXP、コンパイラはVC++7.0です。 原因と解決策をご存知の方、よろしくご教示下さい。

  • ファイル入力方法

    下記の様な入力ファイルinput.datの空行までを出力する(空行以降は無視)プログラムを作ろうとしています。 11 12 13 14 15 16 17 18 19 20 21 22 1001 23 24 25 26 下記のようなソースを作成しましたが、入力が空行で止まってくれません。 どのように修正すればよいのでしょうか? 大変お手数ですが、教えてください。よろしくお願いします。 #include <stdio.h> #include <stdlib.h> int main() { int i,N,a[10][20]; FILE *fpi; if((fpi=fopen("input.dat","r"))==NULL) { fprintf(stderr,"Cannot open file input.dat\n"); exit(1); } N=0; for(i=0 ; i<10 && fscanf(fpi,"%d %d %d %d",&a[i][0],&a[i][1],&a[i][2],&a[i][3]) != 3 ; i++) { N++; } printf("N=%d\n",N); for(i=0;i<N;i++) { printf("%d %d %d %d\n",a[i][0],a[i][1],a[i][2],a[i][3]); } fclose(fpi); return 0; }

専門家に質問してみよう