• ベストアンサー

構造体を使ったファイルの読み込み

『指定された辞書を配列に読み込み、表記または読みまたは品詞を指定すると、その単語の情報(表記、読み、品詞)を標準出力に出力するプログラムを作成せよ。』 という問題なんですが、 アルゴリズムは 1.単語の個数を数える 2.メモリを確保する 3.辞書を読み込む 4.検索する情報を入力する 5.配列の先頭から順番に、入力された情報が読み、標記にある単語を検索し、出力する。 だと思うんです。 しかし単語数を表示してメモリを確保するところまではできたのですが、辞書の読み込みがうまくいきません。 どこがおかしいのか教えてください。 辞書は 学校,ガッコウ,0010 資格,シカク,0011 のように「表記,読み,品詞」順で カンマで区切られているファイルです。 struct JISYO { char *hyouki,*yomi; int hinsi; }; main(int argc, char *argv[]) { fp = fopen(argv[1],"r"); while(f=fgetc(fp)) { if(f==EOF)break; while(f!=',') { jisyo[count2].hyouki[count3]=f; printf("%d\n",jisyo[count2].hyouki[count3]); count3++; f=fgetc(fp); } jisyo[count2].hyouki[count3]=0; f=fgetc(fp); count3=0; while(f!=',') { f=jisyo[count2].yomi[count3]; count3++; f=fgetc(fp); } jisyo[count2].yomi[count3]=0; count3=0; f=fgetc(fp); fscanf(fp,"%d",&hin); jisyo[count2].hinsi=hin; count2++; } fclose(fp); }

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

  • ベストアンサー
  • rentahero
  • ベストアンサー率53% (182/342)
回答No.5

struct JISYO { char *hyouki,*yomi; int hinsi; }; jisyo=(struct JISYO *)malloc(sizeof(struct JISYO)*count); という構造体の配列の確保は確認しました。 で、肝心のhyoukiとyomiはどこで確保してるんですか。 このままでは、hyoukiとyomiにはゴミが入っていてどこともいえないところのメモリを指しています。間違いなくランタイムエラー(アクセス違反)で落ちます。 したがって、この構造体が問題の方で指定されていたのであれば、一回fread+2回メモリスキャンという形式を想定していたのではないでしょうか。 ということで、擬似コード #include <stdio.h> // printf/fopen/ etc... #include <string.h> // strtok/strcpy/ etc... #include <stdlib.h> // malloc/atoi etc... struct JISYO { char *hyouki; char **yomi; int hinsi; }; main(int argc, char *argv[]) { // 1.辞書ファイルをオープンし、サイズを確認する。 // 1-1.辞書ファイルをバイナリでオープン // 1-2.ファイルの最後にシーク // 1-3.ファイル位置を取得=ファイルサイズ // 2.辞書を全部読み込めるメモリを確保する。*1 // 3.行単位でメモリへ読み込み、単語数をカウントする。 // 3-1.実際には一括読みの方がよい。間違えにくい。 // 4.読み込みが終わったらファイルはさっさとクローズ。 // 3-2.読み込んだメモリをスキャンして(forループ) // 3-3.改行があったらカウントして、'\0'(終端記号)に置き換え。*2 // 5.カウントした行数から、構造体のメモリを確保 // 6.メモリをもう一度スキャンし、以下の処理をする。 // 6-1.辞書のメモリ内から、表記と読みへのポインタを //  struct JISYOにセットしていく。その際、カンマを //  '\0'に置き換えることで文字終端をセットする。 //  行末が'\0'で終わっているわけなので、strtokで分割 //  してもよい。*3 // 6-2.表記と読みへのポインタを取得したら次は品詞が //  文字列で入っているので、数値にする。 // 6-3.くりかえす // 7.検索する情報を読み込む // 8.配列をチェックし、該当の単語があれば出力する。 } *1 ココでは、実は+1バイトして、そこには'\0'をしておいたほうが後々便利。詳細は「C言語 文字列 番兵」でweb検索。 *2 ファイル末尾が'\n'で終わっていることは必要条件です。 *3 というか、strtokの元の文字列を'\0'で分割するという特性から、ここではお勧め。実際のところ、strtokはもともとはコマンドラインをargv(charポインタ配列)に指定するために作られた関数なので、こういう使い方が想定どおりの使い方。

すると、全ての回答が全文表示されます。

