- 締切済み
行を分解して配列に入れるには
プログラミング初心者です。 環境はWindows XP SP2 Visual C++6.0,MFC,SDIです。 上の環境下でファイル読み込み関数を作っているのですが、 MFCのファイルダイアログ(コモンダイアログ)を呼び出した後ReadStringで一行読み込んだ行 abcde 18 abc 23 54 23 43 を再度sscanfで読み込んで a = "abede" b = 18 c = "abc" d = 23 e = 54 f = 23 g = 43 と配列に入れなおしたのですがa = "a"と始めの一文字しか配列に入りません。空白で区切る方法など、いい方法がありましたら教えてください。 よろしくお願いします。
- みんなの回答 (8)
- 専門家の回答
みんなの回答
- Oh-Orange
- ベストアンサー率63% (854/1345)
★追記。 ・ポインタでアクセスするなら i カウンタを取ってポインタの最後を比較する方法が普通かな。 つまり // 100回読み出す場合 read_t *p, data[ 100 ]; for ( p = data ; p < &data[100] ; p++ ){ ReadString( str ); sscanf( str, "%s %d %s %d %d %d %d", p->a, &p->b, p->c, &p->d, &p->e, &p->f, &p->g ); } とします。 ・あと i カウンタを使うなら // 100回読み出す場合 read_t *p, data[ 100 ]; int i; for ( i = 0 ; i < 100 ; i++ ){ p = &data[ i ]; ReadString( str ); sscanf( str, "%s %d %s %d %d %d %d", p->a, &p->b, p->c, &p->d, &p->e, &p->f, &p->g ); } というやり方もあります。 どれも処理は同じです。 ・以上。
- zwi
- ベストアンサー率56% (730/1282)
補足します。 Oh-Orangeさんがポインタで記述してますが、 // 100回読み出す場合 read_t data[ 100 ]; int i; for ( i = 0 ; i < 100 ; i++ ){ ReadString( str ); sscanf( str, "%s %d %s %d %d %d %d", data[i].a, &data[i].b, data[i].c, &data[i].d, &data[i].e, &data[i].f, &data[i].g ); } と書いても問題ないです。 読みやすさ、分かり易さで選んでください。 ちなみに書き忘れていたのですが、最初のプログラムで&a[i]でなぜ動いていたかを解説します。 &はポインタ化するための演算子ですが、a[i]をポインタ化するとaの配列のi番目を先頭とするポインタを得ることになります。 ようするにiだけポインタの先頭がずれることになりますが同じ配列にsscanfで格納されるので上書きされて文字列が壊されているプログラムだったのです。
- Oh-Orange
- ベストアンサー率63% (854/1345)
★アドバイス >b、d、e、f、gは整数ですが、テキストファイルから沢山読み込んだ後、 >別の部分で取り出すために配列にしていました。よくなかったでしょうか? ↑ それなら構造体を用意してその配列として読み込めばよい。 つまり // 構造体を用意 typedef struct read_t { char a[ 256 ]; int b; char b[ 256 ]; int d; int e; int f; int g; } read_t; // 100回読み出す場合 read_t *p, data[ 100 ]; int i; for ( p = data, i = 0 ; i < 100 ; i++, p++ ){ ReadString( str ); sscanf( str, "%s %d %s %d %d %d %d", p->a, &p->b, p->c, &p->d, &p->e, &p->f, &p->g ); } とすれば後で配列として取り出せますけど。 ・以上。
- Oh-Orange
- ベストアンサー率63% (854/1345)
★整数と文字列の区別を先につけましょう。 ・MFC を使う以前の基本です。 宣言が char a[256]; int b[256]; char c[256]; int d[256]; int e[256]; int f[256]; int g[256]; となっていますが正しくは char a[ 256 ]; int b; char c[ 256 ]; int d; int e; int f; int g; となります。 b、d、e、f、g は整数ですよね。 配列にする必要はありません。 ・上記のように宣言したら sscanf( str, "%s %d %s %d %d %d %d", a, &b, c, &d, &e, &f, &g ); //再度読み込み とすれば良い。 『&』文字が必要なのは整数型の b、d、e、f、g 変数のみです。 ※a、c に付けても問題はないが普通はつけない。混乱を避けるためにも付けるべきでない。 ・あと C 言語では文字列を直接比較できないため strcmp() 関数を利用します。 間違い⇒if(a[i]='abcde' || a[i]=='a') 関数1; 正しい⇒if( !strcmp(a,"abcde") || !strcmp(a,"a") ) 関数1; ※strcmp() 関数は第一引数、第二引数の文字列を比較して -1、0、+1 を返します。 >if文の使い方がおかしいのでしょうか? ↑ if文ではなくて文字列の比較がおかしいです。→正しくは strcmp() 関数を利用。 その他: >環境はWindows XP SP2 Visual C++6.0,MFC,SDIです。 ↑ C++、MFC はまだ早すぎです。 まずは C 言語の基本『文字列とは』から始めましょう。 もちろん C++ から始めても良いですが『文字列とは』から始める必要があります。 ・以上。下の『参考URL』をよく読みましょう。
- zwi
- ベストアンサー率56% (730/1282)
全体的に文字列の勉強が足りません。 問題点(1) C言語の文字列を理解できていません。文字列は文字配列にしか入れることができません。 a[i]と書いてしまっては、文字配列ではなくて文字変数に過ぎません。 解決策としては、 char a[256][100]; ← これだと99文字が入る文字配列を256個の配列にしています。なぜ99文字かと言うと文字列の終端には'\0'が必要なので100文字入る配列でも(100-1)文字しか入らないのです。 文字列をちゃんと理解しないと今後プログラムを作る上で困ると思います。参考書があるならちゃんと読み直してください。 問題点(2) 文字'a'と文字列"a"は別物だと理解してください。 文字変数に代入できるのが'a'で"a"は代入できません。 文字配列に格納できたり、文字配列と比較できるのが"abced"と書く文字列です。 問題点(3) strcmpの仕様を確認してください。 if( 0 == strcmp("aa","aa") ) と書くのが等しい文字列か比較する時の正しい書き方です。 勉強不足ですので必ず文字列関数ライブラリについて勉強してください。
お礼
あまり文字列について注意を払わなかったので今回を機会に 文字列についてしっかりと勉強しなおしたいと思います。 ありがとうございました。
- zwi
- ベストアンサー率56% (730/1282)
私も文字と文字列と数値の意味が理解できていないように見えますので、a~gの配列宣言の部分が見たいです。 if(a[i]=='abcde')と間違った文字列比較でコンパイルエラーにならない時点で、char a[100];と書いてある気がしています。 ちなみに文字列の比較はstrcmp()関数を使います。
補足
おっしゃるとおりに定義していました。 a~gの定義は char a[256]; int b[256]; char c[256]; int d[256]; int e[256]; int f[256]; int g[256]; if(!strcmp(&a[i], "abcde") 関数1; と用いた方がよろしいでしょうか?
- Tacosan
- ベストアンサー率23% (3656/15482)
えと.... 「文字列比較に == は使えない」んだけど.... あと, その読み込み方だと, やっぱり a~g の定義を見てみたいなぁ. その辺からしてあやしい気がする.
補足
>「文字列比較に == は使えない」んだけど.... 使えないのですか?知らなかったです。 a~gの定義は char a[256]; int b[256]; char c[256]; int d[256]; int e[256]; int f[256]; int g[256]; としています。 何処がおかしいでしょうか?
- Tacosan
- ベストアンサー率23% (3656/15482)
まず, 次のことを確認してみてはどうでしょうか: ・a~g の定義と, sscanf のフォーマット文字列が合致しているかどうか ・ReadString で読み込んだ行が期待したデータになっているか 「ReadString で読み込んだ行が実は Unicode だった」とかいうオチがあると困るので.
補足
お盆の時期なのに早速の回答ありがとうございます。 それぞれ確認してみました。 ReadStringで読み込んだ行をAfxMessageBox()を使って表示したところ期待通りに表示されました。 sscanfで読み込んだ値もaについてみてみたのですが問題なさそうです。 sscanfで読み込んだ後にif文を使って関数わけをしているのですが そのif文の使い方に問題があるのかもしれません。 for(i=0;i<=100;i++){ //繰り返しを仮に100回と指定 ReadString(str); //一行読み込み sscanf(str,"%s %d %s %d %d %d %d",&a[i],&b[i],&c[i],&d[i],&e[i],&f[i],g[i]); //再度読み込み if(a[i]=='abcde') 関数1; ----(1) else if(a[i]=='c') 関数2; } 行の最初の配列aにより関数わけをしています。(1)を以下の様にすると関数1を読み込むのですが if(a[i]='abcde' || a[i]=='a') 関数1; if文の使い方がおかしいのでしょうか? お願いします。
お礼
貴重なアドバイスありがとうございます。 >b、d、e、f、g は整数ですよね。 >配列にする必要はありません。 b、d、e、f、gは整数ですが、テキストファイルから沢山読み込んだ後、別の部分で取り出すために配列にしていました。よくなかったでしょうか? >sscanf( str, "%s %d %s %d %d %d %d", a, &b, c, &d, &e, &f, &g ); //再度読み込み >とすれば良い。 >『&』文字が必要なのは整数型の b、d、e、f、g 変数のみです。 知らなかったです。勉強になりました。 >間違い⇒if(a[i]='abcde' || a[i]=='a') 関数1; >正しい⇒if( !strcmp(a,"abcde") || !strcmp(a,"a") ) 関数1; strcmp関数は先日知ったばかりでまだ使いこなせてませんでしたが便利な関数のようですね。 参考URLを参考にして勉強したいと思います。 ありがとうございました。