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

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

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

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

Cygwin

Cygwinは、Unixのような環境を、Windows上で構築させるコマンドラインインターフェースです。

標準入力

標準入力(stdin)は、プログラムが標準的に用いるデータ入力元。リダイレクトしない限り、プログラムを起動した端末のキーボードが標準入力になります。UNIX系OSやC言語に実装されて普及した概念ですが、他のOSや言語も含めた総称としても使われます。

Q&A

解決済

5回答

3029閲覧

c言語で、「英文中に現れる単語とその出現回数を表示させるプログラム」の作成に困っています。

nk-kong

総合スコア4

C

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

Cygwin

Cygwinは、Unixのような環境を、Windows上で構築させるコマンドラインインターフェースです。

標準入力

標準入力(stdin)は、プログラムが標準的に用いるデータ入力元。リダイレクトしない限り、プログラムを起動した端末のキーボードが標準入力になります。UNIX系OSやC言語に実装されて普及した概念ですが、他のOSや言語も含めた総称としても使われます。

0グッド

1クリップ

投稿2020/07/07 04:05

前提・実現したいこと

c言語の問題です。「標準入力に与えられた文章の単語とその出現回数を出力せよ」という課題が解けなくて困っています。
例えば、標準入力で「this is a pen that is a pineapple」と入力されたら、
1 this
2 is
2 a
1 pen
1 that
1 pineapple
と出力される感じです。

ファイル名はword_histogram.cで、ターミナルはCygwin64を使っています。

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

$ ./word_histogram this is a pen that is a pineapple test.sh: 23 行: 2011 終了 cat $i.in 2012 Segmentation fault (コアダンプ) | ../$cmd $args > $i.out 2>&1 ==== 期待される出力 (Correct output) ==== 1 this 2 is 2 a 1 pen 1 that 1 pineapple ==== 出力の違い (Different lines) ==== --- 1.correct 2020-06-30 22:02:09.080436000 +0900 +++ 1.out 2020-07-07 12:46:38.603230400 +0900 @@ -1,6 +0,0 @@ -1 this -2 is -2 a -1 pen -1 that -1 pineapple ================ テスト 1 失敗(failed) テスト 1 に失敗しました. (A test case is failed) プログラムを確認してください.(0)

該当のソースコード

c

1#include<stdio.h> 2#include<stdlib.h> 3#include<ctype.h> 4#include<string.h> 5#define NUM_WORDS 20000 6 7int main(){ 8 9 char w[30+1]; 10 char *word[NUM_WORDS]; 11 int count[NUM_WORDS]; 12 13 word[NUM_WORDS] = (char *)malloc(sizeof(char) * (strlen(w) + 1)); 14 if(word[NUM_WORDS] == NULL){ 15 fprintf(stderr, "Cannot allocate memory.\n"); 16 return 1; 17 } 18 19 int total = 0, i = 0, find = 0; 20 21 while(scanf("%30s", w) != EOF){ 22 23 tolower(w[strlen(w)]); 24 25 find = -1; 26 for(i=0;i<total;i++){ 27 if(strcmp(*word[i],w)==0){ 28 find=i; 29 } 30 } 31 32 if(find<0){ 33 strcpy(*word[total],w); 34 count[total] = 1; 35 total++; 36 } 37 else{ 38 count[find]++; 39 } 40 41 } 42 43 for(i=0;i<total;i++){ 44 printf("%d\t%s\n", count[i], *word[i]); 45 } 46 47 free(word[NUM_WORDS]); 48 return 0; 49 50}

###補足説明
・コンパイルはgcc -o word_histogram word_histogram.c
・実行は./word_histogram
・make testというコマンドで「すべてのテストに成功しました」と表示されれば、テスト成功。

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

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

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

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

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

guest

回答5

0

ポインタや配列に関する基礎勉強がまだまだ必要ですね。
以下はどれも不当なメモリアクセスとなります。

word[NUM_WORDS] = (char *)malloc(sizeof(char) * (strlen(w) + 1));

