• ベストアンサー

配列の比較について・・・困ってます・・。

ご質問させていただきます。 これは、fin2というファイルから数値を抜き出し配列に格納して、finの文字列と比較し、その文字列のある場所で配列の数値と比較し、合致したら、ある出力をするというものなんですが、 配列に格納した数値が、 a[1]=[123] b=[234] a[1]=[345] b=[400] というふうに増えていくときは問題ないですが、途中でたとえば a[n]=100 b[n]=400 a[n+1]=300 b[n+1]=358 という風にn+1番目のaより、n番目のbが大きいときに、止まってしまうんです、これをうまく処理して最後まで比較させたいんですが、どうしてもうまくいきません。どなたかたすけてください。やはり、 n==b[yabu]の処理の後になんか書けばいいんでしょうか?長々と申し訳ございませんでした。 if(fin2!=NULL) { int yabu=0; for(int i=0; fgets(c,CHARMAX,fin2)!=NULL;i++) { sscanf(c,"%d%*c%*c%d",&a[yabu],&b[yabu]); fprintf(fout2,"%d::::::::::::::%d:%d\n",yabu,a[yabu],b[yabu]); yabu++; } } int yabu=0; n=0; while(fgetc(fin)!=EOF) { n++; if(n==a[yabu]) { fprintf(fout2,"A "); } else if(n==b[yabu]) { fprintf(fout2,"B "); yabu++;} else {fprintf(fout2,"C "); } } printf("%d\n",yabu);

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

  • ベストアンサー
  • itohh
  • ベストアンサー率45% (210/459)
回答No.21

こんにちは。itohhといいます。 もし、固定で良いのでしたら、補足で書かれているように配列に持っておくほうが楽ですね。 char strData1[]={(char)0x90,           (char)0x3C,           (char)0x40,           (char)0x83,           (char)0x60,           (char)0x80,           (char)0x3C,           (char)0x00};    :    :    : fwrite( strData1, sizeof( char ), sizeof(strData1), fout2 ); strlen(strData1)では、最後の0x00を数えてくれません、ですからsizeof(strData1)ですね。 strData1を必要な分だけ用意しておくと良いのではないでしょうか。 strData2,strData3などなど。 こんなとこでしょうか?

kitapei
質問者

お礼

どうもありがとうございました。長期間にわたり回答寄せてくださってありがとうございました!!! おかげさまで、いろいろ勉強することができました!!また、わかんないことがでてきたらここで質問してべんきょうしていきたいと思います。 本当にありがとうございました!!

その他の回答 (20)

  • itohh
  • ベストアンサー率45% (210/459)
回答No.20

こんにちは。itohhといいます。 >903C408360803C00という文字列 なんか凄いデジャビュを感じるので過去の回答を検索してみたら 同じことを聞かれたのを思い出しました。 これは、単なる偶然ですよね! 以下の質問でわたしが一度アドバイスしていますのでそちらを参考にしてください。 この方法では、ダメということなら、再度、補足してください。 ・質問:バイナリファイルの書き出し URL:http://oshiete1.goo.ne.jp/kotaeru.php3?q=175147

参考URL:
http://oshiete1.goo.ne.jp/kotaeru.php3?q=175147
kitapei
質問者

補足

なんか、驚きました!!MIDIデータいじくってる人って意外にいるもんですね。 ところで、あのプログラム鬼のようにむずかしいっす。 じっくり解読してみますが、もっと手軽にできる方法ってありません? あのプログラムとこのプログラムを合体させるだけでも難しそう・・。 ・・なんか凄いですね!!なかなか私にはかけたもんじゃないです・・(泣) わがままばっかりですみません・・・・。

  • itohh
  • ベストアンサー率45% (210/459)
回答No.19

こんにちは。itohhといいます。 すみません、言い忘れたことがあります。 malloc関数で動的に配列を獲得した場合は、使い終わったときに解放することを 忘れずにしてください。 >lpBuf = (char*)malloc( lLen+1 );   :   :   :   : >fwrite( lpBuf, sizeof( char ), lLen, fout2 ); // 関数で使い終わったときに解放する。 free( lpBuf );

kitapei
質問者

補足

ご丁寧な回答ありがとうございました!!!! 非常によく全体の、構造がわかりました!!!!! ・・・・・で、なんですが、ここで追加質問するのもどうかとおもったんですが、 今は、A,B,Cをテキストに出力してますよね? これを、バイナリに出力したいんです。 いままで、903C408360803C00という文字列をバイナリに出力するとき、 C[0]=0x90 C[1]=0x3C・・・・という風に配列を用意して fwrite(C,8,1,fout);という風にしてました。 これをlpBuf[a[i]-1]='A';のとこで 903C408360803C00を出力したいんです。そのままやってもだめなようなんで・・。 なにか、うまい方法ってありますか? 度々すみません。これで最後にしたいと思います。 また、疑問でてきたら新たに質問しなおしたいとおもいます。

  • itohh
  • ベストアンサー率45% (210/459)
回答No.18

