「平成」を感じるもの

C言語を用いて三項まで計算できる電卓を作りたいのですが、どうも上手くいきません。
四則演算(+、-、×、÷)の優先順位を用いたプログラミング方法が分かりません。
以下に自分で作成したソースを添付します。
このソースに修正や追加して3項までの四則演算できるプログラミングを教えていただけますか?
宜しくお願いします。

#include <stdio.h>

int main(void)
{
int answer;/*答え*/
int x,y,z;/*x=第一項,y=第二項,第三項*/
char op1,op2;/*演算子1、演算子2*/

while(1){
printf("式を入力してください\n");
printf("式:");
scanf("%d %c %d %c %d" ,&x,&op1,&y,&op2,&z);

if((op1=='+'|'-'|'*'|'/') && (op2=='+'|'-'|'*'|'/')){

switch(op2){
case '+':
answer=y+z;
break;

case '-':
answer=y-z;
break;

case '*':
answer=y*z;
break;

case '/':
if(z==0){
printf("ERROR\n");
return 0;
}
answer=y/z;
break;

default:
printf("ERROR\n");
return 0;
}
switch(op1){
case '+':
answer=x+answer;
break;

case '-':
answer=x-answer;
break;

case '*':
answer=x*answer;
break;

case '/':
if(y==0){
printf("ERROR\n");
return 0;
}
answer=x/answer;
break;

default:
printf("ERROR\n");
return 0;
}
printf("答え:%d\n",answer);
}

else {
switch(op1){
case '+':
answer=x+y;
break;

case '-':
answer=x-y;
break;

case '*':
answer=x*y;
break;

case '/':
if(y==0){
printf("ERROR\n");
return 0;
}
answer=x/y;
break;

default:
printf("ERROR\n");
return 0;
}
printf("答え:%d\n",answer);
}

}
}
左辺に×、÷が来ても優先的に計算されません。

A 回答 (5件)

どこまでの道具が使えるのかどうかにはよりますが、雰囲気からすれば、2項の「電卓」はコードがあるようですね。


これを、3項に拡張する場合、だらだらとコードを付け加えてゆくよりは、今ある部分を機能的に独立させる方が見通しは良くなります。

たとえば、こんな感じ。



int calc2term(int a, char op, int b)
{
// a op b の値を返す
}

int comp_op(char op1, char op2)
{
// op1 と op2 優先順序を確認する
// op1 が優先なら、-1 を
// op2 が優先なら、1 を
// 優先順序が同じなら 0 を返す。
}


int main()
{
int answer;

// ここまでで、z, y,z op1, op2 が入力されたものとする

if (comp_op(op1, op2) == 1) // 特別扱いするのは、op2 のほうが優先順序が高いときだけ
{
answer = calc2term(y, op2, z);
answer = calc2term(x, op1, answer);
// op2 のほうが優先順位が高いので x op1 (y op2 z) を計算する。
}
else // それ以外の時は、op1 op2 の優先順序が同じ時も含めて、左から順に計算すればいい
{
answer = calc2term(x, op1, y);
answer = clac2term(answer, op2, z);
// (x op1 y) op2 z を計算する
}

// answer の値を表示する。

return 0;
}

この回答への補足

回答ありがとうございます。
3項だけの計算で出来ました。
さらに質問で申し訳ありませんが、以下のプログラムを基に3項だけの計算を2項以上10項以下で可能にしたいのですが、アドバイスをお願いします。
以下に参考のプログラムを貼り付けます。
#include <stdio.h>
#include <stdlib.h>

int calc(int a, int b, int op)/*計算を行ってる関数*/
{
int answer;
switch(op){
case '+':
answer=a+b;
break;

case '-':
answer=a-b;
break;

case '*':
answer=a*b;
break;

case '/':
if(b==0){
printf("0で割ることは出来ません\n");
exit(1);
}
answer=a/b;
break;

default:
printf("ERROR\n");
exit(1);
}
return answer;
}
int main(void)
{
int answer; /*答え*/
int x,y,z; /*x=第一項,y=第二項,第三項*/
char op1,op2; /*演算子1、演算子2*/
while(1){
printf("式を入力してください\n");
printf("式:");
scanf("%d %c %d %c %d" ,&x,&op1,&y,&op2,&z);

if(((op1=='+') || (op1=='-')) && ((op2=='*') || (op2=='/'))) /*右辺と左辺の計算の優先順位の判断*/
{
answer = calc(y, z, op2);/*右辺を初めに計算*/
answer = calc(x, answer, op1);/*右辺の計算後に左辺を計算*/
printf("答え:%d\n",answer);
}
else
{
answer = calc(x, y, op1);/*左辺を計算*/
answer = calc(answer, z, op2);/*右辺を計算*/
printf("答え:%d\n",answer);
}
}
return 0;
}

