[前へ]   [目次へ]   [次へ]

四則演算版計算機(C/C++)


今回は 第22回 で作成した加算だけ計算機を四則演算版に改造してみます。
以下を読む前に自分で一度作成すれば多くの経験値を獲得できるかもしれません。(笑)

まず、今回改造する「加算だけ計算機」のソースを再掲載します。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
< 15>
< 16>
< 17>
< 18>
< 19>
< 20>
< 21>
< 22>
< 23>
< 24>
< 25>
< 26>
< 27>
#include <stdio.h>

int main(void)
{
   
//変数宣言/定義
   
char buf[64];
   
int in1=0;
   
int in2=0;
   
int ans;
   
//入力1
   
printf("1つめの値を入力:");
   fgets(buf,63,stdin);
   sscanf(buf,
"%d",&in1);
   
//入力2
   
printf("2つめの値を入力:");
   fgets(buf,63,stdin);
   sscanf(buf,
"%d",&in2);
   
//加算処理
   
ans=in1+in2;
   
//出力処理
   
printf("結果:%d\n",ans);
   
//終了待ち
   
puts("Enterキーを押すと終了します。");
   getchar();
   
//終了
   
return 0;

では、実際に改造してみます。
まず改造仕様の確認です。

●新しく演算種別の入力を追加します。
●演算種別の入力は演算種別を各値に割り当て、数値によって行います。
●演算種別によって処理を分岐し、四則演算を実行します。
●演算種別と数値の対応は以下の通りとします。
演算種別
+(加算)1
-(減算)2
*(乗算)3
/(除算)4

ということで、まず演算種別の入力を追加します。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
< 15>
< 16>
< 17>
< 18>
< 19>
< 20>
< 21>
< 22>
< 23>
< 24>
< 25>
< 26>
< 27>
< 28>
< 29>
< 30>
< 31>
< 32>
#include <stdio.h>

int main(void)
{
   
//変数宣言/定義
   
char buf[64];//文字入力用バッファ
   
int in1=0;
   
int in2=0;
   
int type=0;//演算種別格納用
   
int ans;
   
//入力1
   
printf("1つめの値を入力:");
   fgets(buf,63,stdin);
   sscanf(buf,
"%d",&in1);
   
//入力2
   
printf("2つめの値を入力:");
   fgets(buf,63,stdin);
   sscanf(buf,
"%d",&in2);
   
//演算種別入力
   
printf("演算種別を入力(1:+,2:-,3:*,4:/):");
   fgets(buf,63,stdin);
   sscanf(buf,
"%d",&type);
   
//加算処理
   
ans=in1+in2;
   
//出力処理
   
printf("結果:%d\n",ans);
   
//終了待ち
   
puts("Enterキーを押すと終了します。");
   getchar();
   
//終了
   
return 0;

次に、以前の加算処理を書き換えて、四則演算に対応させます。
まず、 switch を使って分岐を作成します。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
< 15>
< 16>
< 17>
< 18>
< 19>
< 20>
< 21>
< 22>
< 23>
< 24>
< 25>
< 26>
< 27>
< 28>
< 29>
< 30>
< 31>
< 32>
< 33>
< 34>
< 35>
< 36>
< 37>
< 38>
< 39>
< 40>
< 41>
< 42>
< 43>
#include <stdio.h>

int main(void)
{
   
//変数宣言/定義
   
char buf[64];
   
int in1=0;
   
int in2=0;
   
int type=0;//演算種別格納用
   
int ans;
   
//入力1
   
printf("1つめの値を入力:");
   fgets(buf,63,stdin);
   sscanf(buf,
"%d",&in1);
   
//入力2
   
printf("2つめの値を入力:");
   fgets(buf,63,stdin);
   sscanf(buf,
"%d",&in2);
   
//演算種別入力
   
printf("演算種別を入力(1:+,2:-,3:*,4:/):");
   fgets(buf,63,stdin);
   sscanf(buf,
"%d",&type);
   
//計算処理(加算処理から変更)
   
switch(type){
   
case 1://加算
      
break;
   
case 2://減算
      
break;
   
case 3://乗算
      
break;
   
case 4://除算
      
break;
   
default://それ以外
      
break;
   }
   
//出力処理
   
printf("結果:%d\n",ans);
   
//終了待ち
   
puts("Enterキーを押すと終了します。");
   getchar();
   
//終了
   
return 0;
最後の default の break はあってもなくても結果は一緒ですが、
統一性とか趣味とか、そういう理由で書いてあります。

次に各 case に演算を追加します。
default にきた時は正しく入力されなかったということなので、エラーメッセージを出します。

<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
< 15>
< 16>
< 17>
< 18>
< 19>
< 20>
< 21>
< 22>
< 23>
< 24>
< 25>
< 26>
< 27>
< 28>
< 29>
< 30>
< 31>
< 32>
< 33>
< 34>
< 35>
< 36>
< 37>
< 38>
< 39>
< 40>
< 41>
< 42>
< 43>
< 44>
< 45>
< 46>
< 47>
< 48>
< 49>
#include <stdio.h>

int main(void)
{
   
//変数宣言/定義
   
char buf[64];
   
int in1=0;//入力1格納変数
   
int in2=0;//入力2格納変数
   
int type=0;//演算種別格納用
   
int ans;//結果格納変数
   //入力1
   
printf("1つめの値を入力:");
   fgets(buf,63,stdin);
   sscanf(buf,
"%d",&in1);
   
//入力2
   
printf("2つめの値を入力:");
   fgets(buf,63,stdin);
   sscanf(buf,
"%d",&in2);
   
//演算種別入力
   
printf("演算種別を入力(1:+,2:-,3:*,4:/):");
   fgets(buf,63,stdin);
   sscanf(buf,
"%d",&type);
   
//計算処理(加算処理から変更)
   
ans=0;//ansは初期化していないので0を入れておく
   
switch(type){
   
case 1://加算
      
ans=in1+in2;
      
break;
   
case 2://減算
      
ans=in1-in2;
      
break;
   
case 3://乗算
      
ans=in1*in2;
      
break;
   
case 4://除算
      
ans=in1/in2;
      
break;
   
default://それ以外
      
puts("正しく入力されませんでした");
      
break;
   }
   
//出力処理
   
printf("結果:%d\n",ans);
   
//終了待ち
   
puts("Enterキーを押すと終了します。");
   getchar();
   
//終了
   
return 0;
24行目の部分は、未初期化の変数 ans をここで放置すると正しく入力されなかった場合に
43行目で意味不明な値が出力されるので0を代入することでそれを防いでいます。

30行目、36行目に - (減算)と / (除算)演算子が登場しましたが、これらの効果は
+ (加算)と * (乗算)演算子同様、減算と除算を行うものです。
ただし整数型である int 型で演算した場合、除算結果の小数点以下は切り捨てられます。
このため、
if(n==n/3*3)
のような条件は成立しないことがあります。( n が10だった場合など)

n が int 型でかつ値が10の場合、以下のような処理を辿ることになります。
A B  C D E F G
n == n / 3 * 3


通し記号種別
Aint10変数(n)
B演算子(==)(2項、論理、優先9、結合→)
Cint10変数(n)
D演算子(/)(2項、算術、優先13、結合→)
Econst int3定数
F演算子(*)(2項、算術、優先13、結合→)
Gconst int3定数

優先順位および結合規則から、演算子D(/)、左辺 C、右辺 Eから処理され、
10/3となり、結果は3.3333333...です。
が、 int 型は小数を保持できないため、小数点以下を切捨て、3にされてしまいます。

よって・・・
A B  C      D E
n == vtemp1 * 3


通し記号種別
Aint10変数(n)
B演算子(==)(2項、論理、優先9、結合→)
Cint3一時変数
D演算子(*)(2項、算術、優先13、結合→)
Econst int3定数

次、優先順位から、演算子D(*)、左辺 C、右辺 Eを処理します。
3*3なので、結果は9です。
先ほど、小数点以下が捨てられてしまったため、割った値と同じ値を掛けても値が元に戻りません。
これを逆手にとって、端数を破棄するのに使うこともできます。

したがって・・・
A B  C
n == vtemp2


通し記号種別
Aint10変数(n)
B演算子(==)(2項、論理、優先9、結合→)
Cint9一時変数

最後に演算子B(==)、左辺 A、右辺 Cを処理しますが、
10==9は正しくないので偽になります。


さて、これで一応動くようになりました。
いろいろな値を入力して結果が正しく出力されることを確認してみてください。

実は今回のプログラムにはあえてバグを残しています。
余力があればこのバグを探してみてください。
ヒントは「無限大」です。
実は上級編としてもう一つあります。加算だけの方にもあります。こっちのヒントは「未初期化」です。

また、結果が9桁以上になった時におかしくなるのは「仕様」としてあるのでバグではないものとします。
いや、普通はバグなんですけどね(笑)

次回は今回のプログラムに残ったバグ探し、デバッグの予定です。

[前へ]   [目次へ]   [次へ]

プログラミング講座 総合目次

最終更新 2008/10/17