因为需要应试的原因需要刷刷C,在大家的推荐下,选用了《C程序设计语言》Brain等著的版本。今天在刷第四章的时候,学习了逆波兰式计算器,书上代码及我的注释如下,心得跟在后面。
#include<stdio.h>
#include<stdlib.h>
#define MAXOP 100 //这个是最大一次输入的长度
#define NUMBER '0' //一个标志,意味着接收到的是数字,换成其他也无妨
int getop(char[]);//声明函数,分别是获取一个有意义的值、入栈、出栈
void push(double);
double pop(void);
main(){
int type;//标注每一个获取到的有意义值的类型,如数字,运算符,空格,=
double op2;//临时储存变量,储存并验证被除数和被减数等需要次序的运算数据
char s[MAXOP];//用以储存单次输入的一个列表
while((type=getop(s)) !=EOF){//只要输出的不是一个完整的EOF,这个循环就会持续调用getop录入数据
switch(type){
case NUMBER://如果是数字,getop函数将返回我们设定好的标志'0',则把s中的字符串转数字入栈
push(atof(s));
break;
case '+'://加法运算和乘法运算都是提取出最近的两个值,计算后把结果入栈。
push(pop()+pop());
break;
case '*':
push(pop()*pop());
break;
case '-'://减法和除法,需要考虑除数不为0以及先后次序,再计算后入栈
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;
}
#define MAXVAL 100 //栈 val的最大深度
int sp = 0; //下一个空栈位置
double val[MAXVAL]; //值栈val用于在计算中储存所有有效数据(不储存任何计算符号!)
//运算符号在被getop函数录入的同时,计算后的值就已经被录入到了val,且被肌酸的数也会出栈。
// push 函数:把 f 压入值栈中,并把空栈位置后移(干净利落)
void push(double f)
{
if(sp < MAXVAL)
val[sp++] = f;
else
printf("栈已满不能压入 %g\n",f);
}
//pop 函数:弹出并返回栈顶!顶的值,也就是最后一位的值,同时把空栈标记前移
double pop(void)
{
if(sp > 0)
return val[--sp];
else
{
printf("栈是空的\n");
return 0.0;
}
}
//以下是获取下一个输入的函数
#include<ctype.h>
int getch(void);//这两个函数可以被称作是,“压入”和“释放”缓冲区
void ungetch(int);
int getop(char s[]){//这个函数与缓冲区函数对接,筛选并返回出输入的有效结果,用于main()函数
int i,c;
while((s[0]=c=getch())==' '||c=='\t')
;//空格与tab是允许出现的非数字及运算符号,用于表示间隔,没有它们的话将无法分开多个连续数字。
s[1]='\0';//探测到间隔符,但是根据实测,没必要增加结尾符,探测到空格则会自动结尾。
if (!isdigit(c) && c!='.')
return c; //非数字,直接返回,是否是合法符号main会探测。
i=0;
if(isdigit(c))
while (isdigit(s[++i]=c=getch()))
;
if(c == '.')
while (isdigit(s[++i]=c=getch()))
;
s[i]='\0';//数字的读取
if(c!=EOF)//最后一位的缓冲,如果最后位非数字,则不应该随数字一起录入,否则会造成遗漏。
ungetch(c);//删掉这句,例如 1 2+ 的写法将无法读取到+。按格式写的话这句的确无用。
return NUMBER;
}
#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;
}
代码很优秀,唯一需要注意的就是要按照逆波兰式写法输入数据。