源自《The C Programming Language》 P62 ex4.3:

计算例如:(1 - 2) * (4 + 5)的值,采用逆波兰表示法(即后缀表示法)

代码:

main.c

#include

#include //为了使用库函数atof

#include //使用sin, exp, pow等数学函数

#include //使用strcmp, strlen等字符串函数

#include "getop.h"

#defineMAXOP100//操作数或运算符的最大长度(待处理字符串的最大长度)

#defineNUMBER'0'//标识找到一个数

#defineNAME'n' //标示找到一个数学函数

void push(double );

double pop();

//void printStack(double []);

void clear();

void mathfnc(char []);

//extern double val[];//如果声明为extern val[]; 则报错:变量val被重定义

//extern sp;

//逆波兰计算器

int main()

{

int type;

double op2;

double op1;

//double tmp;

char s[MAXOP];

while((type = getop(s)) != EOF)

{

switch(type)

{

case NUMBER://当待处理字符串是数值字符串时,将其转换,并压栈

push(atof(s));

break;

case '+':

push(pop() + pop());

break;

case '*':

push(pop() * pop());

break;

case '-':

op2 = pop();

push(pop() - op2);//push(pop() - pop());是错误的,虽然算法运算符中操作数的结合方式是从左到右

//但是不能确定push参数中左边的pop函数一定比右边的pop函数先执行

break;

case '/':

op2 = pop();

if(op2 != 0.0)

push(pop() / op2);

else

{

printf("error: divide 0.0!");

return -1;

}

break;

case '%':

op2 = pop();

if(op2 != 0.0)

push(fmod(pop(), op2));

else

printf("error: mod 0.0!");

break;

case '/n'://当键入换行符时,打印输出栈顶元素

/*if(sp > 0)

printStack(val);

else

printf("error: stack empty!/n");

*/

printf("the result = %.8g/n", pop());

break;

case 'p'://不出栈的情况下,打印栈顶元素

op2 = pop();

printf("the top element of stack = %f/n", op2);

push(op2);

break;

case 'd'://复制栈顶元素

op2 = pop();

//tmp = op2;

//printf("the duplication of top element = %f/n", op2);

push(op2);

push(op2);

printf("the duplication of top element = %f/n", op2);

break;

/*case 'S':

push(sin(pop()));

break;

case 'E':

push(exp(pop()));

break;

case 'P':

op2 = pop();

push(pow(pop(), op2));

break;

*/

case NAME://处理数学函数分支,这样比上面分别用每个命令来定义一个函数要通用,并容易扩展

mathfnc(s);

break;

case 's'://交换栈顶元素

op2 = pop();

op1 = pop();

push(op2);

push(op1);

break;

case 'c'://清空堆栈

clear();

break;

default:

printf("error: unknown command %s", s);

break;

}

}

return 0;

}

#defineMAXVAL100//栈val的最大深度

int sp = 0;//栈中的下一个空闲的位置

double val[MAXVAL];//值栈

void push(double f)//把f压入值栈中

{

if(sp < MAXVAL)

val[sp++] = f;

else

printf("error: stack full, can't push %g/n", f);

}

double pop()//从值栈中弹出并返回栈顶的值

{

if(sp > 0)

return val[--sp];

else

{

printf("error: stack empty, can't pop/n");

return 0.0;

}

}

/*void printStack(double* val)

{

printf("top of stack = %f/n", val[sp-1]);

}

*/

void clear()//清空值栈

{

sp = 0;

return;

}

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);

}

getop.c

#include

#include

#include

#include "getop.h"

//extern NUMBER;

#defineNUMBER'0'

#defineNAME'n'

int getop(char s[])//获取下一个运算符或操作数

{

int i;

int c;

while((s[0] = c = getch()) == ' ' || c == '/t')

;

s[1] = '/0';

i = 0;

if(c != '-' && !islower(c) && !isdigit(c) && c != '.')//判断是否属于这四种情况,如不是,下面分别对这四种情况处理

return c;//当是运算符时,返回此运算符的ASCII值

if(c == '-')

if(isdigit(c = getch()) || c == '.')

s[++i] = c;

else

{

if(c != EOF)

ungetch(c);

return '-';

}

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 s[0]; //错误:return c; 例:s = "v ",则

//返回空格,而本意是返回v

}

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);

return NUMBER;//当是操作数时,返回NUMBER,标识这种情况

}

#defineBUFSIZE100//缓冲区的最大长度

//int buf[BUFSIZE];//这样可以正确处理压回EOF(-1)及其他任何负数的情况

