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

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

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

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

Q&A

解決済

4回答

2566閲覧

二分木のメモリ開放の方法

masuter0413

総合スコア50

C

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

0グッド

0クリップ

投稿2019/05/07 02:20

二分木のプログラムを以下のように作成したのですが,メモリの開放はFREE_Memory()でちゃんとできているでしょうか.

c

1#include <stdio.h> 2#include<stdlib.h> 3#include<string.h> 4#define N 30 5 6typedef struct node { 7 struct node *left, *right; 8 char label[N]; 9}TREE; 10TREE *root = NULL;//ポインタ初期化 11 12 //ノードの新規作成 13TREE *NewNode(char *str) { 14 TREE *bp; 15 bp = (TREE *)malloc(sizeof(TREE));//メモリ確保 16 bp->left = NULL; 17 bp->right = NULL; 18 strcpy(bp->label, str); //文字列格納 19 return bp; 20} 21/*ツリー組み立て*/ 22TREE *construct_tree(TREE*node, char *str) { 23 int len1 = 0, len2 = 0; //文字列の長さ 24 if (node == NULL) { //受け取ったrootがNULLのとき 25 node = NewNode(str); //新しくノード(root)作成 26 } 27 else { 28 len1 = strlen(node->label);//nodeに格納されている文字列の長さ 29 len2 = strlen(str); //文字列strの長さ 30 if (len2 < len1) { //文字列の長さ比較 31 node->left = construct_tree(node->left, str);//文字列strの方が短いとき左に登録 32 } 33 else { 34 node->right = construct_tree(node->right, str);//文字列strの方が長いとき右に登録 35 } 36 } 37 return node; 38} 39 40/* 部分木の全ての値を出力 */ 41TREE*print_tree(TREE *node, int depth) { 42 if (node == NULL) { 43 return NULL; 44 } 45 print_tree(node->right, depth + 1);//一番右の子から表示していく 46 { int i; for (i = 0; i < depth; ++i) printf(" "); } // depth分の空白 47 printf("%s\n\n", node->label); 48 print_tree(node->left, depth + 1);//左の子表示 49 return node; 50} 51 52 53/*行きがけ順*/ 54void preorder(TREE*p) { 55 if (p == NULL)return; 56 fprintf(stdout, "立ち寄った節:%s\n", p->label); 57 preorder(p->left); 58 preorder(p->right); 59} 60/*通りがけ順*/ 61void inorder(TREE*p) { 62 if (p == NULL)return; 63 inorder(p->left); 64 fprintf(stdout, "立ち寄った節:%s\n", p->label); 65 inorder(p->right); 66} 67/*帰りがけ順*/ 68void postorder(TREE*p) { 69 if (p == NULL)return; 70 postorder(p->left); 71 postorder(p->right); 72 fprintf(stdout, "立ち寄った節:%s\n", p->label); 73} 74 75/*ツリーを表示する関数*/ 76void Print_All() { 77 print_tree(root, 0);//ツリーの先頭と空白の数(深さ)を与える 78 printf("********** OUTPUT (preorder 行きがけ順)!! **********\n"); 79 preorder(root); 80 printf("********** OUTPUT (inorder 通りがけ順)!! **********\n"); 81 inorder(root); 82 printf("********** OUTPUT (postorder 帰りがけ順)!! **********\n"); 83 postorder(root); 84} 85 86TREE *Free_Memory(TREE *p) { 87 if (p == NULL) { 88 return NULL; 89 } 90 Free_Memory(p->right); 91 free(p->right); 92 Free_Memory(p->left); 93 return p; 94} 95 96int main() { 97 FILE*fp; //ファイルポインタ 98 char str[N];//読み込む文字列 99 //ファイルオープン処理 100 if ((fp = fopen("food.txt", "r")) == NULL) { 101 fprintf(stderr, "%s\n", "error: can't read file."); 102 return EXIT_FAILURE; 103 } 104 fscanf(fp, "%s", str); //最初の文字列読み込み 105 root = NewNode(str);//rootを作成,pはrootへのポインタ 106 while (fscanf(fp, "%s", str) != EOF) {//ファイルエンドまで文字列読み込み 107 construct_tree(root, str); //ツリー組み立て 108 } 109 Print_All(); //ツリーを各方法で表示 110 return 0; 111} 112

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

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

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

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

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

episteme

2019/05/07 02:42

