C程序设计语言逆波兰式计算器学习心得

因为需要应试的原因需要刷刷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;
}

代码很优秀,唯一需要注意的就是要按照逆波兰式写法输入数据。

猜你喜欢

转载自blog.csdn.net/PlusChang/article/details/78992262