char buf[BUFSIZE];//用于ungetch函数的缓冲区

int bufp = 0;//buf中下一个空闲位置

int getch()//取一个字符(可能是要压回的字符)

{

return (bufp > 0) ? buf[--bufp] : getchar();

}

void ungetch(int c)//把字符压回到输入(缓冲区)中

{

if(bufp >= BUFSIZE)

printf("ungetch: too many characters/n");

else

buf[bufp++] = c;

}

getop.h

#ifndef_GETOP_H_

#define_GETOP_H_

//#include

//#include

//#include

//#defineMAXOP100

//#defineNUMBER'0'

int getch();

void ungetch(int);

int getop(char []);

#endif

分析:

1,  程序设计:在设计本程序时,首先进行模块划分,

main.c:main函数 实现操作数压栈,出栈,算术运算,数学运算,打印 复制 交换栈顶元素等基本操作;

push函数 实现将double型数据压入值栈val中;

pop函数 实现将值栈val中的栈顶元素出栈;

clear函数 实现清空值栈val;

mathfnc函数 实现sin,cos, exp, pow等数学操作(调用math.h中的这些库函数来处理val中的数据

并非自定义上述函数);

getop.c:  getop函数 实现从输入中获取一个操作数或操作符(* + - / % sin d 等操作符);

getch函数 实现从自定义的输入缓冲区(buf)或操作系统定义的输入缓冲区中读入一个字符;

ungetch函数 实现将字符压回到自定义的输入缓冲区(buf)中;

getop.h:  声明getop getch ungetch函数。

2,  main函数中通过while((type = getop(s)) != EOF)处理每次从待处理的输入字符串中获取的s,这是程序的主干部分

在确定type != EOF时,通过switch - case 语句分别处理当type为  NUMBER + - * / % /n p d NAME s c default

等情况。

3,  对于 -  / % 情况不能像 + * 情况直接使用push(pop() - pop()),因为不满足交换律,

虽然算法运算符中操作数的结合方式是从左到右,但是不能确定push参数中左边的pop函数一定比右边的pop函数先执行

4,  getop函数,通过while((s[0] = c = getch()) == ' ' || c == '/t') ; 来跳过s头部的空白字符(空格,水平制表符),

每次对于第一个字符c通过判断(c != '-' && !islower(c) && !isdigit(c) && c != '.')这四种情况来分别处理,

若上述条件成立,表明c是一个例如 + - * /等单字符的操作符;

然后分四种情况:c == '-', islower(c), isdigit(c), c == '.' 进行处理。

注意:将最后一个读入的不符合条件的字符压回到自定义的输入缓冲区中。

getch函数: (bufp > 0) ? buf[--bufp] : getchar(); 从自定义输入缓冲区或OS定义的输入缓冲区中读入一个字符

ungetch函数:把字符压回到自定义的输入缓冲区中

5,  在合适的位置定义变量,例如:getop.c中BUFSIZE,buf,bufp在getop函数没有用到,而只在getch及ungetch函数

中用到,故其定义的位置在getop函数之后,而在getch函数之前,这样就可以防止在getop函数中出现无意修改上述变量

的可能。

确定某些文件用到哪些头文件,例如在在getop.c中用到isdigit等判断字符的函数,故在它里面添加ctype.h头文件,而在

main.c中不用到ctype.h中的库函数,故在main.c中不添加ctype.h头文件。

6,  如果想要ungetch函数正确处理压回的EOF或其他任何负数,则将输入缓冲区buf设置为int buf[BUFSIZE],即缓冲区的

数据类型为int型而不是char型。

C语言不要求char变量是signed或unsigned类型的,当把一个char型变量转换成int型变量,结果可能为正也可能为负,

例如,十进制的-1被表示为十六进制为0XFFFF(假定为一台16位机),当把0XFFFF保存到一个char型变量里去时,实际

被保存的数字是0XFF,当把0XFF转换成一个int型数据时,它可能被转换成0X00FF(255),也可能被转换成0XFFFF(-1)

所以打算对待像其他字符那样对待EOF时,应该把输入缓冲区buf声明成一个int型数组。

注:在某些机器上,如果一个char型变量的最高(左)二进制位为1,那么把它转换成一个int型数据时,就会在它的高位上

添加一系列1,这样得到的结果为负数;

在另一些机器上,当需要把一个char型变量转换成一个int型数据时,系统会在它的高位上添加一系列0,这样不管被

转换的char型变量的最高位是1还是0,结果永远是个正数。

