今回は訂正キーの3つ(AC・CE・→)を実装します。(戻る)
[AC]キーの処理
訂正キーの1つでオールクリアを行わせます。
このキーは全てを初期化するためのキーです。
結果メモリ(g_ans)、入力メモリ(g_num)にゼロを代入します。 前回の演算文字(g_ope)には OPE_SET を代入します。 表示モード状態(g_mode)は結果メモリを表示するように切り替えます。
上記の日本語のアルゴリズム(文章)通りに[AC]キーを実装すると次のようになります。
//------------------------------------------------ // [AC]キーの処理 //------------------------------------------------ static void pushAC() { g_mode = 0; g_num = 0; g_ans = 0; g_ope = OPE_SET; }
どうですか。
すごく簡単ですね。
でもこれで十分であり[AC]キーの実装は終わりです。
[CE]キーの処理
訂正キーの1つで入力キャンセルを行わせます。
このキーは入力メモリ(g_num)をクリアするためのキーです。
表示モード状態(g_mode)が入力メモリを表示してるときだけ入力メモリ(g_num)にゼロを代入します。 それ以外の結果メモリを表示してる状態ではビープ音を鳴らします。
上記の日本語のアルゴリズム(文章)通りに[CE]キーを実装すると次のようになります。
//------------------------------------------------ // [CE]キーの処理 //------------------------------------------------ static void pushCE() { if ( g_mode ){ g_mode = 1; g_num = 0; } else{ _putch( BEL ); } }
どうですか。
非常にシンプルですね。
でもこれで十分で[CE]キーの実装も終わりです。
[→]キーの処理
訂正キーの1つで1桁下がり(→)を行わせます。
このキーは入力メモリ(g_num)を1桁削ります。
表示モード状態(g_mode)が入力メモリを表示してるときだけ入力メモリ(g_num)を10で割った値にします。 それ以外の結果メモリを表示してる状態ではビープ音を鳴らします。
上記の日本語のアルゴリズム(文章)通りに[→]キーを実装すると次のようになります。
//------------------------------------------------ // [→]キーの処理 //------------------------------------------------ static void pushBS() { if ( g_mode ){ g_num /= 10; } else{ _putch( BEL ); } }
どうですか。
こちらも非常にシンプルです。
でもこれだけで1桁下がりの[→]キーの実装は終わりです。
サンプル
下のソースコードは今まで空っぽだった訂正キー pushAC、pushCE、pushBS 関数の3つを実装してます。
コンパイルすると訂正キーも演算キーも置数キーも使える電卓ソフトが一通り完成します。
訂正キーの[AC]、[CE]、[→]キーは、それぞれ[A]、[C]、[BS]キーで行います。
//------------------------------------------------------------------------------ // 整数電卓のサンプル(訂正キーの実装) //------------------------------------------------------------------------------ #define _CRT_SECURE_NO_WARNINGS #include <ctype.h> #include <conio.h> #include <stdio.h> //------------------------------------------------ // break 付きのキーワード //------------------------------------------------ #define CASE break;case #define DEFAULT break;default //------------------------------------------------ // 記号定数(制御文字) //------------------------------------------------ #define BEL '\a' #define BS '\b' #define RET '\r' #define ESC '\x1B' //------------------------------------------------ // 記号定数(上限値) //------------------------------------------------ #define MAX_LIMIT (999999999) //------------------------------------------------ // 記号定数(演算文字) //------------------------------------------------ #define OPE_SET (' ') #define OPE_ADD ('+') #define OPE_SUB ('-') #define OPE_MUL ('*') #define OPE_DIV ('/') #define OPE_MOD ('%') #define OPE_EQU ('=') //------------------------------------------------ // グローバル変数 //------------------------------------------------ static int g_mode; // 表示モード状態 static long g_ans; // 結果メモリ変数 static long g_num; // 入力メモリ変数 static int g_ope = OPE_SET; // 前回の演算文字//------------------------------------------------ // [AC]キーの処理 //------------------------------------------------ static void pushAC() { g_mode = 0; g_num = 0; g_ans = 0; g_ope = OPE_SET; } //------------------------------------------------ // [CE]キーの処理 //------------------------------------------------ static void pushCE() { if ( g_mode ){ g_mode = 1; g_num = 0; } else{ _putch( BEL ); } } //------------------------------------------------ // [→]キーの処理 //------------------------------------------------ static void pushBS() { if ( g_mode ){ g_num /= 10; } else{ _putch( BEL ); } }//------------------------------------------------ // 置数キーの処理 //------------------------------------------------ static void pushNum( int num ) { if ( g_mode == 0 ){ g_mode = 1; g_num = 0; } if ( g_num <= (MAX_LIMIT/10) ){ g_num *= 10; g_num += num; } else{ _putch( BEL ); } } //------------------------------------------------ // 演算キーの処理 //------------------------------------------------ static void pushOpe( int ope ) { if ( g_mode ){ switch ( g_ope ){ CASE OPE_SET: g_ans = g_num; CASE OPE_EQU: g_ans = g_num; CASE OPE_ADD: g_ans += g_num; CASE OPE_SUB: g_ans -= g_num; CASE OPE_MUL: g_ans *= g_num; CASE OPE_DIV: g_ans /= g_num; CASE OPE_MOD: g_ans %= g_num; DEFAULT: return; } g_mode = 0; } g_ope = ope; } //------------------------------------------------ // 整数電卓のコマンドを実行 //------------------------------------------------ extern int calcInput( int ch, long *ans ) { // 置数キー if ( isdigit(ch) ){ pushNum( ch - '0' ); } else switch ( ch ){ // 訂正キー CASE 'A': pushAC(); CASE 'C': pushCE(); CASE BS: pushBS(); // 演算キー CASE '+': pushOpe( OPE_ADD ); CASE '-': pushOpe( OPE_SUB ); CASE '*': pushOpe( OPE_MUL ); CASE '/': pushOpe( OPE_DIV ); CASE '%': pushOpe( OPE_MOD ); CASE '=': pushOpe( OPE_EQU ); CASE RET: pushOpe( OPE_EQU ); DEFAULT: return 0; } if ( ans != NULL ){ *ans = g_ans; } return 1; } //------------------------------------------------ // 整数電卓の文字列を作成 //------------------------------------------------ extern char *calcMaker( char buff[] ) { if ( g_mode ){ sprintf( buff, "NUM:%10d.[%c]", g_num, g_ope ); } else{ sprintf( buff, "ANS:%10d.[%c]", g_ans, g_ope ); } return buff; } //------------------------------------------------ // メイン関数 //------------------------------------------------ int main( void ) { char buff[ 256 ]; long ans = 0; int ch; while ( (ch = _getch()) != ESC ){ if ( calcInput(ch,&ans) ){ printf( "\r%s", calcMaker(buff) ); } } printf( "\n\n最終結果:%+d\n", ans ); return 0; } //------------------------------------------------------------------------------ // End of longcalc5.cpp //------------------------------------------------------------------------------
上記の 着色された場所 が実装した訂正キーの処理部分です。
まとめ
上記のソースコードが訂正キーも実装した完成バージョンの新しい整数電卓のサンプルです。
今後のテーマは、計算中のゼロ除算エラーとオーバーフローの不具合対策でしょう。
このままでは 0 で割ろうとすると「動作を停止しました」というエラー・ダイアログが表示されます。
上記のエラー・ダイアログを出さなくするには 0 で割ろうとしてるかチェックする必要があります。
もしも 0 で割ろうとしたときは、電卓関数がエラーコードを戻り値として戻すなどの処理が必要です。
詳しくは第3章の不具合対策で紹介するので、第2章の基本機能はこれで終わります。
※コメント投稿者のブログIDはブログ作成者のみに通知されます