• 締切済み

行を分解して配列に入れるには

プログラミング初心者です。 環境は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"と始めの一文字しか配列に入りません。空白で区切る方法など、いい方法がありましたら教えてください。 よろしくお願いします。

みんなの回答

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.8

★追記。 ・ポインタでアクセスするなら 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)
回答No.7

補足します。 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)
回答No.6

★アドバイス >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)
回答No.5

★整数と文字列の区別を先につけましょう。 ・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』をよく読みましょう。

参考URL:
http://www9.plala.or.jp/sgwr-t/c/sec02.html#s2-4
nirvanana
質問者

お礼

貴重なアドバイスありがとうございます。 >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を参考にして勉強したいと思います。 ありがとうございました。

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.4

全体的に文字列の勉強が足りません。 問題点(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") ) と書くのが等しい文字列か比較する時の正しい書き方です。 勉強不足ですので必ず文字列関数ライブラリについて勉強してください。

nirvanana
質問者

お礼

あまり文字列について注意を払わなかったので今回を機会に 文字列についてしっかりと勉強しなおしたいと思います。 ありがとうございました。

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.3

私も文字と文字列と数値の意味が理解できていないように見えますので、a~gの配列宣言の部分が見たいです。 if(a[i]=='abcde')と間違った文字列比較でコンパイルエラーにならない時点で、char a[100];と書いてある気がしています。 ちなみに文字列の比較はstrcmp()関数を使います。

nirvanana
質問者

補足

おっしゃるとおりに定義していました。 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)
回答No.2

えと.... 「文字列比較に == は使えない」んだけど.... あと, その読み込み方だと, やっぱり a~g の定義を見てみたいなぁ. その辺からしてあやしい気がする.

nirvanana
質問者

補足

>「文字列比較に == は使えない」んだけど.... 使えないのですか?知らなかったです。 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)
回答No.1

まず, 次のことを確認してみてはどうでしょうか: ・a~g の定義と, sscanf のフォーマット文字列が合致しているかどうか ・ReadString で読み込んだ行が期待したデータになっているか 「ReadString で読み込んだ行が実は Unicode だった」とかいうオチがあると困るので.

nirvanana
質問者

補足

お盆の時期なのに早速の回答ありがとうございます。 それぞれ確認してみました。 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文の使い方がおかしいのでしょうか? お願いします。