補足日時:2011/07/20 17:11
    • good
    • 2

No.4 です。



残念ながら、この方針では3項限定でしか処理ができません。
まず、入力からして、数字が3つであることを前提にしていますね。

これ以上項数を増やすためには、「繰り返し」または、「再帰」という仕掛けを導入する必要があります。
※その意味では、No.4 の回答も、柔軟性を欠くものです。

なので、知るべき事は多く、簡単なアドバイスでどうにかなるというレベルではない気がします。

とりあえず、一度配列に読み込んで、乗除算の部分だけ前もって計算して別の配列に移し、最後に加減の計算をするという方針で作ってはみました。

紙の上に、式を書いて何をやっているか追いかけてみれば、流れはわかると思います。
あと、入力の最後は、= です。 1+2*3+4= とか。

int main()
{
int num[10];
char op[10];
int numCount;

int num_wk[10];
char op_wk[10];
int wkCount;

int i;
int j;

int result;
int wk;

int leftTerm;
int rightTerm;

op[0] = '+';
scanf("%d", &num[0]);
for(i = 1; i < 10; i++)
{
scanf("%c", &op[i]);
if (op[i] == '=') break;
scanf("%d", &num[i]);
}

for(j = 0; j < i; j++)
printf("%c %d\n", op[j], num[j]);

// 計算開始
numCount = wkCount = 0;
while(1)
{
if ((op[numCount + 1] != '*') && (op[numCount + 1] != '/'))
{ // 優先順序を意識する必要は無い
op_wk[wkCount] = op[numCount];
num_wk[wkCount] = num[numCount];
numCount++;
wkCount++;
}
else
{
// 優先順序を意識する(乗除の部分を項として計算する)
op_wk[wkCount] = op[numCount]; // 項の前の符号を最初に保持
wk = num[numCount];
numCount++;
while((op[numCount] == '*') || (op[numCount] == '/')) // 次の項が始まるまで
{
wk = calc(wk, num[numCount], op[numCount]);
numCount++;
}
num_wk[wkCount] = wk;
wkCount++;
}

if(op[numCount] == '=') break;
}
printf("--------------------------------\n");
// ここまでで、乗除は部分的に計算されて、wk_num, wk_op に確保されている
for(i = 0; i < wkCount; i++)
{
printf("%c %d\n", op_wk[i], num_wk[i]);
}
// 最終の計算
printf("--------------------------------\n");
result = 0;
for(i = 0; i < wkCount; i++)
{
result = calc(result, num_wk[i], op_wk[i]);
}
printf("Answer = %d", result);
return 0;
}
    • good
    • 2

こまかく見てないけど



> if((op1=='+'|'-'|'*'|'/') && (op2=='+'|'-'|'*'|'/')){

PHPかなんかで正規表現の経験があるんですかね?
でも、C言語で、しかも、条件式として使うなら間違っています。
| 一つはビット毎のorを計算します。
'+'|'-'|'*'|'/' だと、
+を表わす文字コード or -を表わす文字コード or *を表わす文字コード or /を表わす文字コード
になります。
この書き方でするなら
((op1=='+') || (op1=='-' ) || (op1=='*' ) || (op1=='/' ))
とする必要があります。(わかりやすくするために括弧を付けました。)
他にもstrchrを使うとか方法はあります。

で、このifが成りたつときに、y○z を先に計算するようですけど
今までは条件が異常だったので、真になることが無く、全部x△yを先に計算していましたが、上の修正をすると、op1,op2の全ての組合せで真になるので、逆に、x△yを先に計算することがなくなります。

どちらを先に計算するのか、もう一度、条件をよく考えてみましょう
    • good
    • 0

> 左辺に×、÷が来ても優先的に計算されません。



そんなコードは書かれていないので、当然です。

また、

> if((op1=='+'|'-'|'*'|'/') && (op2=='+'|'-'|'*'|'/')){

このコードは、あなたが意図してる動作とは違うと思います。
    • good
    • 0

C言語はものすごく大昔にやったので文法的な間違いは指摘できません。



まず
if((op1=='+'|'-'|'*'|'/') && (op2=='+'|'-'|'*'|'/')){
の部分ですが、これですとop1,op2が+-*/のどの組み合わせでも
後ろのyとzの計算をしてしまうと思います。
条件的には[op1が+もしくは-]かつ[op2が*もしくは/]であれば
後ろのyとzの計算を優先する、としなければいけないと思います。

また、上の条件に当てはまらない場合のルートではxとyの計算のみを行って
zの計算が抜けているのでそれも追加する必要があると思います。

さらにanswerがint型であるため割り算のときに割り切れない数字の組み合わせですと
なにやら不都合が出ると思われます。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


おすすめ情報