質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

2回答

1164閲覧

C言語に関する質問でした

SUNMOON_14

総合スコア20

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2020/10/14 15:38

編集2020/10/15 05:18

前提・実現したいこと

C言語

発生している問題・エラーメッセージ

問題点1

問題点2

試したこと

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

  • fgets改行\nも含めて読み込むため、キーワードとして入力する文字列末尾には、Enterキーによる改行が付いている。これを取り除かなければ、(比較対象の単語には改行は付いていないので)すべての比較が一致しない。
  • fgetsの第2引数に、格納先の配列の要素数+1を指定してはいけない。配列の全要素に文字データが格納される状況で、自動的に付加されるヌル文字\0が配列の範囲を超えて書き込まれるsizeofを利用して、配列の要素数を指定すべきだ。
  • ファイルから読み込んだ文字列から単語を切り出す際、単語の長さが0であっても総単語数のカウンターを1増やしている。改行を含む文字列で総単語数が1増えてしまうのはこれが原因だ。カウンターの処理の前に、単語の長さを調べれば対処できる。
  • fopenに失敗したら、ファイル処理を続けてはいけない。
  • 配列名をそのまま使えばいい状況で、意味もなくポインター変数を使うのはやめようp_word, p_key, bufは、今回のコードではすべて不要だ。
  • if文で単語を構成する文字かどうかをチェックするさい、isalnumを使ったチェックを二重に行なっている。一度目のチェックが成立しないなら、単語を構成しない文字であることは自明なので、チェックは一度でいい。つまり、if (alnum(...)) {...} else {...}の形で書ける。
  • 文字列のクリアに配列の全要素を0クリアする必要はなく、先頭要素にヌル文字\0を設定するだけでいい。ヌル文字\0より後ろは文字列処理に使われないからだ。

C

1#include <ctype.h> 2#include <stdio.h> 3#include <string.h> 4#define SIZE 5000 5 6int main(void) 7{ 8 int target_count = 0; 9 int all_count = 0; 10 11 char keyword[32]; 12 printf("Input a word for search and count: "); 13 fgets(keyword, sizeof(keyword), stdin); 14 // 入力文字列の末尾に改行があれば、それを取り除く 15 char *last = keyword + strlen(keyword) - 1; 16 if (last >= keyword && *last == '\n') { 17 *last = '\0'; 18 } 19 printf("Input keyword is '%s'\n", keyword); 20 21 FILE *fp; 22 char text[SIZE]; 23 fp = fopen("test.txt", "r"); 24 if (fp == NULL) { 25 printf("cannot open\n"); 26 return 1; 27 } 28 29 char current_word[32]; 30 int j = 0; 31 while (fgets(text, sizeof(text), fp) != NULL) { 32 for (int i = 0; text[i] != '\0'; i++) { 33 if (isalnum(text[i])) { 34 current_word[j] = text[i]; 35 j++; 36 } else { 37 current_word[j] = '\0'; 38 if (j == 0) { 39 continue; 40 } 41 all_count++; 42 printf("current word is '%s'\n", current_word); 43 if (strcasecmp(keyword, current_word) == 0) { 44 target_count++; 45 } 46 current_word[0] = '\0'; 47 j = 0; 48 } 49 } 50 } 51 fclose(fp); 52 53 printf("全単語数: %d\n", all_count); 54 printf("単語数: %d\n", target_count); 55}

投稿2020/10/14 16:59

編集2020/10/14 17:00
Daregada

総合スコア11990

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Daregada

2020/10/14 17:01

かぶった。そしてだいたい同じ指摘をしている。
guest

0

fgets で読み込むと '\n' を含むので次のようにして削除してください。

diff

1 printf("Input a word for search and count: "); 2 fgets(p_key, 32+1, stdin); 3+ char *p = strchr(p_key, '\n'); 4+ if (p != NULL) *p = '\0'; 5 printf("Input key = %s\n", p_key);

それから、fgets の第2引数で、32+1 とか size+1 のように 1足していますが、
これはいけません。実際に存在する配列の要素数にしてください。

fopen に失敗した場合でも、メッセージを出すだけで次に進み fgets を
実行するのは変です。return 1; などで、main を終了してください。

単語数が実際より増えるのは、行頭にスペースがあったり、単語間のスペースが
2個以上ある場合です。もう少しよく考えてみてください。

ポインタ p_key や p_word は、配列 key や word の先頭を指している
だけで一度も変更していません。
p_key や p_word を使用せず、key や word と書けばいいでしょう。
buf も不要です。text で十分です。

追記
解決済みなったので別解です。

C

1#include <stdio.h> // printf, fgets, fopen, fclose, fscanf, perror 2#include <string.h> // strchr, strcasecmp 3 4int main(void) 5{ 6 int cnt = 0, all = 0, *p; 7 char key[100], word[100]; 8 9 FILE *fp = fopen("test.txt","r"); 10 if (fp == NULL) { perror("test.txt"); return 1; } 11 12 printf("Input a word for search and count: "); 13 if (!fgets(key, sizeof key, stdin)) return 2; 14 if (p = strchr(key, '\n')) *p = '\0'; 15 printf("Input key = %s\n", key); 16 17 while (1) { 18 fscanf(fp, "%*[^a-zA-Z0-9]"); // 英数字以外を読み飛ばす 19 if (fscanf(fp, "%99[a-zA-Z0-9]", word) != 1) break; // 単語を取得 20 all++; 21 if (!strcasecmp(key, word)) cnt++; 22 } 23 fclose(fp); 24 25 printf("全単語数:%d\n", all); 26 printf("単語数:%d\n", cnt); 27}

投稿2020/10/14 16:31

編集2020/10/15 05:31
kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問