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

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

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

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

Q&A

解決済

2回答

1871閲覧

c言語での分配法則のプログラム

退会済みユーザー

退会済みユーザー

総合スコア0

C

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

0グッド

0クリップ

投稿2020/01/29 04:44

編集2020/01/29 04:53

前提・実現したいこと

入力された算術式を二分木と捉えて、右回転・左回転を使って分配法則を行って展開する関数を作成しています。((x+9)(y+8))であれば((((xy)+(9y))+(x8))+(98))に、(7((p+(q+r))(x+y)))は(((((((7p)x)+((7q)x))+((7r)x))+((7p)y))+((7q)y))+((7r)y))という形になればいいです。
((x+9)
(y+8))は正しく表示されるのですが、(7*((p+(q+r))(x+y)))は正しく表示されず、計算結果も(((((((((77)*p)*x)y)+((((77)*q)*x)y))+((((77)*r)*x)y))+((((77)*p)*x)y))+((((77)*q)*x)y))+((((77)*r)*x)*y))となり、計算結果も294と正解の42と全く違う値になってしまいます。

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

C

1(7*((p+(q+r))*(x+y))) 2show: (7*((p+(q+r))*(x+y))) 3eval: 42 4dist: (((7*(7*((p*x)*y)))+((7*(7*((q*x)*y)))+(7*(7*((r*x)*y)))))+((7*(7*((p*x)*y)))+((7*(7*((q*x)*y)))+(7*(7*((r*x)*y)))))) 5assoc: (((((((((7*7)*p)*x)*y)+((((7*7)*q)*x)*y))+((((7*7)*r)*x)*y))+((((7*7)*p)*x)*y))+((((7*7)*q)*x)*y))+((((7*7)*r)*x)*y)) 6eval: 294 7 8*** Error in `./ex3': double free or corruption (fasttop): 0x0000000001c31290 *** 9======= Backtrace: ========= 10/lib64/libc.so.6(+0x7c619)[0x7f9273d1f619] 11./ex3[0x400a84] 12./ex3[0x400a68] 13./ex3[0x400a78] 14./ex3[0x400a68] 15./ex3[0x400a68] 16./ex3[0x400b74] 17./ex3[0x4012c8] 18/lib64/libc.so.6(__libc_start_main+0xf5)[0x7f9273cc4c05] 19./ex3[0x4006c9] 20======= Memory map: ======== 2100400000-00402000 r-xp 00000000 00:28 9045122 /exports/home/j418828/centos7/AdvProg/T6/week02/ex3 2200601000-00602000 r--p 00001000 00:28 9045122 /exports/home/j418828/centos7/AdvProg/T6/week02/ex3 2300602000-00603000 rw-p 00002000 00:28 9045122 /exports/home/j418828/centos7/AdvProg/T6/week02/ex3 2401c31000-01c52000 rw-p 00000000 00:00 0 [heap] 257f926c000000-7f926c021000 rw-p 00000000 00:00 0 267f926c021000-7f9270000000 ---p 00000000 00:00 0 277f9273a8d000-7f9273aa2000 r-xp 00000000 08:01 2365672 /usr/lib64/libgcc_s-4.8.5-20150702.so.1 287f9273aa2000-7f9273ca1000 ---p 00015000 08:01 2365672 /usr/lib64/libgcc_s-4.8.5-20150702.so.1 297f9273ca1000-7f9273ca2000 r--p 00014000 08:01 2365672 /usr/lib64/libgcc_s-4.8.5-20150702.so.1 307f9273ca2000-7f9273ca3000 rw-p 00015000 08:01 2365672 /usr/lib64/libgcc_s-4.8.5-20150702.so.1 317f9273ca3000-7f9273e5b000 r-xp 00000000 08:01 2361504 /usr/lib64/libc-2.17.so 327f9273e5b000-7f927405b000 ---p 001b8000 08:01 2361504 /usr/lib64/libc-2.17.so 337f927405b000-7f927405f000 r--p 001b8000 08:01 2361504 /usr/lib64/libc-2.17.so 347f927405f000-7f9274061000 rw-p 001bc000 08:01 2361504 /usr/lib64/libc-2.17.so 357f9274061000-7f9274066000 rw-p 00000000 00:00 0 367f9274066000-7f9274087000 r-xp 00000000 08:01 2361497 /usr/lib64/ld-2.17.so 377f9274269000-7f927426c000 rw-p 00000000 00:00 0 387f9274283000-7f9274287000 rw-p 00000000 00:00 0 397f9274287000-7f9274288000 r--p 00021000 08:01 2361497 /usr/lib64/ld-2.17.so 407f9274288000-7f9274289000 rw-p 00022000 08:01 2361497 /usr/lib64/ld-2.17.so 417f9274289000-7f927428a000 rw-p 00000000 00:00 0 427ffdda0c5000-7ffdda0e6000 rw-p 00000000 00:00 0 [stack] 437ffdda11b000-7ffdda11d000 r-xp 00000000 00:00 0 [vdso] 44ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] 45Abort (core dumped)

該当のソースコード

C

1void dist_prod_exp_sub(Exp *ep) { 2 if((*ep)->node == '*' && (*ep)->left->node != '+' && (*ep)->right->node == '+'){ 3 rotate_left_exp(ep); 4 (*ep)->right = make2_exp('*', ((*ep)->left)->left, (*ep)->right); 5 dist_prod_exp(&(*ep)); 6 } 7 else if((*ep)->node == '*' && (*ep)->left->node == '+' && (*ep)->right->node != '+') { 8 rotate_right_exp(ep); 9 (*ep)->left = make2_exp('*', (*ep)->left, ((*ep)->right)->right); 10 dist_prod_exp(&(*ep)); 11 } 12 else if((*ep)->node == '*' && (*ep)->left->node == '+' && (*ep)->right->node == '+') { 13 rotate_left_exp(ep); 14 (*ep)->right = make2_exp('*',((*ep)->left)->left, (*ep)->right); 15 rotate_right_exp(&((*ep)->left)); 16 ((*ep)->left)->left = make2_exp('*', ((*ep)->left)->left, (((*ep)->left)->right)->right); 17 rotate_right_exp(&((*ep)->right)); 18 ((*ep)->right)->left = make2_exp('*', ((*ep)->right)->left, ((*ep)->right)->right->right); 19 dist_prod_exp(&(*ep)); 20 } 21 if((*ep)->left != NULL) 22 dist_prod_exp(&((*ep)->left)); 23 if((*ep)->right != NULL) 24 dist_prod_exp(&((*ep)->right)); 25} 26 27void dist_prod_exp(Exp *ep) { 28 dist_prod_exp_sub(ep); 29 dist_prod_exp_sub(ep); 30}

試したこと

((x+9)*(y+8))などを入力すると、正しく展開はされていますが、二回目を入力すると上と同じようなエラー文が表示されます。

補足情報

このプログラムの演算子は、和と積のみです。

出力には、showは入力された算術式をそのまま表示、evalは計算結果を表示(アルファベットは1として計算)、distは分配法則を使って展開した式を表示、assocはdistで表示された式の括弧をすべて左にくくりなした式を表示しています。
Exp型は、2分木の節を格納するためのデータ構造で、下の構造体と同じ形です。

C

1typedef struct _tree { 2 char node; /* 節のデータ (1文字) */ 3 struct _tree *left; /* 左の子へのポインタ */ 4 struct _tree *right; /* 右の子へのポインタ */ 5} Tree;

rotate_left_exp、rotate_right_expはそれぞれ二分木を左回転・右回転する関数です。
make2_expは、括弧の中の引数で二分木を生成する関数で、左から根となる演算子、左の子の値、右の子の値です。

周りの人に聞いてもあまり分かってないため、ここで初めて質問させていただきます。長々とすみません、よろしくお願いします。

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

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

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

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

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

y_waiwai

2020/01/29 04:49

違う、というのはなにがどういうふうに違うんでしょうか。 実際の計算結果と、こうなるはず、の値を提示しましょう
退会済みユーザー

退会済みユーザー

2020/01/29 04:53

すみません、説明不足でした。内容を付け加えさせていただきました。ありがとうございます。
guest

回答2

0

ベストアンサー

Expや記載されていない各種関数が正しく、初期の木が正常である前提ですが、回転と木の生成までは正常であるように思いました。
(回りくどいこと再帰呼び出しになっており複雑なので自信はあまりありませんが)

気になったのはdist_prod_exp(Exp *ep)の方で、subを2回呼んでいる理由です。
これがちょっとよく分かりません。

あと最初のif~elseとその後のifでepが変わっているのと最初のif~elseで再帰呼び出しが行われた後のその後のifでまた再帰呼び出ししているののコンボで処理の流れが無駄に難解になってしまっています。

条件を整理してみましょう。

投稿2020/01/29 09:36

編集2020/01/29 10:26
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

退会済みユーザー

退会済みユーザー

2020/01/29 13:44

回答の方ありがとうございます。すこし整理してまたやってみます。ありがとうございました。
退会済みユーザー

退会済みユーザー

2020/01/29 14:13

とりあえず回転&make処理をした後の部分木のrootは必ず+になっているので、rootはもう触れる必要が無く左右のnodeについてのみ再帰呼び出しするように設計すると良いと思います。 左右両方+の場合も実は片側だけ処理して、左右のNodeについて再帰呼び出しすれば場合分けが減るはずです。 後は木を式として出力する関数があるなら呼び出しごとにどういう木になっているか出力してみればバグの原因が追求しやすいと思います。 再帰のコツは相似な構造を見つけることです。 明確な答えになってなくてすいませんが、是非頑張って下さい。
guest

0

以下3点になんとなく違和感を感じます。

(*ep)->node

引数epはダブルポインタでないのにこの書き方は正しいですか?
ep->nodeでいいような気がします。

rotate_right_exp(&((*ep)->left));

leftにはアドレスが入っているのだから、rotate_right_exp(ep->left)でいいような気がします。
rightも同様です。
もっともrotate_right_expの引数の型がダブルポインタなら問題ありません。

dist_prod_exp(&(*ep));

引数epはアドレスなのだからdist_prod_exp(ep)でいいような気がします。
ただし結果は変わらないかもしれません。

なんとなく違和感を感じただけで正解かわかりませんので参考程度にお願いします。

投稿2020/01/29 05:17

ttyp03

総合スコア16998

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

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

退会済みユーザー

退会済みユーザー

2020/01/29 05:18

ご回答ありがとうございます。一度それで書いてます、ありがとうございました。
退会済みユーザー

退会済みユーザー

2020/01/29 05:29

dist_prod_exp(ep)はエラーにならなかったのですが、それ以外の二つは訂正したところエラーになってしまいました。私の説明不足でした、答えていただいたのにすみません。少し自分でも考えてみます。
ttyp03

2020/01/29 05:35

いえ、的外れな回答失礼しました。 また何か気づいたらコメントします。
退会済みユーザー

退会済みユーザー

2020/01/29 05:37

ありがとうございます、本当にすみません。
ttyp03

2020/01/29 06:10

2関数の引数はダブルポインタじゃないですかね? そうするとしっくりくるんですが。 void dist_prod_exp_sub(Exp **ep) void dist_prod_exp(Exp **ep) そもそも今のコードってコンパイルエラー出ません?
退会済みユーザー

退会済みユーザー

2020/01/29 13:45

コンパイル時点でエラーは出てないです。ダブルポインタの方で一度やってみます。何度もありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問