- ベストアンサー
C言語について教えてください
ファイルの文を読み込み、I、Weなどの定めた単語の数を数えるプログラムを作りたいのですが、うまくいきません。 具体的な問題点は、単語の数を数える際、一致する単語があった場合、再び最初から文を見直すため、無限ループしてしまう。 We,WE、weなど大文字小文字の違いで単語が数えられないなどです。 #include <stdio.h> #include <stdlib.h> #include <string.h> int main( void ) { char filename[FILENAME_MAX]; int j=0; int k=0; int l=0; int m=0; int n=0; int o=0; int w; char str[50]; FILE *fp; gets(filename); fp = fopen(filename,"r"); { if(fp==NULL) { printf("ERROR"); return -1; } } fscanf(fp,"%50s",str); for(w=0;w<=j+k+l+m+n+o;w++) { if(strcmp("I",str)==0) { j++; } if(strcmp("We",str)==0) { k++; } if(strcmp("You",str)==0) { l++; } if(strcmp("He",str)==0) { m++; } if(strcmp("She",str)==0) { n++; } if(strcmp("They",str)==0) { o++; } } printf("I: %d\n",j); printf("We: %d\n",k); printf("You: %d\n",l); printf("He: %d\n",m); printf("She: %d\n",n); printf("They: %d",o); fclose(fp); return 0; }
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
改良してみました。 詳細はソースを参照してください ============= ソースはここから ==================================== // WordCount.cpp : コンソール アプリケーションのエントリ ポイントを定義します。 // #include "stdafx.h" #include <ctype.h> // "単語"の最大長を定義します // (終端は含まれません) #define MAX_WORD_LEGTH 50 // 単語とその数を組にして考えます // そのために構造体を定義します // // 検査したい単語は決まっているので // あらかじめテーブルに格納しておきます // 大文字小文字を区別しないで比較するため、小文字ベースとします struct WORD_REC { char s[MAX_WORD_LEGTH + 1]; // 文字列 int Count; }WordTbl[] = {{"i", 0}, {"we", 0}, {"you", 0}, {"he", 0}, {"she", 0}}; // 文字列を小文字ベースに変換します // Bufferはstrの長さ + 1以上確保されていることが必要です static void MakeLower(char* str, char* Buffer) { int i; int n = strlen(str); for (i = 0; i < n; ++i) { Buffer[i] = tolower(str[i]); } Buffer[n] = '\0'; } // 文字列をテーブルから探し、そのインデックスを戻します // 見つからない場合は-1を戻します static int FindWord(char* str) { int i; char s[MAX_WORD_LEGTH + 1]; // 小文字に変換した文字列格納用 // 大文字・小文字を区別しないので // 小文字ベースに変更します MakeLower(str, s); for (i = 0; i < sizeof (WordTbl) / sizeof (WordTbl[0]); ++i) { // 文字列を照合します if (strncmp(s, WordTbl[i].s, MAX_WORD_LEGTH) == 0) { // 文字列が見つかりました return i; } } // 文字列が見つかりません return -1; } int main(int argc, char* argv[]) { char filename[FILENAME_MAX]; FILE *fp; char s[MAX_WORD_LEGTH + 1]; int i; gets(filename); fp = fopen("test.txt", "r"); if (fp == NULL) { printf("ERROR"); return -1; } // ファイルの終端に達するとfscanf() がEOFを戻します while (fscanf(fp,"%50s", s) != EOF ) { int i; // テーブル内と照合します i = FindWord(s); if (i >= 0) { // 文字列が見つかった場合 // iはテーブルのインデックスです WordTbl[i].Count++; // カウントアップ } } fclose(fp); // 表示を行います for (i = 0; i < sizeof (WordTbl) / sizeof (WordTbl[0]); ++i) { printf("%s: %d\n", WordTbl[i].s, WordTbl[i].Count); } return 0; } ==== ソースはここまで ========================================= #define MAX_WORD_LEGTH 50 としている割には while (fscanf(fp,"%50s", s) != EOF ) となっていて不十分です ご愛嬌ということで... 参考になれば幸いです。
その他の回答 (3)
- BLK314
- ベストアンサー率55% (84/152)
オッと、バグを発見です(笑) Theyが表示されないです。 この修正は質問者様への課題としておきましょう。 難しいものじゃないので.. それでは
- D-Matsu
- ベストアンサー率45% (1080/2394)
カウンタも一つ二つならi,j等である程度大丈夫ですが、それ以上多い場合はわけがわからなくなるのでちゃんと役割に応じた名前にしておいた方がいいですね。 この場合は単語名でもそのまま名前にしといた方がいいでしょう。 あとgets()は簡単にバッファオーバーフローできてしまうので使わない方がいいです。fgets(filename, FILENAME_MAX, stdin)に置き換えておきましょう。 ところで入力ファイルの中身と期待する出力を出していただけませんか? それによっておそらく回答の方向が変わってくるので。 > #1 tolower()でもいいんですが、一応stricmp()とかstrcasecmp()とか言ったケース無視比較関数もあります。 #コンパイラによってどれが実装されてるかが変わるのでtolower()を使った方が簡単で確実なんですが。
- junkUser
- ベストアンサー率56% (218/384)
ええと、・・・ fscanf(fp,"%50s",str); が for の外にあるので、str の値が永久に変わりません。 つまり、"I"が見つかったら、j++ なので永久に w<=j+k+l+m+n+o になりますね。 >We,WE、weなど大文字小文字の違いで単語が数えられない そんなあなたに ctype.h の tolower がありますよ。 文字をすべて小文字に直してしまえば、We の場合は we で一致します。