その他の回答 (4)

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.4

問題は >struct JISYO { >char *hyouki,*yomi; >int hinsi; >}; と、 >jisyo[count2].hyouki[count3]=f; とかですね。 jisyo[count2]で、count2が1の場合、確保したメモリの何バイト目を指定していると思っていますか? 1行目の文字列を格納したあとを指していると考えているかと思いますが。 が、実際には先頭から12バイト後ろを(32bitOSの場合)指しています。 char*4バイト*2、intで4バイトです。sizeofで確認可能です。 で、 >f=jisyo[count2].yomi[count3]; これは読みを格納するつもりなんですから jisyo[count2].yomi[count3] = f; ですよね(^^;;という前提で。 もう気づいたかもしれませんが、 jisyo[count2].yomi[count3]で、count2=0、count3=1のときは、先頭から4バイト目を指しています。つまり、せっかく格納したhyoukiが3バイト以上あったら上書きしちゃってますよね。 といったことが問題になります。あくまでもchar*はアドレスを指すものであって、実体を指すものではありません。 こういった場合なのですが、まず、ファイルの内容をすべて読み込んでバッファに書き込んでしまいます。 で、その読み込んだバッファの中の、どの場所に目的の文字列の先頭があるか?という情報を別の領域を準備し、格納していくのがいいと思います。 もちろん他にも方法は考えられますが。 順序としては、 1.ファイルサイズと、単語の数を調べる。 単語の数は、改行の数でわかりますよね。 #最後の行が改行で終わってるかは確認でいてくださいね。 2.ファイルサイズ分のバッファを確保 3.辞書の管理をする構造体(struct JISYO)のサイズ*単語の数のサイズのメモリを確保 あとは、カンマと改行の位置をファイル内容のバッファを前から調べていき、辞書の構造体の配列に、それぞれの文字列の先頭アドレスを構造体のメンバに格納していってください。 改行、カンマの領域に'\0'を入れていくのを忘れずに。

すると、全ての回答が全文表示されます。
  • rentahero
  • ベストアンサー率53% (182/342)
回答No.3

まさかとはおもいますが、fseekかまたはrewindでファイルポインタを戻してないからうまくいってないとかそういうことではないでしょうね? それなら、先の回答は無視してください。

すると、全ての回答が全文表示されます。
  • rentahero
  • ベストアンサー率53% (182/342)
回答No.2

あなたの期待している構造体の形式では、多分期待した動作はできないでしょう。 なぜなら、単語のサイズをどうするのか、余った領域は無駄ではないのか、ということを考えると、以下のようなアルゴリズムを検討してみてください。 1.辞書ファイルをオープンし、サイズを確認する。 2.辞書を全部読み込めるメモリを確保する。 3.行単位でメモリへ読み込み、単語数をカウントする。 4.ファイルをクローズする 5.単語数分のstruct JISYOの配列を確保する。 6.メモリをスキャンし、以下の処理をする。 6-1.辞書のメモリ内から、表記と読みへのポインタをstruct JISYOにセットしていく。その際、カンマを0に置き換えることで文字終端をセットする。 6-2.品詞をstruct JISYOにintにして保存する。 6-3.くりかえす。 7.検索する情報を読み込む 8.配列をチェックし、該当の単語があれば出力する。

すると、全ての回答が全文表示されます。
  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.1

まず、コンパイルが通るソースを載せてください。 変数の宣言がぜんぜんありません。 >しかし単語数を表示してメモリを確保するところまではできたのですが、辞書の読み込みがうまくいきません。 動的にメモリ確保してるところが無いんですけど。どこですか?

inuiman
質問者

補足

申し訳ありません。字数制限のため『単語の個数,メモリの確保』を省いたんですが一緒に変数の宣言まで消してしまいました。 以下が『単語の個数を数え,メモリを確保』までのソースです。 struct JISYO { char *hyouki,*yomi; int hinsi; }; main(int argc, char *argv[]) { int c,count=0,count2=0,count3=0,hin=0; char f; FILE *fp; struct JISYO *jisyo; fp = fopen(argv[1],"r"); while(c=fgetc(fp)) { if(c==EOF)break; if(c=='\n')count++; } fclose(fp); printf("tangosuu = %d",count); jisyo=(struct JISYO *)malloc(sizeof(struct JISYO)*count); }

すると、全ての回答が全文表示されます。

関連するQ&A