C語言實(shí)現(xiàn)簡單計(jì)算器程序
這兩天在看一個C語言寫的計(jì)算器程序,做了不少的功夫,跟著作者一步步的進(jìn)行完善,了解了許多細(xì)節(jié)性的東西,在此自己做個總結(jié),加深自己對程序的印象,也算是梳理。
在該計(jì)算器程序,能進(jìn)行加減乘除、sin、cos、exp等操作,同時能進(jìn)行數(shù)值保存功能。而該計(jì)算器使用逆波蘭表示法。即所有運(yùn)算符都跟在操作數(shù)的后面,比如下列表達(dá)式:
(1 - 2) * (4 + 5)采用逆波蘭表示法表示為:1 2 - 4 5 + *
逆波蘭表達(dá)法中不需要圓括號,只要知道每個運(yùn)算符需要幾個操作數(shù)就不會引起歧義。
計(jì)算器程序?qū)崿F(xiàn)很簡單,具體原理如下:
while(/* 下一個運(yùn)算符或操作數(shù)不是文件結(jié)束指示符 */) if(/* 是數(shù) */) /* 將該數(shù)壓入到棧中 */ else if (/* 是運(yùn)算符 */) /* 彈出所需數(shù)目的操作數(shù) */ /* 執(zhí)行運(yùn)算 */ /* 將結(jié)果壓入到棧中 */ else if (/* 是換行符 */) /* 彈出并打印棧頂?shù)闹?*/ else /* 出錯 */
在程序設(shè)計(jì)中,使用模塊化思想,getop函數(shù)來進(jìn)行讀入,該函數(shù)返回一個標(biāo)識,用來標(biāo)識讀入的是什么類型。主循環(huán)體中根據(jù)該標(biāo)識執(zhí)行相應(yīng)的動作。
以下是該程序: (我將所有函數(shù)和變量放在同一文件)
#include <stdlib.h> #include <stdio.h> #include <string.h> #define MAXOP 100 #define NUMBER '0' //標(biāo)識讀入的是數(shù)字 #define NAME 'n' //標(biāo)識讀入的是字符串(函數(shù)名或非法字符串) #define ALPHA 26 int getop(char []); void push (double); //壓棧 double pop(void); //出棧 void clear(void); //清空棧 void mathfnc(char []); //執(zhí)行相應(yīng)的數(shù)學(xué)函數(shù)sin、cos、exp等 int main(void) { int type; int i, var = 0; double op1, op2,v; char s[MAXOP]; double variable[ALPHA]; for (i = 0; i < ALPHA; i++) //初始化用于保存數(shù)值的變量數(shù)組 variable[i] = 0.0; while ((type = getop(s)) != EOF) //讀取輸入 { switch (type) { case NUMBER: push (atof(s)); break; case NAME: mathfnc(s); break; case '+': push (pop() + pop()); break; case '*': push (pop() * pop()); break; case '-': op2 = pop(); push (pop() - op2); break; case '/': op2 = pop(); if (op2 != 0.0) push (pop() / op2); else printf ("error: zero divisor\n"); break; case '%': op2 = pop(); if (op2 != 0.0) push (fmod(pop(), op2)); else printf ("error: zero divisor\n"); break; case '?': //打印棧頂元素 op2 = pop(); printf ("\t%.8g\n", op2); push (op2); break; case '=': //保存數(shù)值 pop(); if (var >= 'A' && var <= 'Z') variable[var - 'A'] = pop(); else printf ("error: no variable name\n"); break; case 'c': clear(); break; case 'd': //復(fù)制棧頂元素 op2 = pop(); push(op2); push(op2); break; case 's': //交換棧元素 op1 = pop(); op2 = pop(); push(op1); push(op2); case '\n': v = pop(); //v保存最后的一次結(jié)果 printf ("\t%.8g\n", v); break; default: if (type >= 'A' && type <= 'Z') push(variable[type - 'A']); else if (type == '@') //輸入的字符@表示最近一次結(jié)果值 push(v); else printf ("error: unknown command %s\n", s); break; } var = type; } return 0; } /* ----------------------------------------------------------- */ #define MAXVAL 100 int sp = 0; //標(biāo)識棧頂 double val[MAXVAL]; void push(double f) { if (sp < MAXVAL) val[sp++] = f; else printf ("error: stack full, can't push %g\n", f); } double pop(void) { if (sp > 0) return val[--sp]; else { printf ("error: statck empty\n"); return 0.0; } } void clear(void) { sp = 0; } void mathfnc (char s[]) { double op2; if (strcmp (s, "sin") == 0) push(sin(pop())); else if(strcmp (s, "cos") == 0) push(cos(pop())); else if(strcmp (s, "exp") == 0) push(exp(pop())); else if(strcmp (s, "pow") == 0) { op2 = pop(); push (pow(pop(), op2)); } else printf ("error: %s not supported\n", s); } /* ----------------------------------------------------------- */ #include <ctype.h> int getch(void); void ungetch(int); int getop(char s[]) { int i, c; while ((s[0] = c = getch()) == ' ' || c == '\t') //過濾開頭的空白字符 ; s[1] = '\0'; i = 0; if (islower(c)) //判斷是否為小寫字母,也即讀取由小寫字母組成的字符串 { while (islower(s[++i] = c = getch())) ; s[i] = '\0'; if (c != EOF) ungetch(c); if (strlen (s) > 1) return NAME; else return c; } if (!isdigit(c) && c != '.' && c != '-') return c; if (c == '-') //用于判斷是負(fù)數(shù)還是減操作 { if (isdigit(c = getch()) || c == '.') s[++i] = c; else { if (c != EOF) ungetch(c); return '-'; } } if (isdigit(c)) //收集整數(shù)部分 while (isdigit(s[++i] = c = getch())) ; if (c == '.') //收集小數(shù)部分 while (isdigit(s[++i] = c = getch())) ; s[i] = '\0'; if (c != EOF) ungetch(c); return NUMBER; } /* ----------------------------------------------------------- */ /* * 引用以下兩個函數(shù)是因?yàn)椋撼绦虿荒艽_定它已經(jīng)讀入的輸入是否足夠 * * 除非超前多讀入一些輸入,在本程序中,讀入一些字符合成一個數(shù)字 * * 所以在看到第一個非數(shù)字字符之前,已經(jīng)讀入的數(shù)的完整性是不能確定的 * 由于程序要超前讀入一個字符,這樣就導(dǎo)致最后又一個字符不屬于當(dāng)前所要讀入的數(shù) */ #define BUFSIZE 100 char buf[BUFSIZE]; int bufp = 0; int getch(void) { return (bufp > 0) ? buf[--bufp] : getchar(); } void ungetch (int c) { if (bufp >= BUFSIZE) printf ("ungetch: too many characters\n"); else buf[bufp++] = c; }
該程序雖然簡單,但是還是存在一些小小的問題,比如沒有數(shù)據(jù)時進(jìn)行pop的話,會打印棧中無數(shù)據(jù)同時返回?cái)?shù)值0.0,在循環(huán)體中許多執(zhí)行操作會將該數(shù)值保存到棧中,之后打印該值,用戶體驗(yàn)度比較差。程序設(shè)計(jì)方面,模塊化設(shè)計(jì)使得該程序容易增加功能而不影響其他模塊,比如增加一些數(shù)學(xué)函數(shù)處理,在mathfnc函數(shù)中去添加,或增加一些運(yùn)算符操作,可以在主循環(huán)體中增加。
總之,這次學(xué)習(xí)還是頗有收獲。
關(guān)于計(jì)算器的精彩文章請查看《計(jì)算器專題》 ,更多精彩等你來發(fā)現(xiàn)!
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- C語言數(shù)據(jù)結(jié)構(gòu)之簡易計(jì)算器
- C語言實(shí)現(xiàn)簡單計(jì)算器功能(1)
- C語言實(shí)現(xiàn)簡單的計(jì)算器
- C語言實(shí)現(xiàn)簡單計(jì)算器功能(2)
- C語言實(shí)現(xiàn)簡單計(jì)算器
- C語言結(jié)課設(shè)計(jì)之計(jì)算器功能
- 用C語言實(shí)現(xiàn)計(jì)算器功能
- C語言實(shí)現(xiàn)個稅計(jì)算器
- C語言運(yùn)用函數(shù)指針數(shù)組實(shí)現(xiàn)計(jì)算器功能
- 用C語言實(shí)現(xiàn)簡單的計(jì)算器功能
相關(guān)文章
基于Matlab實(shí)現(xiàn)離散系統(tǒng)分岔圖的繪制
這篇文章主要介紹了如何利用Matlab實(shí)現(xiàn)離散分岔圖的繪制,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Matlab有一定的幫助,需要的可以參考一下2022-04-04C語言 structural body結(jié)構(gòu)體詳解用法
C 數(shù)組允許定義可存儲相同類型數(shù)據(jù)項(xiàng)的變量,結(jié)構(gòu)是 C 編程中另一種用戶自定義的可用的數(shù)據(jù)類型,它允許您存儲不同類型的數(shù)據(jù)項(xiàng),結(jié)構(gòu)用于表示一條記錄,假設(shè)您想要跟蹤圖書館中書本的動態(tài),您可能需要跟蹤每本書的下列屬性2021-10-10Linux中使用C語言的fork()函數(shù)創(chuàng)建子進(jìn)程的實(shí)例教程
fork是一個在Linux系統(tǒng)環(huán)境下專有的函數(shù),現(xiàn)有的進(jìn)程調(diào)用fork后將會創(chuàng)建一個新的進(jìn)程,這里我們就來看一下Linux中使用C語言的fork()函數(shù)創(chuàng)建子進(jìn)程的實(shí)例教程2016-06-06