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

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

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

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

Q&A

解決済

2回答

1949閲覧

c言語で電卓の演算子の比較

user012

総合スコア11

C

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

0グッド

0クリップ

投稿2020/11/06 16:55

c言語で演算子の優先順位を考慮した電卓を作ろうおもいました

リストでstackを再現しその中に値を保存していく方法で固めました
そこで問題なのが
演算子の優先順位の比較方法が思いつかなくて自分の持ってる知識では難しいと思ったので質問しました。
私が思いついたのはswitch文で

c

1switch (c){ 2 case '*': 3 push (&op, 50); 4 break; 5 case '+': 6 push (&op, 49); 7 break; 8//この演算子の場合はこの値を保存する仕組みを作り比較する方法 9//pop(&op)で取り出し比較した後これの逆をしないといけない 10}

この非効率な方法しか思いつきませんのでアドバイスをください。

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

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

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

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

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

kazuma-s

2020/11/07 01:30

op, 50, 49 の意味を説明してください。 演算は + - * / だけですか? 括弧は無いのですか? 数値は浮動小数点数ですか? 整数だけですか? 入力は 1行で、結果を表示するんですか? 表示した結果に追加の演算が行えるのですか? 結果表示後は新しい式の入力とするんですか? 実際の入出力の例をいくつか挙げてください。
user012

2020/11/07 01:59

リストを数値保存用、演算子保存用の二つのリストの作成を考えていて、 &opはリストの識別のための情報です。 演算子を直接比較してもうまく動かないので演算子ごとに数値を割り当て 比較します 50,49は適当な数字です ()は今回はなしと考えています 数値は浮動小数点を考えています。 getcharで'='で終了です まずは結果出力で終了と考えています
thkana

2020/11/07 09:19

それが効率がいいのか悪いのか(他にやりようがあるのか)は他の部分と組み合わせた時に初めて評価できます。また、今どきのコンピュータの性能を念頭においたとき、そこに効率の良さを求めるだけの価値があるのか、という問題もあります。 50とか49とかナゾな数値を出してくるあたり、他の部分はまだ全然...なんじゃないかと思いますが、方針だけでも出来ているのなら(例えば"5+4*3-2/1="をどの様に処理するか、とか)示してください。
guest

回答2

0

ベストアンサー

リストでstackを再現しその中に値を保存していく方法で固めました

本当にスタックが必要でしょうか?

1 + 2 * 3 = を計算するとき、1 + 2 を見た時点ではこの計算を実行できません。
次の演算子が優先順位の高い * である可能性があるからです。1 も + もどこかに
保存しておかなければならないので、スタックが必要だと考えたのですね。
演算子の * を見たら + と優先順位を比較し、2 * 3 は計算できます。
次に = が来ようが、+ が来ようが、* が来ようが 2 * 3 は計算できます。
保存しておかなければならないのは、前の値と演算子 1個だけでいいので、
スタックは必要ありません。

スタックが必要なのは、1 + 2 * ( 3 - 4 / 5 ) のように括弧がある場合です。
1 + も 2 * も 3 - も保存しておかなければなりません。
括弧が多重になるともっとたくさん保存しなければならず、しかも後から
保存した情報から先に使用しますから、スタックということです。
スタックは数値用と演算子用の 2つ用意してもいいし、
数値と演算子を一組にしたものを押し込んでいく一つのスタックでも構いません。

演算子の優先順位の比較方法が思いつかなくて自分の持ってる知識では難しいと思ったので質問しました。

優先順位の比較がそれほど難しいことでしょうか?

  • と - の優先順位を 1、* と / の優先順位を 2 とすると、

単にそれを比較するだけです。

演算子の優先順位を比較せずに + より先に * を演算するやり方があります。
次のコードが理解できますか?

C

1#include <stdio.h> // getchar, scanf, printf, puts 2#include <ctype.h> // isspace 3 4int c; 5 6double factor(void) // 因数(factor)は数値 7{ 8 double val = 0; 9 if (scanf("%lf", &val) == 1) 10 while (isspace(c = getchar())) ; // 次の演算子を読み込んでおく 11 else 12 c = EOF; // エラーのため入力打ち切り。次の演算子はない 13 return val; 14} 15 16double term(void) // 項(term)は因数(factor)の積商 17{ 18 double val = factor(); 19 while (1) 20 if (c == '*') 21 val *= factor(); 22 else if (c == '/') 23 val /= factor(); 24 else 25 break; 26 return val; 27} 28 29double expr(void) // 式(expression)は項(term)の和差 30{ 31 double val = term(); 32 while (1) 33 if (c == '+') 34 val += term(); 35 else if (c == '-') 36 val -= term(); 37 else 38 break; 39 return val; 40} 41 42int main(void) 43{ 44 double val = expr(); 45 if (c == '=') 46 printf("%.15g\n", val); 47 else 48 puts("error"); 49}

もちろん、これは一つのやり方であり、演算子を比較するやり方もあります。
非効率な方法でもよいので思いつくなら、それを質問に追記してもらえれば
アドバイスできると思います。

追記
演算子の優先順位を比較するやり方も書いてみました。

C

1#include <stdio.h> // scanf, printf, puts 2 3int priority(char op) 4{ 5 if (op == '+' || op == '-') return 1; 6 if (op == '*' || op == '/') return 2; 7 return 0; // op == '=' 8} 9 10int main(void) 11{ 12 double val[3]; 13 char op[3]; 14 if (scanf("%lf %c", &val[0], &op[0]) != 2) return puts("error"); 15 for (int i = 1; op[i-1] != '='; i++) { 16 if (scanf("%lf %c", &val[i], &op[i]) != 2) return puts("error"); 17 while (i > 0 && priority(op[i-1]) >= priority(op[i])) { 18 switch (op[--i]) { 19 case '+': val[i] += val[i+1]; break; 20 case '-': val[i] -= val[i+1]; break; 21 case '*': val[i] *= val[i+1]; break; 22 case '/': val[i] /= val[i+1]; break; 23 default: return puts("error"); 24 } 25 op[i] = op[i+1]; 26 } 27 } 28 printf("%.15g\n", val[0]); 29}

理解できますか?

追記2
演算子の優先順位を比較しないほうが行数が多いのですが、
工夫すれば減らすことができます。

C

1#include <stdio.h> // scanf, printf 2 3char c, op[] = "+-*/"; 4 5double expr(int i) 6{ 7 double val = 0; 8 if (i < 4) 9 for (val = expr(i+2); c == op[i] || c == op[i+1]; ) 10 c == '+' ? val += expr(i+2) : c == '-' ? val -= expr(i+2) : 11 c == '*' ? val *= expr(i+2) : (val /= expr(i+2)); 12 else if (scanf("%lf %c", &val, &c) != 2) c = 0; 13 return val; 14} 15 16int main(void) 17{ 18 double val = expr(0); 19 printf(c == '=' ? "%.15g\n" : "error\n", val); 20}

expr と term がよく似ているから一つにまとめられないか、
いっそのこと factor もまとめてしまおうということで、
expr、term、factor を expr 一つにして、expr(0)、expr(2)、expr(4) の
呼出しで区別するようにしました。

投稿2020/11/07 14:30

編集2020/11/08 10:55
kazuma-s

総合スコア8224

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

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

user012

2020/11/07 15:57

プログラム理解できました。 ほんとにすごいですね、どうしたらそのようなプログラムが書けるのでしょうか?とても参考になりました。
user012

2020/11/08 10:39

理解できました! int priority(char op)この関数とても参考になりました。
guest

0

まずは、非効率だろうがなんだろうが、あなたの思う方法で実装していきましょう。
それできちんと動けばOKOKです。

それでなにか不具合が起こったなら、それについて聞いていただければよろしいかと思います

投稿2020/11/06 22:45

y_waiwai

総合スコア88042

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

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

user012

2020/11/07 02:00

そうですね。 まずは作ってみようとおもいます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問