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

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

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

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

Q&A

4回答

3578閲覧

C言語でリスト構造を用いたワードカウンタを作成したい

Nanora_s

総合スコア10

C

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

0グッド

0クリップ

投稿2019/03/16 06:15

前提・実現したいこと

大学の課題でリスト構造を用いたワードカウンタ(文章を読み込み、単語を一つずつ認識して文章中に何回出てきたかを出力するプログラム)を作成しています。
リスト構造がいまいち良く分からないまま頑張ってプログラムに追加していましたが、segmentation faultが出て手詰まりになってしまいました。
このプログラムをちゃんとした形で動かしたく、ご助力をお願いします。

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

リスト構造を用いたところ、各関数に新たな引数を設定したのでそれをmain関数内の足りないと出てきたところを補ったらsegmentation faultが出ました。 それ以外ですと wordlist.c: In function ‘get_word’: wordlist.c:24:2: warning: null argument where non-null required (argument 2) [-Wnonnull] strcpy(list->word,'\0'); が出ました。

該当のソースコード

C

1# include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4 5FILE *fp; 6char word[1024]; 7 8struct LIST{//単語を登録する構造体 9 char word[1024];//単語 10 int count; 11 struct LIST *next; 12}; 13 14int get_word(struct LIST *list){ 15 char letter;//文章内の単語 16 17 letter = fgetc(fp); 18 while(!(letter == ' ' || letter == EOF || letter == ',' || letter == '.')){ 19 //この条件が成り立たない場合 20 strcpy(word,list->word);//単語をwordリストに入れる 21 list->count ++;//リスト番号を1増やす 22 letter = fgetc(fp);//これ初期化的な奴? 23 } 24 strcpy(list->word,'\0'); 25} 26int list_length = 0; 27 28void count_up(struct LIST *list){ 29 int i; 30 31 for(i =0;i< list_length;i++){//単語数だけ繰り返す 32 if(strcmp(list->word,word)){//もし同じ単語なら 33 list[i].count++;//カウントする 34 return ; 35 } 36 } 37 list[i].count = 1; 38 strcpy(list->word,word); 39 list_length++; 40 return; 41} 42 43void output(struct LIST *list){ 44 int i; 45 for(i = 0;i<list_length;i++){ 46 printf("%s : %d\n",list->word, list[i].count); 47 } 48 return ; 49 50} 51 52 int main(struct LIST *list){ 53 54 int ret; 55 56 fp = fopen("input.txt" , "r"); 57 ret = get_word(list); 58 printf("%s\n",list->word); 59 60 while(ret == 1){ 61 count_up(list); 62 ret = get_word(list); 63 printf("%s\n",list->word); 64 } 65 output(list); 66 return 0; 67} 68

試したこと

とにかくエラーをなくすことに専念したのでエラー表示が出なくなってからは何がおかしいのか確認できないくなってしまいました。

補足情報(FW/ツールのバージョンなど)

使用しているのはvimエディタでコンパイラはgccです。
windows10に標準搭載のLinax(Ubuntu/Bash)環境で作業しています。

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

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

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

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

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

episteme

2019/03/16 07:51

struct LIST の総数は単語数に伴って増加するはずよね? どこで増やして(=mallocして)ます?
guest

回答4

0

