プロが教える店舗&オフィスのセキュリティ対策術

 ファイルからデータを読み込んで、単語の出現頻度を調べるプログラムを作ろうと考えて、下記のようなプログラムを書いてみました。

#include <stdio.h>
#include <string.h>

main()
{ struct data
{char word[128];
int freq;}
word_data[128];
char words[128];
char term[128];
int i=0;
int nw=0;
int j;
char buff[128];
FILE *fp_in=fopen("data.txt","r");

while(fgets(fp_in,128,buff)!=EOF){
char buff[128];
int k;
for(k=0;k<=128;k++){
printf("%s",buff);
if(('A'<=buff[k] && buff[k]<='Z')||('a'<=buff[k] && buff[k]<='z'))
term[i++]=buff[k];
else if(i>0) term[i]='\0';}
for(j=0;j<nw;j++){
if(strcmp(term,word_data[j].word)==0) break;
if(j==nw)
{strcpy(word_data[j].word,term);
word_data[j].freq=1;
nw++;}
else if(j!=nw)
{word_data[j].freq++;
i=0;}
}}
for(j=0;j<nw;j++)
printf("%s %d",word_data[j].word,word_date[j].freq);
return 0;}

コンパイルは通ったのですが、実行しても画面に何も表示されません。原因は何処にあるのでしょうか?分かる方がいましたら、ご回答宜しくお願いします。

A 回答 (7件)

各行に複数単語がある場合にも対応してみました。


一部エラーチェックのコードも追加しました。

-------------------------------------------------

#include <stdio.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
#define MAX_NWORDS 128

int isLetter(char c){
  if( ('A'<=c && c<='Z') ||('a'<=c && c<='z') ) {
    return TRUE;
  }else{
    return FALSE;
  }
}

main() {
  struct data {
    char word[128];
    int freq;
  } word_data[MAX_NWORDS];
  char term[128];
  int nw=0;
  int i,j,k;
  char buff[128];
  FILE *fp_in=fopen("data.txt","r");

  while(fgets(buff,128,fp_in)!=NULL){
    k=0;
    while(buff[k]!='\n'){
      while(! isLetter(buff[k]) && buff[k]!='\n') k++;
      if(buff[k]=='\n')break;

      i=0;
      while(isLetter(buff[k])) term[i++]=buff[k++];
      term[i]='\0';

      for(j=0;j<nw;j++) if(strcmp(term,word_data[j].word)==0) break;
      if(j==nw) {
        strcpy(word_data[j].word,term);
        word_data[j].freq=1;
        nw++;
        if(nw==MAX_NWORDS){
          printf("more than %d words found.\n", MAX_NWORDS);
          exit(1);
        }
      } else {
        word_data[j].freq++;
      }
    }
  }
  for(j=0;j<nw;j++) printf("%s %d\n",word_data[j].word,word_data[j].freq);
  return 0;
}

この回答への補足

丁寧にありがとうございます。
 もう1点質問させていただきたいのですが、最終結果を出力するときに辞書式順序(A,a,B,b,・・,Z,z)にソートする場合はどうすればいいのでしょうか?昨晩自力でやってみたのですが、どうもうまくいきません。アスキーコードの配列を用いる気がするのですが、アスキーコードですと、'A'~'Z'の後に、'a'~'z'が続きますよね。これをそのまま用いると、大文字が先にまとめて表示されてしまい、小文字が後にまとめて表示されてしまいますよね。
また、'A'='a'-32ですので、一旦、全ての小文字を大文字に変換して、大小比較をし、また元に戻すといった手段も考えてみたのですが、私にはソースコードが書けませんでした。
 宜しければ、ご回答お願いできますでしょうか?
 以下に私が書いてみたソースコードを挙げておきます。
 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define MAX_NWORDS 128

int isLetter(char c){
if(('A'<=c && c<='Z')||('a'<=c && c<='z')){
return TRUE;
}else{
return FALSE;
}
}
main(){

struct data{
char word[128];
int freq;
};

struct data word_data[MAX_NWORDS];
struct data word_data_cp[MAX_NWORDS];

char term[128];
int nw=0;
int i,j,k,p,x;
char m;
char buff[128];
FILE *fp_in=fopen("data.txt","r");

while(fgets(buff,128,fp_in)!=NULL){

k=0;
while(buff[k]!='\n'){
while(!isLetter(buff[k]) && buff[k]!='\n') k++;
if(buff[k]=='\n')break;

i=0;
while(isLetter(buff[k])) term[i++]=buff[k++];
term[i]='\0';

for(j=0;j<nw;j++)
if(strcmp(term,word_data[j].word)==0) break;
if(j==nw){
strcpy(word_data[j].word,term);
word_data[j].freq=1;
nw++;
if(nw==MAX_NWORDS){
printf(" more than %d words found.\n",MAX_NWORDS);
exit(1);
}
}else{
word_data[j].freq++;
}}}


for(p=0;p<nw;p++){
for(j=0;j<nw-p-1;j++){
x=strcmp(word_data[j].word,word_data[j+1].word);
if(x>0){
word_data_cp[j]=word_data[j];
word_data[j]=word_data[j+1];
word_data[j+1]=word_data_cp[j];}
}}

for(j=0;j<nw;j++)
{printf("%s %d\n",word_data[j].word,word_data[j].freq);}
printf("Total %d Words\n",nw);
return 0;
}

