今回は、ソフトウェア会社の研修で作成した電卓プログラムを紹介します!
使用している言語はC言語です。
私が実務未経験で入社して、研修前半で作成したプログラムの1つです。
研修課題に電卓プログラムが選ばれている理由はいくつかあります。
●四則演算をそれぞれ関数に分けてプログラムが組めるのか
●関数ポインタを活用することが出来ているか
●効率の良いアルゴリズムになっているのか
上記のことを学習し、自力でプログラムを組めるようになるのが電卓プログラムの研修の目的でした。
実際の電卓では四則演算以外にも様々な演算処理を行うことができますが、今回作成したプログラムは四則演算のみに限定されています。
※このプログラムの終了条件は ’x’ が入力された場合です。
電卓プログラムのコード
/*****************************************************************************
電卓プログラム(四則演算のみ)
終了条件:xが入力された時
<resson_dentaku.c> ver1.00
------------------------------------------------------------------------------
作成日:
作成者:
******************************************************************************/
//---ヘッダファイル---//
#include <stdio.h>
#include <ctype.h>
//---マクロ定義---//
#define ARRAY_LENGTH 17
#define PLUS 10
#define MINUS 11
#define MULTI 12
#define DIV 13
#define EQUAL 14
#define FINISH -1
//---配列の宣言---//
char numSymbol[ARRAY_LENGTH] = "0123456789+-*/=x";
int calcInt[ARRAY_LENGTH] = {0,1,2,3,4,5,6,7,8,9,PLUS,MINUS,MULTI,
DIV, EQUAL,FINISH};
//---関数ポインタ宣言---//
typedef int (*FUNC_CALC)(int a, int b);
ヘッダファイルには<stdio.h>と<ctype.h>の2つをインクルードしてあります。
マクロ定義では配列のサイズとそれぞれの演算子に対応する番号を定義しています。
配列には文字の配列(char numSymbol[ ])とその文字に対応した番号が格納されている配列(int calcInt[ ])を準備してあります。
今回の課題では関数ポインタを使用するという制約があったので、戻り値にint、引数にint型の整数2つを使用する関数ポインタを宣言してあります。
電卓プログラムで使用した関数群
入力を処理する関数
//----------------------------------------------------------------------------
// 関数名 :reInputVal
// 機 能 :入力された数字または演算記号に一致する整数値を返す。
// :返す整数値は配列calcIntに対応
// 戻り値 :int (入力された数字または演算記号に対応する整数値 失敗:-1)
//----------------------------------------------------------------------------
int reInputVal( /* 成功:整数値 失敗:-1 */
void
)
{
int i; //添え字
int reVal; //数字または演算記号
char ch; //入力を受け取る変数
scanf("%c", &ch); //入力された文字を1文字ずつ読み取る
/* for文でループしながら一致する文字を配列から検索 */
for(i = 0; i < ARRAY_LENGTH; i++)
{
if(tolower(ch) == numSymbol[i]) //文字が一致した場合
{
reVal = calcInt[i]; //対応する整数値をreValに代入
return reVal;
}
}
}
数値・演算記号・終了条件の’x’の入力を受け付けて、その数値が演算記号の番号を戻り値で返す関数です。
for文を使用して、char numSymbol[ ] に格納されている文字以外は読み捨てるように処理しています。
四則演算の関数
//----------------------------------------------------------------------------
// 関数名 :plus
// 機 能 :足し算
// 戻り値 :int (計算結果)
//----------------------------------------------------------------------------
int plus( /* 戻り値:計算結果 */
int ri, /* i:右辺 */
int lf /* i:左辺 */
)
{
lf = lf + ri;
return lf;
}
//----------------------------------------------------------------------------
// 関数名 :minus
// 機 能 :引き算
// 戻り値 :int (計算結果)
//----------------------------------------------------------------------------
int minus( /* 戻り値:計算結果 */
int ri, /* i:右辺 */
int lf /* i:左辺 */
)
{
lf = lf - ri;
return lf;
}
//----------------------------------------------------------------------------
// 関数名 :multi
// 機 能 :かけ算
// 戻り値 :int (計算結果)
//----------------------------------------------------------------------------
int multi( /* 戻り値:計算結果 */
int ri, /* i:右辺 */
int lf /* i:左辺 */
)
{
lf = lf * ri;
return lf;
}
//----------------------------------------------------------------------------
// 関数名 :div
// 機 能 :割り算
// 戻り値 :int (計算結果)
//----------------------------------------------------------------------------
int div( /* 戻り値:計算結果 */
int ri, /* i:右辺 */
int lf /* i:左辺 */
)
{
if(ri == 0){
ri = 1;
}
if(lf == 0){
return ri;
}
lf = lf / ri;
return lf;
}
//----------------------------------------------------------------------------
// 関数名 :equal
// 機 能 :右辺を左辺に代入する
// 戻り値 :int (計算結果)
//----------------------------------------------------------------------------
int equal( /* 戻り値:計算結果 */
int ri, /* i:右辺 */
int lf /* i:左辺 */
)
{
return lf;
}
どれも単純な関数ですね。
割り算の場合のみ、0で除算しないように処理してあります。
main関数の処理(関数のポインタを格納した配列と変数の宣言まで)
/*****************************************************************************
---main関数---
******************************************************************************/
int main(viod)
{
FUNC_CALC arrayFn[] = {plus, //足し算の関数
minus, //引き算の関数
multi, //掛け算の関数
div, //割り算の関数
equal //イコール
};
int input = 0; //入力値
int right = 0; //右辺
int left = 0; //左辺
int symbol = PLUS; //演算記号
int eqFlag = 0; //=演算子のフラグ:0 or 1
宣言しておいた関数ポインタを使用して、それぞれの関数のアドレスを配列arrayFn[ ]に格納します。
この処理によって例えば
arrayFn[0](1, 1)とした場合に1+1の足し算をした結果を返すことが可能になります。
変数についてはコメントに書いてある通りです。
演算記号の初期値はPLUSにしてあります。
main関数の処理(演算の処理部分)
/* xが入力されるまでループ */
while(input != FINISH)
{
/* 入力された文字から数字・演算記号に対応する整数値を返す */
input = reInputVal();
if(input == FINISH) //xが入力された場合
{
return 0; //ここで処理を終了
}
if(input < PLUS) //数値が入力された場合
{
//数字が連続する間は桁を増やす
right = (right * 10) + input;
// printf("入力値: %d\n", right);
}
if((PLUS <= input) && (input <= EQUAL)) //演算記号が入力された場合
{
if(input == EQUAL) //イコールが入力された場合
{
if(right == 0) //右辺がゼロだった場合(連続で=を入力した)
{
right = left; //左辺を右辺に代入する
/* かけ算の場合は右辺に0を代入 */
if(symbol == MULTI)
{
right = 0;
}
}
left = arrayFn[symbol - 10](right, left); //関数ポインタの呼び出し
right = 0;
eqFlag = 1; //=フラグを立てる
printf("計算結果: %d\n", left);
}
else
{
if(eqFlag == 1) //フラグが立っている場合(*2=のような計算)
{
if(input == MULTI || input == DIV)
{
right = 1;
}
else
{
right = 0;
}
symbol = input; //フラグが立っていた場合は先に代入
eqFlag = 0; //フラグを倒す
}
left = arrayFn[symbol - 10](right, left);
symbol = input;
right = 0;
// printf("計算結果: %d\n", left);
}
}
}
printf("終了\n");
return 0;
}
電卓プログラムを作成している中で少し戸惑った処理は以下のような処理です。
+2= 2
= 4
= 6
*2= 12
= 24
このように電卓では、=を入力し続けると1つ前の演算で処理した内容を再度実行してくれます。
この処理を実装するため、イコールが入力された直後の処理の時のみ、その他の演算子と計算順序を入れ替えてあります。※上の写真の21~31行目の処理です。
イコールが入力された直後かどうかの判断はeqFlagで判定しています。今回はビット演算ではなく、単純に0か1を代入して値を切り替えています。
コマンドプロンプトで実行すると・・・
こんな形でだいぶ電卓に近い処理をすることができるようになりました!
研修で作成したプログラムですが、いい勉強になりました。
Windowsの電卓アプリなどは他にもいろいろな機能がついていて、突き詰めるとかなり難しくなるらしいです。笑
興味のある方は挑戦してみてはどうでしょう!
この記事が参考になればうれしいです!
その他:研修で作成したC言語プログラム
その他のC言語プログラム集はこの投稿にまとめてあります!
C言語の初心者用のコードなので是非活用して下さい。
【C言語】研修 サンプルプログラム集
Sample Code(全文Ver)
/*****************************************************************************
電卓プログラム(四則演算のみ)
終了条件:xが入力された時
<resson_dentaku.c> ver1.00
------------------------------------------------------------------------------
作成日:
作成者:
******************************************************************************/
//---ヘッダファイル---//
#include <stdio.h>
#include <ctype.h>
//---マクロ定義---//
#define ARRAY_LENGTH 17
#define PLUS 10
#define MINUS 11
#define MULTI 12
#define DIV 13
#define EQUAL 14
#define FINISH -1
//---配列の宣言---//
char numSymbol[ARRAY_LENGTH] = "0123456789+-*/=x";
int calcInt[ARRAY_LENGTH] = {0,1,2,3,4,5,6,7,8,9,PLUS,MINUS,MULTI,
DIV, EQUAL,FINISH};
//---関数ポインタ宣言---//
typedef int (*FUNC_CALC)(int a, int b);
/*************************** static関数 **************************************/
//----------------------------------------------------------------------------
// 関数名 :reInputVal
// 機 能 :入力された数字または演算記号に一致する整数値を返す。
// :返す整数値は配列calcIntに対応
// 戻り値 :int (入力された数字または演算記号に対応する整数値 失敗:-1)
//----------------------------------------------------------------------------
int reInputVal( /* 成功:整数値 失敗:-1 */
void
)
{
int i; //添え字
int reVal; //数字または演算記号
char ch; //入力を受け取る変数
scanf("%c", &ch); //入力された文字を1文字ずつ読み取る
/* for文でループしながら一致する文字を配列から検索 */
for(i = 0; i < ARRAY_LENGTH; i++)
{
if(tolower(ch) == numSymbol[i]) //文字が一致した場合
{
reVal = calcInt[i]; //対応する整数値をreValに代入
return reVal;
}
}
}
//----------------------------------------------------------------------------
// 関数名 :plus
// 機 能 :足し算
// 戻り値 :int (計算結果)
//----------------------------------------------------------------------------
int plus( /* 戻り値:計算結果 */
int ri, /* i:右辺 */
int lf /* i:左辺 */
)
{
lf = lf + ri;
return lf;
}
//----------------------------------------------------------------------------
// 関数名 :minus
// 機 能 :引き算
// 戻り値 :int (計算結果)
//----------------------------------------------------------------------------
int minus( /* 戻り値:計算結果 */
int ri, /* i:右辺 */
int lf /* i:左辺 */
)
{
lf = lf - ri;
return lf;
}
//----------------------------------------------------------------------------
// 関数名 :multi
// 機 能 :かけ算
// 戻り値 :int (計算結果)
//----------------------------------------------------------------------------
int multi( /* 戻り値:計算結果 */
int ri, /* i:右辺 */
int lf /* i:左辺 */
)
{
lf = lf * ri;
return lf;
}
//----------------------------------------------------------------------------
// 関数名 :div
// 機 能 :割り算
// 戻り値 :int (計算結果)
//----------------------------------------------------------------------------
int div( /* 戻り値:計算結果 */
int ri, /* i:右辺 */
int lf /* i:左辺 */
)
{
if(ri == 0){
ri = 1;
}
if(lf == 0){
return ri;
}
lf = lf / ri;
return lf;
}
//----------------------------------------------------------------------------
// 関数名 :equal
// 機 能 :右辺を左辺に代入する
// 戻り値 :int (計算結果)
//----------------------------------------------------------------------------
int equal( /* 戻り値:計算結果 */
int ri, /* i:右辺 */
int lf /* i:左辺 */
)
{
// lf = ri;
return lf;
}
/*****************************************************************************
---main関数---
******************************************************************************/
int main(viod)
{
FUNC_CALC arrayFn[] = {plus, //足し算の関数
minus, //引き算の関数
multi, //掛け算の関数
div, //割り算の関数
equal //イコール
};
int input = 0; //入力値
int right = 0; //右辺
int left = 0; //左辺
int symbol = PLUS; //演算記号
int eqFlag = 0; //=演算子のフラグ:0 or 1
/* xが入力されるまでループ */
while(input != FINISH)
{
/* 入力された文字から数字・演算記号に対応する整数値を返す */
input = reInputVal();
if(input == FINISH) //xが入力された場合
{
return 0; //ここで処理を終了
}
if(input < PLUS) //数値が入力された場合
{
//数字が連続する間は桁を増やす
right = (right * 10) + input;
// printf("入力値: %d\n", right);
}
if((PLUS <= input) && (input <= EQUAL)) //演算記号が入力された場合
{
if(input == EQUAL) //イコールが入力された場合
{
if(right == 0) //右辺がゼロだった場合(連続で=を入力した)
{
right = left; //左辺を右辺に代入する
/* かけ算の場合は右辺に0を代入 */
if(symbol == MULTI)
{
right = 0;
}
}
left = arrayFn[symbol - 10](right, left); //関数ポインタの呼び出し
right = 0;
eqFlag = 1; //=フラグを立てる
printf("計算結果: %d\n", left);
}
else
{
if(eqFlag == 1) //フラグが立っている場合(*2=のような計算)
{
if(input == MULTI || input == DIV)
{
right = 1;
}
else
{
right = 0;
}
symbol = input; //フラグが立っていた場合は先に代入
eqFlag = 0; //フラグを倒す
}
left = arrayFn[symbol - 10](right, left);
symbol = input;
right = 0;
// printf("計算結果: %d\n", left);
}
}
}
printf("終了\n");
return 0;
}
コメント