こんにちは。itohhといいます。 ソースを見てみました。 >if(fin2!=NULL)                 <-----(0) >{ >int yabu=0;                   <----(1) >for(int i=0; fgets(c,CHARMAX,fin2)!=NULL;i++) >{    :    : >yabu++;                     <----(2) >} >}    :    : >int yabu=0;                   <----(3) >long lLen=0; >char *lpBuf=NULL; >if( (fin = fopen( "sample.txt", "r" )) != NULL ) { //sample.txtはfinファイル名    :    : >for(i=0; i<yabu; i++ ) {            <----(4)    :    : > }   :   : yabu変数を考えてみてください。 最終的に、yabu変数の中に入っている値によってforループの回数が変わります。(4) yabu変数は、(2)でfin2ファイルを読み込むときにカウントアップされていますよね? 今度は宣言するところを見てみると、2カ所あります。(1)(3) (1)の宣言では、(0)のifブロック内にありますからこのブロックを抜け出たときに スコープがはずれそれ以降は使えなくなります。 しかし、(3)で再度宣言がされているため(4)で使用することが出来るのです。 ですが、一度、スコープがはずれているため、折角カウントした値はクリアされています。 (forループがゼロ回しか廻らないことになる) 使う直前に変数を宣言することを薦める人もいますが、まだなれていない人には間違いの 元ですから、関数内で使用する変数の宣言は全て先頭で行うことをお薦めします。 まとめますと。 (1)では宣言をやめる。 int aaaaaa()     <---------関数の先頭 {  int yabu=0;  long lLen=0;  char *lpBuf=NULL;  FILE *fin;  FILE *fin2;  int i=0;  (その他の宣言を行う)   :        if(fin2!=NULL)                 <-----(0)   :   : }

  • tgb
  • ベストアンサー率78% (32/41)
回答No.17

 ANo.#13の注意点にも書いたようにcc[]の宣言位置に注意 する必要があります。cc[]の宣言が現在localになっている と思いますが、local変数に対してはメモリーに制約がある ようで、大きなサイズは宣言できません。globalにして関数 の外で宣言すると100万や1000万位はOKだと思います。 マシンのメモリー要領による制約もありますので確認して ください。(この辺の詳しい事は私も余りよく知りません。)  実際に100万の文字を読み込むのなら、私の方法より itohhさんの方がよいのではないかと思います。  プログラムが質問で提示されたもので全て(つまり、質問 のために縮小されたものを作って提示したのではない)なら、 finのファイルから読み込まれる文字データは全く未使用で 文字データの個数のためのみにfinにアクセスしていることに なりますので、何らかの別の方法でこの文字数が分かれば そちらを参照するようにする事を検討された方がよいと思い ます。取りあえず現在の方法でやって行くことは可能は可能 です。

kitapei
質問者

お礼

どうもありがとうございました。大きさの問題ってむずかしいです・・・・。 とりあえず、このプログラムでやっていって、また別に勉強していきたいと思います!!どうも、ありがとうござました!!

  • tgb
  • ベストアンサー率78% (32/41)
回答No.16

失礼しました。 char cch[4]={"ABC"}; または char cch[]={"ABC"}; としてください。

kitapei
質問者

お礼

ご回答ありがとうございます。 素早いお返事本当に嬉しいです。 早速、やってみます。ポイントもうちょっと、待って下さい。

kitapei
質問者

補足

またしても、質問で申し訳ないですが、char cc[]の部分の配列の数についてなんですが、一般的にこれって限界の数ってあるんでしょうか? たとえば1000000ぐらいにするとまともに動かないんですが・・・。 ちなみに環境はVC++6.0です。

  • itohh
  • ベストアンサー率45% (210/459)
回答No.15

こんちには。itohhといいます。 すみません、(3)の処理でfinファイルの長さを越える処理が入っていませんでした。 for(i=0; i<yabu; i++ ) {   if( a[i] <= lLen ) {     lpBuf[a[i]-1] = 'A';   }   if( b[i] <= lLen ) {     lpBuf[b[i]-1] = 'B';   } }

kitapei
質問者

お礼

ご回答ありがとうございます。 返事がおそくなって申し訳ございませんでした。 で、早速やってみたんですが、下のtgbさんに対するレスでもかいたんですが、 初期化子の数が多すぎるといったエラーがとれないんですが、なにかが いけないんでしょうか?

  • itohh
  • ベストアンサー率45% (210/459)
回答No.14

こんにちは。itohhといいます。 先ほどは、時間がなかったのでサンプルを載せることが出来ませんでした。 改めて、じっくり解説します。 (1)fgetc(fin)したデータを使用していないので、まずは、finファイルのサイズを測ることにします。 (2)finファイルのサイズ分のエリアを確保して初期クリアします。    (この後は、ほぼtgbさんと同じ回答です。) (3)tgbさんが回答したように"A"、"B"を動的配列に設定していく。 (4)A,B,Cを設定した動的配列を出力する。 FILE *fin; long lLen=0; char *lpBuf=NULL; // (1)の処理 if( (fin = fopen( "fin.dat", "r" )) != NULL ) {   fseek( fin, 0, SEEK_END ); // ファイルの最後に移動する   lLen = ftell( fin ); // 現在のファイルポインタの位置を取得する(ファイルサイズ)   fclose( fin ); } // (2)の処理 lpBuf = (char*)malloc( lLen+1 ); // ファイルのサイズ+1分のエリアを確保。 memset( lpBuf, 0x00, lLen+1 ); memset( lpBuf, 'C', lLen ); // 'C'で初期クリア // (3)の処理 for(i=0; i<yabu; i++ ) { // 省略します。 } // (4)の処理 fwrite( lpBuf, sizeof( char ), lLen, fout2 ); こんな感じではどうでしょうか?

kitapei
質問者

補足

こんばんは。結局このプログラム考え抜いたんですが、どうしてもむずかしくておてあげです。以下のようにやるとCしか出力されません・・・・。 何度もお恥ずかしいんですが、なにか根本的に間違ってます?お時間あれば教えてください・・・。 if(fin2!=NULL) { int yabu=0; for(int i=0; fgets(c,CHARMAX,fin2)!=NULL;i++) { sscanf(c,"%d%*c%*c%d",&a[yabu],&b[yabu]); fprintf(fout2,"%d::::::::::::::%d:%d\n",yabu,a[yabu],b[yabu]); yabu++; } } int yabu=0; long lLen=0; char *lpBuf=NULL; if( (fin = fopen( "sample.txt", "r" )) != NULL ) { //sample.txtはfinファイル名   fseek( fin, 0, SEEK_END );   lLen = ftell( fin );   fclose( fin ); } lpBuf = (char*)malloc( lLen+1 ); memset( lpBuf, 0x00, lLen+1 ); memset( lpBuf, 'C', lLen ); for(i=0; i<yabu; i++ ) {   if( a[i] <= lLen ) {     lpBuf[a[i]-1] = 'A';   }   if( b[i] <= lLen ) {     lpBuf[b[i]-1] = 'B';   } } fwrite( lpBuf, sizeof( char ), lLen, fout2 );

  • tgb
  • ベストアンサー率78% (32/41)
回答No.13

 ANo.#11の補足を読むとA(800)やB(850)をfinファイルの何番目文字 として出力するのか曖昧になってしまいます。 「a[],b[]にある数値に対応した位置にそれぞれA、Bを出力し、 それ以外ではCを出力する。その際、数値が必ずしも単調に 増加するとは限らない」 と言う条件では行けないのでしょうか?  上のような前提で処理例を示しますのでやってみていただけ ないでしょうか?  a[],b[]を読み込んだ後、以下のようにしてください。 int n=0; int i,k; char cch[3]={"ABC"}; char cc[1000]; while(fgetc(fin)!=EOF) {cc[n]=cch[2];n++;} for(i=0;i<yabu;i++){ k=a[i]-1;cc[k]=cch[0]; k=b[i]-1;cc[k]=cch[1]; } for(i=0:i<n;i++)fprintf(fout2,"%1c ", cc[i]); 注意点: ・cc[1000]のサイズ1000をfinファイルにある文字数より大きな  値に適当に修正してください。 ・a[]、b[]に同じ数値があるときは"B"が出力されます。 ・fin2を読み込むときに設定したyabuの値をそのまま使用します。 ・cc[]のサイズが大きいときは宣言の位置を適当に変えてください。

kitapei
質問者

お礼

お返事おそくなって申し訳ございません。パソコンがこわれちゃったんで・・・。 で、早速、やってみたんですが、 char cch[3]={"ABC"}; のところの、エラーで、「初期化子の数が多すぎます」というエラーが取れません。なにがいけないんでしょうか?

  • itohh
  • ベストアンサー率45% (210/459)
回答No.12

こんにちは。itohhといいます。 前から思っていたのですが、finファイルを実際に読む必要性がないのではないでしょうか? finファイル内のデータを使うのではなく、データの長さだけが必要なのですよね? finファイルとは、例えば"fin.dat"みたいにプログラムが動く前に実在するファイルなのですよね? finファイルの長さを測ってその長さ以内のa,bを順に出力するのではいけないのでしょうか?

  • itohh
  • ベストアンサー率45% (210/459)
回答No.11

こんにちは。itohhといいます。 >130..344 >500..600 >700..999 >800..850 この場合は、どのように出てほしいのでしょうか? A(130) B(344) A(500) B(600) A(700) A(800) たぶん、上記のようになって終わってしまうと言うことですよね? この後、 B(999) B(850) と出てほしいのでしょうか? それとも A(130) B(344) A(500) B(600) A(700) B(999)  <--追加 A(800) B(850)  <--追加 と出てほしいのでしょうか?

kitapei
質問者

補足

ご回答ありがとうございます。 この場合は A(130) B(344) A(500) B(600) A(700) B(999)  <--追加 A(800) B(850) というふうに出したい んです。つまり、fin2の ファイルには上から順に一行に二つ数字があるんですけど、それをaとbというふたつの配列に読み込んでますよね?それを一行分ずつ上から順に出力したいんです。つまり、配列に格納された数字の大きさを中心に考えるのではなくて、一行分ずつ出力していきたいんです。重ねがさね恐縮ですが、アドバイス頂けたら嬉しいです。

関連するQ&A