c语言逆波兰计算器程序,逆波兰计算器(C语言)相关推荐

  1. java 简单的计算器程序,Java 简易计算器程序

    最近开始学习java,参考教科书写了一个简单的计算器程序,贴上来,以便有用的时候可以参考. 呵呵,哈哈!!! import java.awt.Container; import java.awt.Fl ...

  2. c语言日期计算器程序代码,旧计算器(C语言代码)

    #### 原题链接:[题目486 - ACM在线评测系统](http://nyoj.top/problem/486 "nyoj在线评测") #### 原题内容: **题目描述:** ...

  3. java体重指数计算器程序_java 学习 ——计算器小程序

    简易计算器小程序代码: package jisuanqi; //声明需要插入的包 import java.awt.*; import java.lang.Object; import java.lan ...

  4. c语言键盘连续双击程序,编了个C语言的键盘程序有点问题,请指点下!

    编了个C语言的键盘程序有点问题,请指点下! [复制链接] 做了个机械手,想用键盘来控制抓,放物品,现在他显示字符时有点错,高手能帮我在keil里跑下,把我的这个错改下吗?谢谢了!原程序如下:(P2.0 ...

  5. C语言编写一个赋值程序,实验2 用C语言编写简单程序——2.1 基本数据处理.doc

    实验2 用C语言编写简单程序--2.1 基本数据处理 实验2 用C语言编写简单程序 2.1 基本数据处理 [实验目的] (1)掌握算术表达式和赋值表达式的使用. (2)掌握基本输出函数的使用. (3) ...

  6. 百一测评c语言两个数求和程序,2017计算机二级C语言考前测试题与答案

    2017计算机二级C语言考前测试题与答案 三.程序修改题 下列给定程序中函数fun的功能是:将长整型数中各位上为奇数的数依次取出,构成一个新数放在t中.高位仍在高位,低位仍在低位. 例如,当s中的数为 ...

  7. 《C语言实战教学》:程序式思维及C语言介绍

    课程介绍 大家好,欢迎来到"C语言实战教学".随着互联网的发展,世面上已经出现了很多C语言的课程,质量差的有,质量好的也不少,但是,绝大部分都是盯着C语言讲,很少有结合各方面实际情 ...

  8. c语言程序设计勘误,《程序设计基础教程(C语言)》勘误表

    <<程序设计基础教程(C语言)>勘误表>由会员分享,可在线阅读,更多相关<<程序设计基础教程(C语言)>勘误表(2页珍藏版)>请在人人文库网上搜索. 1 ...

  9. 如何用c语言编写stm32的程序吗,STM32入门C语言详解

    <STM32入门C语言详解>由会员分享,可在线阅读,更多相关<STM32入门C语言详解(6页珍藏版)>请在人人文库网上搜索. 1.最新 料推荐阅读 flash : 芯片内部存储 ...

最新文章

  1. 2021年大数据Spark(三十五):SparkStreaming数据抽象 DStream
  2. sybase Invalid command line argument 'and'.
  3. Thinkpad W520 完美安装Ubuntu14.04LTS
  4. 单应性矩阵求解函数findHomography()
  5. 增加XP的IIS连接数,解决403.9连接用户过多的问题
  6. SpringBoot 自定义Kafka消息序列化和反序列化
  7. TCP/IP(五):TCP 协议详解
  8. [转]Hadoop集群_WordCount运行详解--MapReduce编程模型
  9. linux sudo 版本,Linu下如何升级当前sudo版本
  10. postgresql成本因子调整
  11. 归并排序 c++_数据结构:排序(4)||有序表的归并(归并排序)、基数排序
  12. Linux基金会宣布成立Ceph基金会
  13. 基于Python和selenium 获取 公开的搜狐汽车 数据
  14. Win10秘笈:两种方式修改网卡物理地址(MAC)
  15. skyfire塞班_Symbian Foundation的灯光熄灭
  16. 关于浏览器被hao123劫持
  17. 【笑话】程序员和青蛙公主
  18. 学嵌入式为什么要学Linux?
  19. 对量子态和运算的一些基础认识
  20. Python之print打印

热门文章

  1. oraclestddev函数_ORACLE分组函数stddev和variance,我心存的疑问
  2. 两个surfaceview重叠显示
  3. mysql摧毁重建_mysql数据文件破坏后的修复方法
  4. Hololens开发探索总结(介绍篇)
  5. K7中使用VDMA设计video system
  6. 视觉里程计Visual Odometry(VO)
  7. 从伦敦金中学习爆仓的原因
  8. Java 生成一张带文字的图片,并写入Word文档
  9. 拷贝构造函数和赋值函数
  10. 用Python显示真实的星空