前提・実現したいこと
C言語, teratail初心者です。
学校の課題で「テキストファイルから単語を読み取り、同じ単語が出現すれば回数を記録し、単語は辞書順にソートして線形リストを作る。」という課題です。このソートがうまくいきません。
初心者故にコードが汚い所があると思いますが、ご助力いただけると幸いです。
解決策でなくても、「ここが駄目」っていうポイントだけでもありがたいです。
発生している問題・エラーメッセージ
大体の単語はソート出来ているのですが、一部上手くソートされていません。
(Mrsという単語が、辞書順で最後尾の訳では無いのに、最後尾に行ってしまう
a行が上手くソートされない など。)
該当のソースコード
C
1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4 5#define True 1 6#define False 0 7 8typedef struct word{ 9 char name[20]; 10 int count; 11 struct word *next; 12}Word; 13 14/* ---プロトタイプ宣言--- */ 15int read_word(FILE*, char[]); 16void print_nodes(Word*, FILE*); 17Word *add_node(char[], Word*); 18Word *create_word(char[]); 19int check_word(char[], Word*); 20Word *sort_node(char[], Word*); 21 22/* ---main関数--- */ 23int main(void){ 24 FILE *fp; 25 FILE *fp_print; 26 Word *root = NULL; 27 char buf[20]; 28 29 fp = fopen("anne_short.txt", "r"); 30 fp_print = fopen("output.txt", "a"); 31 32 if(fp == NULL){ 33 printf("Error!\n"); 34 exit(1); 35 }else{ 36 printf("リスト作成中\n"); 37 38 while(read_word(fp, buf) > 0){ 39 root = add_node(buf, root); 40 } 41 42 printf("リスト作製終了\n"); 43 print_nodes(root, fp_print); 44 } 45 fclose(fp); 46 fclose(fp_print); 47 48 return 0; 49} 50 51/* ---anne_short.txtから単語の読み取り--- */ 52int read_word(FILE *fp, char buf[]){ 53 int ch; 54 int index = 0; 55 int i; 56 57 while((ch = fgetc(fp)) != EOF){ 58 switch(ch){ 59 case ' ': 60 case ',' : 61 case '.': 62 case '\n': 63 case '\0': 64 if(index == 0){ //読み飛ばす文字が続いた場合 65 break; 66 }else{ 67 buf[index++] = '\0'; 68 return index; 69 } 70 default: 71 buf[index++] = ch; 72 break; 73 } 74 } 75} 76 77/* ---nodeのnameを出力--- */ 78void print_nodes(Word *out, FILE *fp_print){ 79 if(out != NULL){ 80 printf("単語:%s 回数:%d回\n", out->name, out->count); 81 fprintf(fp_print, "単語:%s 回数:%d回\n", out->name, out->count); 82 print_nodes(out->next, fp_print); 83 } 84} 85 86/* ---新規nodeの追加--- */ 87Word *add_node(char buf[], Word *root){ 88 Word *behind;// 挿入する直前のnodeのアドレス 89 Word *front;// 挿入する直後のnodeのアドレス 90 Word *tmp; 91 92 // 初回実行時はrootに新規nodeを紐づけ 93 if(root == NULL){ 94 root = create_word(buf); 95 96 // 2回目以降 97 }else{ 98 if((check_word(buf, root)) == True){// True = 新出の単語 99 behind = sort_node(buf, root); 100 front = behind->next; 101 102 if(behind == root){// 先頭に追加する場合 103 tmp = create_word(buf); 104 root = tmp; 105 tmp->next = behind; 106 107 }else if(behind->next == NULL){// 最後尾に追加する場合 108 behind->next = create_word(buf); 109 110 }else{// リストの途中に追加する場合 111 tmp = create_word(buf); 112 behind->next = tmp; 113 tmp->next = front; 114 } 115 } 116 } 117 return root; 118} 119 120/* ---新規nodeの作製--- */ 121Word *create_word(char buf[]){ 122 Word *node = (Word*)malloc(sizeof(Word)); 123 124 // 新規nodeの初期化 125 node->next = NULL; 126 node->count = 1; 127 strcpy(node->name, buf); 128 129 return node; 130} 131 132/* ---新出単語かどうかのチェック--- */ 133int check_word(char buf[], Word *root){ 134 Word *checker = root; 135 136 // 新出ならTrue, 既出ならcountをインクリメントしてFalseを返す 137 while(checker != NULL){ 138 if(stricmp(checker->name, buf) == 0){ 139 checker->count++; 140 return False; 141 }else{ 142 checker = checker->next; 143 } 144 } 145 return True; 146} 147 148/* ---nodeを挿入する際に辞書順に--- */ 149Word *sort_node(char buf[], Word *root){ 150 Word *node = root; 151 Word *behind = node; // 単語を挿入する直前のnodeのアドレス 152 153 while(stricmp(buf, node->name) > 0){ 154 if(node->next != NULL){ 155 behind = node; 156 node = node->next; 157 }else{ 158 break; 159 } 160 } 161 162 return behind; 163} 164
試したこと
補足情報(FW/ツールのバージョンなど)
私の環境を記させて頂きます。足りない情報がございましたら教えていただけると幸いです。
Windows 8
テキストエディタ : サクラエディタ
コンパイラ mingw-w64
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/07/02 17:54