tolower(w[strlen(w)]);
if(strcmp(*word[i],w)==0){
strcpy(*word[total],w);
printf("%d\t%s\n", count[i], *word[i]);

他にも、

  • 単語の大文字小文字は区別するのか? (This と thisなど)

コードを読む限り、全て小文字扱いとするようですが、、、

各センテンスで「何をしたいのか」をコメント書きしましょう。
正しく動かなくても、やりたいことは(コメントで)書ける筈です。

投稿2020/07/07 05:00

編集2020/07/07 06:22
DreamTheater

総合スコア1095

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

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

Daregada

2020/07/07 06:00

> また、現在のコードには、入力された文字列を単語単位に分割する処理がないようです。 scanf が担当しています。
DreamTheater

2020/07/07 06:21 編集

this is a pen that is a pineapple これをどうやってscanfが分割するのですか? ・・・あっ! 空白がセパレータでしたね。失礼しました。
nk-kong

2020/07/07 15:26

回答ありがとうございます。 プログラミングを始めてまだ間もないので、まだまだ至らない点がございました。 ご指摘いただいた箇所を、今後意識して取り組みたいと思います。
guest

0

元のソースをまるっと無視して書いたやつ。

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <ctype.h> 5 6typedef struct { 7 int count; 8 char *word; 9} WordWithCount; 10 11typedef struct { 12 int length; 13 int nextIndex; 14 WordWithCount *list; 15} WordWithCountList; 16 17void init(WordWithCountList *words, int initSize); 18int indexOf(WordWithCountList *list, char *token); 19void add(WordWithCountList *words, char *token); 20char *strlower(char *src); 21 22const char *delimiters = " .,?!:;(){}[]\n"; 23 24int main(void) 25{ 26 WordWithCountList words; 27 28 init(&words, 16); 29 30 char line[1000]; 31 fgets(line, sizeof(line), stdin); 32 33 for (char *token = strtok(line, delimiters); token != NULL; token = strtok(NULL, delimiters)) { 34 int foundIndex = indexOf(&words, token); 35 if (foundIndex >= 0) { 36 words.list[foundIndex].count++; 37 } else { 38 add(&words, token); 39 } 40 } 41 42 for (int i = 0; i < words.nextIndex; i++) { 43 printf("%d %s\n", words.list[i].count, words.list[i].word); 44 } 45 46 return 0; 47} 48 49void init(WordWithCountList *words, int initSize) 50{ 51 words->nextIndex = 0; 52 words->length = initSize > 0 ? initSize : 1; 53 words->list = malloc(words->length * sizeof(WordWithCount)); 54 55 if (words->list == NULL) { 56 fprintf(stderr, "words.list allocation (size: %d) is failed.\n", words->length); 57 exit(1); 58 } 59} 60 61int indexOf(WordWithCountList *words, char *token) 62{ 63 for (int i = 0; i < words->nextIndex; i++) { 64 if (strcasecmp(words->list[i].word, token) == 0) { 65 return i; 66 } 67 } 68 return -1; 69} 70 71void add(WordWithCountList *words, char *token) 72{ 73 words->list[words->nextIndex].word = strlower(token); 74 words->list[words->nextIndex].count = 1; 75 words->nextIndex++; 76 77 if (words->nextIndex >= words->length) { 78 words->length *= 2; 79 words->list = realloc(words->list, words->length * sizeof(WordWithCount)); 80 if (words->list == NULL) { 81 fprintf(stderr, "wordList re-allocation (size: %d) is failed.\n", words->length); 82 exit(2); 83 } 84 } 85} 86 87char *strlower(char *src) 88{ 89 char *ptr = src; 90 while (*ptr != '\0') { 91 *ptr = tolower(*ptr); 92 ptr++; 93 } 94 return src; 95}

投稿2020/07/07 18:05

Daregada

総合スコア11990

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

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

0

ベストアンサー

同じ変数を使って書いてみましたが、ちょっと変わった書き方をしているので、
あくまでもこれは参考として、やり方を理解するだけにし、自分自身の書き方で
書き直してみてください。

C

1#include <stdio.h> // scanf, printf, fprintf 2#include <stdlib.h> // malloc, free 3#include <ctype.h> // tolower 4#include <string.h> // strcmp, strcpy 5 6#define NUM_WORDS 20000 7 8int main(void) 9{ 10 char *word[NUM_WORDS], w[30+1]; 11 int count[NUM_WORDS], total = 0, i; 12 13 while (scanf("%30s", w) == 1) { 14 for (i = 0; w[i]; i++) w[i] = tolower((unsigned char)w[i]); 15 for (i = 0; i < total && strcmp(word[i], w); i++) ; 16 if (i == total) { 17 if (i == NUM_WORDS) 18 return fprintf(stderr, "Too many data.\n"), 1; 19 if ((word[total] = malloc(strlen(w) + 1)) == NULL) 20 return fprintf(stderr, "Cannot allocate memory.\n"), 2; 21 strcpy(word[total], w), count[total++] = 1; 22 } 23 else count[i]++; 24 } 25 for (i = 0; i < total; i++) 26 printf("%d\t%s\n", count[i], word[i]), free(word[i]); 27 return 0; 28}

投稿2020/07/07 14:36

kazuma-s

総合スコア8224

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

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

nk-kong

2020/07/07 15:26

回答ありがとうございます。 このコードで実行したところ、うまくいきました。 このコードを参考にして、自分なりにプログラミングしようと思います。
guest

0

とりあえず。

word[NUM_WORDS] = (char *)malloc(sizeof(char) * (strlen(w) + 1));において
配列wordNUM_WORDS番目(の1つの箱)にmallocした結果を代入していますが、意図した動作でしょうか?(おそらく違うと思います)
また、配列wは初期化されておらずゴミ値が入っているのでstrlen(w)は30でもなく31でもなく出鱈目な結果が返ってきます。

またtolower(w[strlen(w)]);についてですが、意味、意図が不明です。
まずはtolowerの引数は何でどんな結果を返すのかリファレンスを読みましょう。

投稿2020/07/07 04:31

編集2020/07/07 04:36
can110

総合スコア38266

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

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

nk-kong

2020/07/07 15:21

回答ありがとうございます。 学校の教授のサンプルコードをそのまま使ったのが原因でした。
guest

0

配列 word の各要素に、配列 w の大きさ分の容量を割り当てないと正常に動きません。
word[NUM_WORDS] = ...って、いきなり配列の領域外にアクセスしています。

投稿2020/07/07 04:31

Daregada

総合スコア11990

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

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

nk-kong

2020/07/07 15:19

回答ありがとうございます。 確かにその通りですね。以後気を付けるようにします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問