这两天在看一个C语言写的计算器程序,做了不少的功夫,跟着作者一步步的进行完善,了解了许多细节性的东西,在此自己做个总结,加深自己对程序的印象,也算是梳理。
在该计算器程序,能进行加减乘除、sin、cos、exp等操作,同时能进行数值保存功能。而该计算器使用逆波兰表示法。即所有运算符都跟在操作数的后面,比如下列表达式:
(1 - 2) * (4 + 5)采用逆波兰表示法表示为:1 2 - 4 5 + *
逆波兰表达法中不需要圆括号,只要知道每个运算符需要几个操作数就不会引起歧义。
计算器程序实现很简单,具体原理如下:
while(/* 下一个运算符或操作数不是文件结束指示符 */) if(/* 是数 */) /* 将该数压入到栈中 */ else if (/* 是运算符 */) /* 弹出所需数目的操作数 */ /* 执行运算 */ /* 将结果压入到栈中 */ else if (/* 是换行符 */) /* 弹出并打印栈顶的值 */ else /* 出错 */
在程序设计中,使用模块化思想,getop函数来进行读入,该函数返回一个标识,用来标识读入的是什么类型。主循环体中根据该标识执行相应的动作。
以下是该程序: (我将所有函数和变量放在同一文件)
#include <stdlib.h> #include <stdio.h> #include <string.h> #define MAXOP 100 #define NUMBER '0' //标识读入的是数字 #define NAME 'n' //标识读入的是字符串(函数名或非法字符串) #define ALPHA 26 int getop(char []); void push (double); //压栈 double pop(void); //出栈 void clear(void); //清空栈 void mathfnc(char []); //执行相应的数学函数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++) //初始化用于保存数值的变量数组 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 divisorn"); break; case '%': op2 = pop(); if (op2 != 0.0) push (fmod(pop(), op2)); else printf ("error: zero divisorn"); break; case '?': //打印栈顶元素 op2 = pop(); printf ("t%.8gn", op2); push (op2); break; case '=': //保存数值 pop(); if (var >= 'A' && var <= 'Z') variable[var - 'A'] = pop(); else printf ("error: no variable namen"); break; case 'c': clear(); break; case 'd': //复制栈顶元素 op2 = pop(); push(op2); push(op2); break; case 's': //交换栈元素 op1 = pop(); op2 = pop(); push(op1); push(op2); case 'n': v = pop(); //v保存最后的一次结果 printf ("t%.8gn", v); break; default: if (type >= 'A' && type <= 'Z') push(variable[type - 'A']); else if (type == '@') //输入的字符@表示最近一次结果值 push(v); else printf ("error: unknown command %sn", s); break; } var = type; } return 0; } /* ----------------------------------------------------------- */ #define MAXVAL 100 int sp = 0; //标识栈顶 double val[MAXVAL]; void push(double f) { if (sp < MAXVAL) val[sp++] = f; else printf ("error: stack full, can't push %gn", f); } double pop(void) { if (sp > 0) return val[--sp]; else { printf ("error: statck emptyn"); 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 supportedn", 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] = '