補足日時:2004/01/22 17:15
    • good
    • 0

修正版。

動作確認ずみ。
strcmpを使っている部分は2箇所ありますが、
たぶん、2箇所めのstrcmpのみをこのstrcmp_dictorderに変更するのがよいと思います。
(大文字、小文字の違いによって意味が違う単語もありますので。)

int strcmp_dictorder(char*a,char*b){
int i;
char ca,cb;

for(i=0;i<=strlen(a);i++){
ca=a[i];if(ca>='a')ca-=32 ;
cb=b[i];if(cb>='a')cb-=32 ;
if(ca!=cb) return ca-cb;
}
for(i=0;i<=strlen(a);i++){
if (a[i]!=b[i]) return a[i]-b[i];
}
return 0;
}
    • good
    • 0
この回答へのお礼

何度も丁寧にありがとうございます。
先ほど、実行してみましたところ、小文字の後に大文字が続く個所が数箇所あったのですが、
最初のforループに
if(ca==cb-32) return 0;
if(ca-32==cb) return 1;
の2文を追加してみましたところ大文字→小文字の順番に上手く並びました。
 文字列の比較では、strcmp関数を使うといったことしか
思い浮かばなかったので悩んでいたのですが、自分で関数を作ってしまえばいいのですね。また、教えて頂いた大文字と小文字を無視した大小関係の比較の書き方はなるほどと思いました。
 お忙しいところ、丁寧に回答していただきまして本当にありがとうございました。これからも何か機会がありましたらよろしくお願いします。

お礼日時:2004/01/24 03:04

以下のような関数を定義して、strcmpの代わりにつかってみてください。

返り値の符号は逆のほうがいいかもしれません。結果を見て適当に直してください。
動作確認はしていません。
下の関数のa[i]でエラーがでるようなら、
a[i]を*(a+i)に変えてみてください。

int strcmp_dictorder(char*a,char*b){
int i;
char ca,cb;

for(i=0;i<=strlen(a);;i++){
ca=a[i];if(ca>='a')ca-=32
cb=b[i];if(cb>='a')cb-=32
if(ca<cb)return -1;
else if (ca>cb)return 1;
else if (a[i]<b[i])return -1;
else if (a[i]>b[i])return 1;
else ;/*compare next letter*/
}
return 0;
}
    • good
    • 0

No3までを踏まえて動作するように書き換えてみました。

制御構造も一部かえました。回答No2に示したようなdata.txtに対して動作確認ずみです。

-------------------------------------------------
#include <stdio.h>
#include <string.h>

main() {
  struct data {
    char word[128];
    int freq;
  } word_data[128];
  char term[128];
  int i;
  int nw=0;
  int j;
  char buff[128];
  FILE *fp_in=fopen("data.txt","r");
 
  while(fgets(buff,128,fp_in)!=NULL){
    int k;
 
    i=0;
    for(k=0;k<=128;k++){
      if( ('A'<=buff[k] && buff[k]<='Z')||('a'<=buff[k] && buff[k]<='z') ) {
        term[i++]=buff[k];
      } else {
        break;
      }
    }
    if(i>0){
      term[i]='\0';
      for(j=0;j<nw;j++) if(strcmp(term,word_data[j].word)==0) break;
      if(j==nw) {
        strcpy(word_data[j].word,term);
        word_data[j].freq=1;
        nw++;
      } else {
        word_data[j].freq++;
      }
    }
  }
  for(j=0;j<nw;j++) printf("%s %d\n",word_data[j].word,word_data[j].freq);
  return 0;
}
-------------------------------------------------
注意:上記ソースコードは、行頭に全角スペースが入っているため、そのままコピーペーストしてもコンパイルできないことがあります。
    • good
    • 0

・char buffの宣言が2箇所にあります。

そのためファイルから読み込んだ文字列は、while文の内部で使われていません。

・fgetsの書式が違います。
fgets(buff,128,fp_in,128,buff)のはずです。

・fgetsの返すファイル終端をあらわす値はEOFではなくNULLです。

・結果表示部で、word_dat"e"[j]を表示しようとしています。

・結果は、各単語の情報を表示するように改行も出力したほうがよさそうです。

・char words[128]は使われていません。
    • good
    • 0

・各行のはじめの単語しかチェックしない仕様のようですが、それでいいのでしょか?



・行のはじめの1文字がA-Za-zのいずれかでない場合、term[0]の値が不定になります。この状態でstrcmpを実行すると問題がある気がします。

(上の2点は、各行が1単語からなり、その単語は行の1カラム目から始まる、という場合は問題ありませんが...)

・すでに登録した単語と同じ単語を見つけたばあい、iの値を0にリセットせずに次の行を読み込んでいます。次の行の単語は、term中の前回の単語の後ろに連結されます。
(
たとえば、データファイルが

and
and
or

だった場合、orを読み込んだ時点でのtermは、"andor"になります。(他の部分の動作に問題がなかったとしても)
    • good
    • 0

 for(j=0;j<nw;j++){


のループの中に、
 if(j==nw)
という条件式があります。"thenの部分"は実行されません。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!