関連するQ&A

  • 2行読み込んで一行戻り、また2行読み込む

    2行読み込んで一行戻り、また2行読み込む はじめまして、現在、「2行読み込み、一行戻り、また2行読み込む」処理のものを作成しています。 具体的には、 A B C D E と5行に渡り記述されたファイルを上記の旨で表示させる場合、 A B B C C D D E としたいのですが、 filename = ARGV[0] ABCDE = [] file = open(filename) while f = file.gets do  f.chomp!   g = file.gets   g.chomp!  p f  p g end file.close とすると出力は "A" "B" "C" "D" abcde.rb:9: private method `chomp!' called for nil:NilClass (NoMethodError) もちろん2行読み込んで、そのまま次の2行を読み込む記述のため上記のようになってしまいます。 まとめますと、 「一行戻るための記述がわからないので、それを実現するための記述を教えてほしい」 ということです。 rewindを使うと先頭まで戻ってしまうのでどうしたらいいのかさっぱりです。 わかりづらくて非常に申し訳ない、初歩的であろう質問ですがよろしくお願いします。 rubyは1.8.6を使っています。

    • ベストアンサー
    • Ruby
  • 配列

    String型の配列の中の文字列の文字数を数える方法で困っています。 問題は、int型の変数lenで与えられた数字よりも大きい文字数の文字列はいくつあるか調べます。 例) stringsLongerThan({"a","ab","abc"}, 0) 3つ全ての文字列の文字数は0より大きいので3を返す stringsLongerThan({"a","ab","abc"}, 2) "abc"の文字数が2より大きいので1を返す stringsLongerThan({"a","ab","abc","abcd","abcde","abcdef","abcdefg"}, 3) "abcd","abcde","abcdef","abcdefg"の4つが文字数3より大きいので4を返す 途中まで組んだのですが、配列array[]の中の文字列の文字数を数えるにはどうしたらよいのでしょうか? public int stringsLongerthan(String[] array, int len){       int result=0;      for(int i=0;i<array.length;i++){        //ここで配列array[i]の文字列の文字数を数える       int count=文字数;       if(cont>len)        result++;     }      return result; } 宜しくお願いします。

    • ベストアンサー
    • Java
  • セルの値が同じ行を条件に従って行削除するマクロ

    A~E列までデータがあり 行数は約30,000行あります。 A列は半角英数字と-で桁数は11桁又は14桁です。 数字のみもあれば数字と英字の組み合わせもあります。 (英字はどこの桁にあるか何個あるかは不規則です) 例 ABCD123456789X 124345678901234 55555-55555 ABC12345DEF678 E列には半角の 1 か 2 しかありません。 A列が同じ値の行を検出して重複している行は1行だけ残して 後は行削除をしたいです。 行削除はE列の値によって判定したいです。 重複行は1つの値に対して何行あるか不明です。 30,000行のうち、重複行を削除すると10,000行くらいになる予定です。 (1)重複行にてE列の値が1だけの場合    どれでもいいので1行残して残りは行削除 (2)重複行にてE列の値が2だけの場合   どれでもいいので1行残して残りは行削除 (3)重複行にてE列の値が1も2もある場合   E列の値が2の行をどれでもいいので1行残して残りは削除 例 (1) 1234567890XXXX-1 1234567890XXXX-1 1234567890XXXX-1 ↓ 1234567890XXXX-1 (2) 123ABCDE901234-2 123ABCDE901234-2 ↓ 123ABCDE901234-2 (3) 12345678901234-1 12345678901234-2 ↓ 12345678901234-2 ABC45678901234-1 ABC45678901234-2 ABC45678901234-1 ABC45678901234-2 ↓ ABC45678901234-2 手作業では5時間かかりましたがミスだらけです。 まだ数ファイル残っており手作業では厳しいのでマクロを 作成したいのですが、どう記述していのかまったく検討が付きません。 どうかよろしくお願いします。

  • 配列のソートについて

    配列をソートした時、もともとデータのあった配列番号を記憶しておきたいのですが いい方法はないでしょうか (31,55,84,20,96,14); //1 2 3 4 5 6 ↓ (14,20,31,55,84,96) //6 4 1 2 3 5    ※ソート前の配列番号 いくつかの行(配列A)の、違う列にあるデータを抜き出して配列Bにまとめた後、配列Bをソート その後、配列Bのもともとの順番の位置の行にあるデータを上からコピーしていく感じで行ごとのソートを考えています イメージはこんな感じです a[0]=[1,512,200]; a[1]=[3,100,1]; a[2]=[4,100,265]; a[3]=[8,300,1]; //ソート対象を抜き出す b[0]=a[0][1]; b[1]=a[1][2]; b[2]=a[2][0]; b[3]=a[3][1]; b.sort(); c[0]=a[b[0]のソート前の配列番号]; c[1]=a[b[1]のソート前の配列番号]; c[2]=a[b[2]のソート前の配列番号]; c[3]=a[b[3]のソート前の配列番号];

  • 配列のキーに配列を使う場合

    初歩的な事なのかもしれないのですが、 $abc = $a["$b["c"]"]; のように配列のキーに配列を使いたいのですが、上記だとエラーが出ます。 どのように記述すればよいでしょうか?

    • ベストアンサー
    • PHP
  • アプリ起動時にダイアログも開くには?

    <環境> WIN98 VC++6.0 MFC SDIにて アプリ起動時に、SDIは非表示にしているおり、さらに同時にダイアログも非表示で開きたいのですが、ダイアログのコードはどこに書けばよいのでしょうか?

  • 配列の並び替え

    下のように5つの配列がA~E列まであって、2、3行目にデータが入っています。このときに、2行目の値が3行目の値より小さい配列で、かつ、2行目の値が小さい順に並べる。その後に、3行目より、2行目の値の方が大きい配列を3行目の値が大きい順に並べるマクロコードを教えてください。   A B C D E←列      1  1 2 3 4 5←配列番号 2  4 9 8 6 2 3  1 5 7 10 3      ↑ 行    ↓     A B C D E 1  5 4 3 2 1 2  2 6 8 9 4 3  3 10 7 5 1

  • EXCEL VBA:文字列のコピー

    1. intputbox で入力したパスにある全ての txtファイル名を sheet1 C列に表示。 (現在 6ファイルでテスト。予定作業で100ファイル程度) 2. 配列を使って C列のファイル名のファイルを順番に読み込み sheet2 A列に行単位で読み込み。 →今ココ 3. sheet2 A列に表示されたファイルに hostname_abcde という行があり、abcde 部分だけを sheet1 A列にコピー。 ( _ は半角スペースに読み替えてください。hostname_を検索すればいいのですが、その後に 続く abcde がファイルによって文字数が異なりコピーする方法が分かりません) 4. 「3.」のコピー後に sheet2全セルをクリアして 動的配列の next文へ進み、要素2 のテキスト ファイルを sheet2 A列に読み込みまた、 hostname_abcde の abcde を sheet1 A列の次のセルに コピー。要素数分繰り返します。 実際に記述した内容は職場のPCでないと分からないので詳しく書けませんが、上記 3. と 4. の 方法をご教示頂きたくお願い致します。

  • スカラーを配列に変換

    $abc = <<END_OF_MESSAGE; A B C END_OF_MESSAGE; これをそのまま @abc = (A, B, C) という配列にして使いたいのですが、どうすればいいのでしょうか?

    • ベストアンサー
    • Perl
  • 配列の使い方について

    二つ教えてください。 1.二次元配列で例えばファイルの一行目をグループ[1]に、二行目はグループ[2]に、三行目はグループ[1]に、四行目はグループ[3]に、みたいな感じでファイルの値を任意のグループ[n]に代入していきグループ分けする方法を教えてください。 2.上のような方法で作った配列を例えばグループ[2]にグループ[5]の要素をすべてつけたし、グループ[5]は削除する方法を教えてください。

専門家に質問してみよう