テストコードちょこっと書けばわかるやん。mallocのたびに+1 / freeのたびに-1 するカウンタを仕込んでおいて、最終的に0になればOK.
guest

回答4

0

最低限度これで良いのでは?

C

1void Free_Memory(TREE *p) {//そもそも戻り値いらない 2 if (p) { 3 Free_Memory(p->left); 4 Free_Memory(p->right); 5 free(p); 6 } 7}

解放を先にするのならこんな感じ。

C

1void Free_Memory(TREE *p) {//そもそも戻り値いらない 2 if (p) { 3 TREE *pleft = p->left, *pright = p->right; 4 free(p); 5 Free_Memory(pleft); 6 Free_Memory(pright); 7 } 8}

投稿2019/05/07 14:53

HogeAnimalLover

総合スコア4830

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

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

0

ベストアンサー

C

1/*帰りがけ順*/ 2void postorder(TREE*p) { 3 if (p == NULL)return; 4 postorder(p->left); 5 postorder(p->right); 6 fprintf(stdout, "立ち寄った節:%s\n", p->label); 7}

をちょびっといぢって:

C

1/*帰りがけ順*/ 2void do_postorder(TREE*p, void(*fun)(TREE*)) { 3 if (p == NULL)return; 4 do_postorder(p->left); 5 do_postorder(p->right); 6 fun(p); 7}

を定義すれば、帰りがけになんかすることができるから

C

1void free_node(TREE* p) { free(p); } 2... 3do_postroder(root, &free_node); /* これでrootを根とするTREEは全滅 */

投稿2019/05/07 11:23

編集2019/05/07 12:11
episteme

総合スコア16614

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

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

0

使用している開発環境が分らないのですが、ライブラリーによっては、メモリーリークを検出できます。
例えば VC++ ですと、<crtdbg.h>をインクルードしてmain の最初で_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG));
などとしておくと、malloc したメモリーを free しないで終了するとその旨を報告してくれます。(デバッグビルド時のみ)
テストデータを適当に作って Free_Memory を呼ぶように修正して実行してみましたが、メモリーの解放はできてないです。

修正方法ですが、「p->left あるいは p->rightNULL でなかったら、それぞれを Free_Memory で解放してから pfree で解放する」でいいと思います。

c

1void Free_Memory(TREE * p) { 2 if (p == NULL) { 3 return; 4 } 5 if (p->left) { 6 Free_Memory(p->left); 7 } 8 if (p->right) { 9 Free_Memory(p->right); 10 } 11 free(p); 12}

指摘されましたので、修正します。

c

1void Free_Memory(TREE * p) { 2 if (p == NULL) { 3 return; 4 } 5 Free_Memory(p->left); 6 Free_Memory(p->right); 7 free(p); 8}

これで充分ですね。

投稿2019/05/07 08:58

編集2019/05/07 09:32
Bull

総合スコア986

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

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

episteme

2019/05/07 09:18

if (p->left) , if (p->right) は不要スね。 呼ばれた先の if ( p == NULL ) { return; } で門前払いだから。
Bull

2019/05/07 09:26

あっ、そうですね。 結局、tacsheaven さんの回答で充分でした。
guest

0

C

1TREE *Free_Memory(TREE *p) { 2 if (p == NULL) { 3 return NULL; 4 } 5 Free_Memory(p->right); 6 free(p->right); 7 Free_Memory(p->left); 8 return p; 9}

ぱっと見、あるノードの下の枝を解放してますけど、

  • 右の枝は解放しているけど、左の枝は?
  • 自分自身は?

というあたりで、解放できてないような気がしますが。

C

1TREE *Free_Memory(TREE *p) { 2 if (p == NULL) { 3 return NULL; 4 } 5 Free_Memory(p->right); 6 Free_Memory(p->left); 7 free(p_right); 8 free(p_left); 9 free(p); 10 return p; // ただしこの p はもうアクセスできない 11}

投稿2019/05/07 02:25

tacsheaven

総合スコア13703

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

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

episteme

2019/05/07 02:32

それだと二重解放にならん? freeするのは p だけでいいように思える。
tacsheaven

2019/05/07 02:36

あー、確かに。free(p->left) と free(p->right) は(Free_Memory 内で自身を free する以上は)いらないか。
episteme

2019/05/07 03:37

うん、結局帰りがけ順:void postorder(TREE*p) が全TREEを辿れるなら、そいつの fprintf を free に置き換えるだけかと。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問