回答編集履歴

1 修正前のコードを貼り付けてしまった。

raccy

raccy score 17827

2016/11/15 22:48  投稿

気になるところがたくさんあったので、大きく書き換えました。
* メッセージは日本語にしました。
* 日本語化にあたり、必ずUTF-8になるようにしました。UTF-8環境で実行するようにしてください。
* `int`では小さいかも知れないので、`intmax_t`で最大限対応できるようにしました。
* 2分木を解放するために`free_tree()`を追加しました。
* `const`にできる引数は`const`にしました。
* ファイルを読み込んで2分木にするコードを`read_data()`として分離しました。
* メッセージを吐いて終わる所`die()`でまとめました。`die()`は`noreturn`をつけて、処理が返らないことを明確にしました。
* エラーメッセージは標準エラー出力に出すようにしました。
* ファイル読み込みは最後まで行うようにしました。20個しか読み込まない理由がわからない。
* 数字でないところは読み飛ばすようにしました。
* ファイルの読み込み途中でエラーが発生した場合は、エラーメッセージを出して終了するようにしました。
* 入力終わりは標準入力が閉じられることで終了するようにしました。MacやLinuxはCtrl+D、WindowsはCtrl+Zで終わります。
* 終わる前に2分木のメモリ解放を行うようにしました。
* 真と偽は`true`と`false`を使うようにしました。
* `?:`演算子の方がわかりやすいような気がするときは、変えました。
* if-else分は必ずブロックにするようにしました。
* `{`の前で改行するかはK&Rスタイルにしました。
```C
#include <errno.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdnoreturn.h>
#include <string.h>
#define MSG_ERR_INVALID_ARGS \
   u8"引数がありません。引数でファイル名を指定してください。"
   u8"引数が無いか、多すぎます。引数でファイル名を指定してください。"
#define MSG_ERR_FAIL_OPEN_FILE u8"ファイルを開けません。"
#define MSG_ERR_FAIL_READ_FILE u8"ファイルの読み込みに失敗しました。"
#define MSG_ERR_NO_MEMORY u8"メモリ不足です。"
#define MSG_FOUND_NUMBER u8"見つかりました。"
#define MSG_NOT_FOUND_NUMBER u8"見つけられませんでした。"
struct node {
   intmax_t data;
   struct node *left;
   struct node *right;
};
struct node *insert_data(intmax_t x, struct node *p);
void free_tree(struct node *p);
bool search_tree(intmax_t x, const struct node *p);
void print_tree(const struct node *p);
struct node *read_data(FILE *fp);
static inline noreturn void die(const char *restrict format, ...)
{
   va_list args;
   va_start(args, format);
   fprintf(stderr, format, args);
   vfprintf(stderr, format, args);
   va_end(args);
   exit(1);
}
int main(int argc, char *argv[])
{
   if (argc != 2) die("%s\n", MSG_ERR_INVALID_ARGS);
   FILE *fp = fopen(argv[1], "r");
   if (fp == NULL) die("%s: %s\n", MSG_ERR_FAIL_OPEN_FILE, argv[1]);
   struct node *root = read_data(fp);
   fclose(fp);
   if (root == NULL)
       die("%s: %s\n", MSG_ERR_FAIL_READ_FILE, strerror(errno));
   print_tree(root);
   {
       int i;
       intmax_t x;
       while ((i = scanf("%" SCNdMAX, &x)) != EOF) {
           if (i == 0) {
               scanf("%*c");
               continue;
           }
           printf("%" PRIdMAX ": %s\n", x, search_tree(x, root)
               ? MSG_FOUND_NUMBER
               : MSG_NOT_FOUND_NUMBER);
       }
   }
   free_tree(root);
   root = NULL;
   return 0;
}
struct node *insert_data(intmax_t x, struct node *p)
{
   if (p == NULL) {
       p = (struct node *)malloc(sizeof(struct node));
       if (p == NULL) die("%s\n", MSG_ERR_NO_MEMORY);
       p->data = x;
       p->left = NULL;
       p->right = NULL;
       return p;
   }
   if (x != p->data) {
       if (x < p->data) {
           p->left = insert_data(x, p->left);
       } else {
           p->right = insert_data(x, p->right);
       }
   }
   return p;
}
void free_tree(struct node *p)
{
   if (p->left != NULL) free_tree(p->left);
   if (p->right != NULL) free_tree(p->right);
   free(p);
}
bool search_tree(intmax_t x, const struct node *p)
{
   if (p == NULL) return false;
   if (x == p->data) return true;
   return search_tree(x, x < p->data ? p->left : p->right);
}
void print_tree(const struct node *p)
{
   if (p == NULL) return;
   print_tree(p->left);
   printf("%" PRIdMAX "\n", p->data);
   print_tree(p->right);
}
struct node *read_data(FILE *fp)
{
   struct node *root = NULL;
   int i;
   intmax_t x;
   errno = 0;
   while ((i = fscanf(fp, "%" SCNdMAX, &x)) != EOF) {
       if (i == 0) {
           fscanf(fp, "%*c");
           continue;
       }
       root = insert_data(x, root);
   }
   if (errno != 0) return NULL;
   return root;
}
```

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る