誰が書いても似たようになっちゃうかー...

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4 5struct LIST{//単語を登録する構造体 6 char word[1024];//単語 7 int count; 8 struct LIST *next; 9}; 10 11/* fpから1単語を切り出して返す */ 12const char* get_word(FILE* fp) { 13 static char word[256]; 14 int ch; 15 char letter[2]; 16 letter[1] = '\0'; 17 word[0] = '\0'; 18 19 /* 空白文字をskipする */ 20 do { 21 ch = fgetc(fp); 22 if ( ch == EOF ) return NULL; 23 } while( ch == ' ' || ch == ',' || ch == '.' ); 24 25 /* 空白文字までをwordに取り込む */ 26 while ( !(ch == ' ' || ch == ',' || ch == '.' || ch == EOF) ) { 27 letter[0] = ch; 28 strcat(word, letter); 29 ch = fgetc(fp); 30 } 31 return word; 32} 33 34/* list中にwordがあれば当該LISTのcountを+1する。 35 さもなくば新たなLISTを確保し先頭に挿入する 36 */ 37struct LIST* count_up(struct LIST *list, const char* word) { 38 struct LIST* result = list; 39 while ( list != NULL ) { 40 if ( strcmp(list->word,word) == 0 ) {//もし同じ単語なら 41 ++list->count;//カウントして 42 return result; // おしまい 43 } 44 list = list->next; 45 } 46 // 新たなLISTを(先頭に)追加する 47 list = result; 48 result = (struct LIST*)malloc(sizeof(struct LIST)); 49 strcpy(result->word,word); 50 result->count = 1; 51 result->next = list; 52 return result; 53} 54 55void output(const struct LIST *list){ 56 while ( list != NULL ) { 57 printf("%s : %d\n",list->word, list->count); 58 list = list->next; 59 } 60} 61 62int main() { 63 struct LIST* list = NULL; 64 const char* word; 65 FILE* fp = fopen("input.txt" , "r"); 66 67 while ( (word = get_word(fp)) != NULL ) { 68 list = count_up(list, word); 69 } 70 fclose(fp); 71 72 output(list); 73 74 // listの各要素を廃棄する 75 while ( list != NULL ) { 76 struct LIST* next = list->next; 77 free(list); 78 list = next; 79 } 80 return 0; 81}

投稿2019/03/16 14:15

episteme

総合スコア16614

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

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

jimbe

2019/03/16 15:45

あぁ, fclose 入れたのに free 忘れてました ><
guest

0

こういうことかと思うのですが. あっているでしょうか.

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4 5struct LIST{ 6 char word[1024]; 7 int count; 8 struct LIST *next; 9}; 10 11int get_word(FILE *fp, char *word) { 12 int i, v; 13 14 i = 0; 15 while(1) { 16 v = fgetc(fp); 17 if(v == -1) break; 18 if(v == ' ' || v == ',' || v == '.' || v == '\r' || v == '\n') { 19 if(i == 0) continue; 20 break; 21 } 22 word[i] = (char)(v & 0xff); 23 i++; 24 } 25 word[i] = '\0'; 26 return i; 27} 28 29 30struct LIST *create_item(char *word, struct LIST *next) { 31 struct LIST *list; 32 list = (struct LIST *)malloc(sizeof(struct LIST)); 33 strcpy(list->word, word); 34 list->count = 1; 35 list->next = next; 36 return list; 37} 38 39struct LIST *count_up(struct LIST *root, char *word) { 40 struct LIST *list; 41 42 for(list = root; list != NULL; list = list->next) { 43 if(strcmp(list->word, word) == 0) { 44 list->count ++; 45 return root; 46 } 47 } 48 return create_item(word, root); 49} 50 51void output(struct LIST *list){ 52 int i = 0; 53 for(; list != NULL; list = list->next) { 54 printf("%s : %d\n", list->word, list->count); 55 i ++; 56 } 57 printf("-- %d items\n", i); 58} 59 60int main(int argc, char *argv[]) { 61 int ret; 62 FILE *fp; 63 char word[1024]; 64 struct LIST *root; 65 66 fp = fopen("input.txt", "r"); 67 while(1) { 68 ret = get_word(fp, word); 69 if(ret == 0) break; 70 root = count_up(root, word); 71 } 72 fclose(fp); 73 74 output(root); 75 76 return 0; 77}

リスト構造がいまいち良く分からないまま頑張ってプログラムに追加していました

構造をしっかり理解せずにコードを書いても, 例え動いたとしても分からないままでは無いでしょうか.
リストは言葉よりも図にしたほうが分かりやすい類では無いかと思いますので, 図によって解説している書籍やサイトを探してみては如何でしょう.

投稿2019/03/16 08:36

jimbe

総合スコア12543

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

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

jimbe

2019/03/16 08:49

asm さんのざっくり雛形とそっくりに^^
guest

0

間違いが多く
また、関数同士の意図がバラバラで歪です。
(例: get_wordは読み取った単語をどこに入れますか?返り値として何を想定していますか?
どういった状態の場合に元の関数に戻ることを想定していますか?)

正直、設計段階からやり直した方がよいです。

ざっくりとした雛形だけ作ると以下

c

1/* TODO: fpから1単語を読み出しdestにコピーする関数を書くこと 2 戻り値として、読み込めた時は0以外、読み込めなかった時は0を返す 3 destに書き込んだ文字数でも返しとけばちょうどいい 4*/ 5int get_word(FILE* fp, char* dest){ 6} 7 8/* TODO: listとwordを受け取って 9 list内にwordがあればカウントを1増やす 10 なければリストの末尾にmallocもしくはcallocで増やす 11*/ 12void cout_up(LIST* list, char* word){ 13} 14 15 16/* TODO: listの内容を出力する 17*/ 18void output(LIST* top){ 19} 20int main(void){ 21 FILE* fp = fopen("input.txt", "r"); 22 LIST list = {}; 23 char word[1024]; 24 while(get_word(fp, word)){ // wordが読み取れる間 25 puts(word); 26 count_up(list, word); // wordをlistに追加 27 } 28 output(list); 29}

リストについて

list[i].count これではlistは単なる配列です。
リスト構造といった場合のリストはおそらく線形リストであり
list = list->nextで次の要素にアクセスしていく奴です。

考える上でちょっと難しいのが何も入っていない初期状態をどうするかです。
まぁ、今回の場合は「1個分を次の単語のために予約する」のがラクな気がします。

c

1// 追加時 2LIST* current = top; 3LIST* next = current->next; 4if(!next) { // 次の要素がない 5 strcpy(now->word, word); // 単語を登録 6 now->next = あたらしい要素を予約し次の要素として登録 7} 8current = next;

的な

投稿2019/03/16 08:35

asm

総合スコア15147

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

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

0

main関数の引数は言語仕様上、引数の個数、引数の値(つまりint argc, char *argv[]、もしくはvoid)と決まっています。
そこにstruct LIST *listという引数を書いているので、本来のargcがlistに置き換わっておりおかしな動作になっています。
listはmain関数の中で定義し、メモリの割り当てをする必要があります。

c

1int main(void) 2{ 3 struct LIST *list; 4 int ret; 5 list = (struct LIST*)malloc(sizeof(struct LIST)); 6 7 fp = fopen("input.txt" , "r"); 8

またリスト構造とのことですが、構造体内のnextが使われていません。
countも同じ構造体内にあったら意味がないようように思えますし。
全体的に見直しが必要です。

投稿2019/03/16 06:43

ttyp03

総合スコア16996

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

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

jimbe

2019/03/16 07:02

count はワードの出現数を数えるカウンタではないでしょうか. おそらく > list->count ++;//リスト番号を1増やす が間違っていて > list[i].count++;//カウントする が本命(?)と思います.
ttyp03

2019/03/16 07:04

要素の中にカウント持ってたら、各要素にカウントが入ることになるので意味がないと思うのですよ。
ttyp03

2019/03/16 07:06

何番目かを表すという意味ではあってもいいですけど。 少なくとも全体の個数を表す意味では置き場所は違いますね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問