程序:编写一个具有加、减、乘、除四则运算功能的计算器程序。
思路:用逆波兰法来实现,在逆波兰法中,所有运算符都跟在操作数后面,比如以下中缀表达式中:
(1-2)*(4+5)采用逆波兰法表示为:12-45+*;逆波兰法中不需要括号,只需要知道每个运算符需要几个操作数就不会引起歧义。
实现:没遇到数就把它压入栈中;当一个运算符到达时,从栈中弹出相应的操作数即可,并把运算结果再压入栈中。到达行末尾时再把栈顶的值弹出并打印就可。下面看流程图:
while (下一个运算符或操作数不是文件结束指示符)
{
if (是数)
将数压入栈中
else if (是运算符)
弹出所需数目的操作数
执行运算
将结果压入栈中
else if (是换行符)
弹出并打印栈顶的值
else
出错
}
到目前为止有个问题?栈放在那儿?一种可能是把它放入主函数main中,把栈及其当前位置作为参数传递给对它执行压入和弹出的函数,但是,main函数不需要了解控制栈的变量信息,它只进行压入和弹出操作。因此,可以把栈及相关信息放在外部变量中,并只提供push和pop函数访问,而不能被main函数访问。
#include <stdio.h>
#include <stdlib.h>
#define MAXOP 100 /*操作数或运算符的最大长度*/
#define NUM '0' /*标识找到一个数*/
int getop(char []);
void push(double ;
double pop(void);
int main(void)
{
int type;
double op2;
char s[MAXOP];
while ( (type=getop(s)) != EOF)
{
switch (type)
{
case NUM:
push(atof(s));
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 '\n':
printf("\t%.8g\n",pop());
break;
default:
printf("error: unknown command %s\n",s);
break;
}
}
return 0;
}
因为+和*两个运算符不需要满足交换律,因此,操作数的弹出次序无关紧要,但是,-和/两个运算符的左右操作数必须加以区分,在函数中调用
push(pop() - pop()); 是错的
#define MAXVAL 100 /*栈val的最大深度*/
int sp = 0; /*下一个空闲栈的位置*/
double val[MAXVAL];
void push(double f)
{
if (sp < MAXVAL)
val[sp++] = f;
else
printf("error: stack full, cant push %g\n",f);
}
double pop(void)
{
if (sp > 0)
return val[--sp];
else
{
printf("error: stack empty\n");
return 0.0; //
}
}
接下来看getop函数的实现;
#include <ctype.h>
int getch(void);
void ungetch(int);
int getop(char s[])
{
int i,c;
while ( (s[0]=c=getchar()) == ' ' || c == '\t'); //跳过制表符和空格
s[1] = '\0';
if (!isdigit(c) && c!='.')
return c; /*不是数*/
i = 0;
if (isdigit(c)) /*收集整数部分*/
while (isdigit(s[++i]) = c = getch());
if (c == '.') /*收集小数部分*/
while (isdigit(s[++i]) = c = getchar());
s[i] = '\0';
if (c != EOF)
ungetch(c);
return NUM;
}
那么这个getch和ungetch函数是干什么的呢?其实是为了超前读入,负责你不知道你是否已经读入完整的数。
getch函数是用于读入下一个待处理的字符,而ungetch函数则用于把字符放回到输入中,这两个函数之间的协同工作也很简单,建立一个共享缓冲区就好。其实标准库提供了函数ungetc, 它将一个字符压回到栈中。下面看实现
#define BUFSIZE 100
char buf[BUFSIZE]; /*用于ungetch函数的缓冲区*/
int bufp; /*buf中指向下一个空闲位置*/
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;
}