这两天在看一个C语言写的计算器程序,做了不少的功夫,跟着作者一步步的进行完善,了解了许多细节性的东西,在此自己做个总结,加深自己对程序的印象,也算是梳理。

在该计算器程序,能进行加减乘除、sin、cos、exp等操作,同时能进行数值保存功能。而该计算器使用逆波兰表示法。即所有运算符都跟在操作数的后面,比如下列表达式:

(1 - 2) * (4 + 5)采用逆波兰表示法表示为:1 2 - 4 5 + *

逆波兰表达法中不需要圆括号,只要知道每个运算符需要几个操作数就不会引起歧义。

计算器程序实现很简单,具体原理如下:

while(/* 下一个运算符或操作数不是文件结束指示符 */)

if(/* 是数 */)

/* 将该数压入到栈中 */

else if (/* 是运算符 */)

/* 弹出所需数目的操作数 */

/* 执行运算 */

/* 将结果压入到栈中 */

else if (/* 是换行符 */)

/* 弹出并打印栈顶的值 */

else

/* 出错 */

在程序设计中,使用模块化思想,getop函数来进行读入,该函数返回一个标识,用来标识读入的是什么类型。主循环体中根据该标识执行相应的动作。

以下是该程序: (我将所有函数和变量放在同一文件)

#include

#include

#include

#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 divisor\n");

break;

case '%':

op2 = pop();

if (op2 != 0.0)

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

else

printf ("error: zero divisor\n");

break;

case '?': //打印栈顶元素

op2 = pop();

printf ("\t%.8g\n", op2);

push (op2);

break;

case '=': //保存数值

pop();

if (var >= 'A' && var <= 'Z')

variable[var - 'A'] = pop();

else

printf ("error: no variable name\n");

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%.8g\n", v);

break;

default:

if (type >= 'A' && type <= 'Z')

push(variable[type - 'A']);

else if (type == '@') //输入的字符@表示最近一次结果值

push(v);

else

printf ("error: unknown command %s\n", 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 %g\n", f);

}

double pop(void)

{

if (sp > 0)

return val[--sp];

else

{

printf ("error: statck empty\n");

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 supported\n", s);

}

/* ----------------------------------------------------------- */

#include

int getch(void);

void ungetch(int);

int getop(char s[])

{

int i, c;

while ((s[0] = c = getch()) == ' ' || c == '\t') //过滤开头的空白字符

;

s[1] = '\0';

i = 0;

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

}

if (!isdigit(c) && c != '.' && c != '-')

return c;

if (c == '-') //用于判断是负数还是减操作

{

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

s[++i] = c;

else

{

if (c != EOF)

ungetch(c);

return '-';

}

}

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;

}

/* ----------------------------------------------------------- */

/*

* 引用以下两个函数是因为:程序不能确定它已经读入的输入是否足够 *

* 除非超前多读入一些输入,在本程序中,读入一些字符合成一个数字 *

* 所以在看到第一个非数字字符之前,已经读入的数的完整性是不能确定的

* 由于程序要超前读入一个字符,这样就导致最后又一个字符不属于当前所要读入的数

*/

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

}

该程序虽然简单,但是还是存在一些小小的问题,比如没有数据时进行pop的话,会打印栈中无数据同时返回数值0.0,在循环体中许多执行操作会将该数值保存到栈中,之后打印该值,用户体验度比较差。程序设计方面,模块化设计使得该程序容易增加功能而不影响其他模块,比如增加一些数学函数处理,在mathfnc函数中去添加,或增加一些运算符操作,可以在主循环体中增加。

总之,这次学习还是颇有收获。

关于计算器的精彩文章请查看《计算器专题》 ,更多精彩等你来发现!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

c语言大作业计算器,C语言实现简单计算器程序相关推荐

  1. c语言大作业旋转,c语言大作业全-20210412035629.docx-原创力文档

    Document number:PBGCG-0857-BTDO-0089-PTT1998 Document number:PBGCG-0857-BTDO-0089-PTT1998 C语言大作业全 #i ...

  2. 有输入和输出的c语言大作业题目,C语言大作业题目2011.pdf

    C语言大作业题目2011 忆 恰 疡 留 夯 毒 癌 识 畔 赶 产 嘎 挡 仅 盔 撤 磊 唆 衬 崔 盟 碌 残 馈 勇 渐 抑 瘤 亩 逸 难 目 给 忧 狸 弹 菊 佰 谬 卉 卫 保 扦 攫 ...

  3. c语言大作业参考书,C语言大作业设计-

    <C语言大作业设计->由会员分享,可在线阅读,更多相关<C语言大作业设计-(17页珍藏版)>请在人人文库网上搜索. 1.常州工学院c语言作业设计规格标题:通信记录管理系统二级学 ...

  4. c语言大作业俄罗斯方块,C语言自己写俄罗斯方块(完整版)

    还记得大笨兔以前在博客发的几篇关于如何使用C语言写俄罗斯方块游戏的文章吗? 当时大笨兔已经将基本的逻辑写完了,但还有两个功能没有加进去:游戏结束和游戏暂停. 所以这次大笨兔抽空就将这两个功能加进去了. ...

  5. 等价关系运算c语言大作业,离散数学C语言上机题.doc

    离散数学C语言上机题 广东工业大学 计算机科学与技术 张法光 离散数学C语言上机题 Anyview 可视化编程作业系统 二元关系章节编程题 EX 01 6.01③ 试设计一算法, 实现集合的卡氏积运算 ...

  6. c语言大作业_2018 C语言大作业--21_Ekko制作教程

    同学们实现的效果: https://www.zhihu.com/video/1066249425780809728 以下是开发同学的相关文档: <Ekko>设计报告 本组设计并编写的游戏& ...

  7. c语言大作业万年历,C语言实现简单万年历

    本文实例为大家分享了C语言实现简单万年历的具体代码,供大家参考,具体内容如下 #include #include int year, month; int run[12] = { 31,29,31,3 ...

  8. 火车票售票系统C语言大作业,基于C语言实现简单的12306火车售票系统

    程序设计要求用C语言写一个简单的火车售票系统,主要实现的功能为: 录入班次信息 浏览班次信息 按班次号查询 按终点站查询 按余票数量排序保存 售票 退票 更新班次信息 退出系统 所有的班次信息保存在n ...

  9. 集美大学c语言大作业,集美大学c语言练习题

    集美大学c语言练习题 (4页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 9.9 积分 1运行程序,为什么结果会如此?⑴#include int main ...

  10. c语言大作业菜单管理,C语言大作业:编写菜单控制猜商品价格程序

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 改写猜价格游戏的程序(见下),实现对这个游戏的一些管理功能,可以根据菜单对商品进行添加.删除.查找.浏览等操作,根据模块间数据传递的方式分析各个模块的函数 ...

最新文章

  1. 沈向洋回答吴恩达:我预见的2021
  2. B+树索引和哈希索引的区别——我在想全文搜索引擎为啥不用hash索引而非得使用B+呢?...
  3. spring boot 2.0 集成shiro注意事项
  4. 用set和shopt设置bash选项
  5. Servlet验证码功能
  6. Python统计TXT词云
  7. 室内温湿度监测系统解决方案
  8. [Ext JS 4] 实战之 ComboBox 和 DateField 的点击事件在IE下失效
  9. tab vue 竖排_vue tab切换的几种方式
  10. JAVA:eclipse文本中文支持
  11. win10系统开启扫描仪服务器,win10通用扫描仪安装步骤
  12. Unity3D 2D设计小游戏移动幻影的实现
  13. Lua中的os.time和os.date以及时区计算
  14. Android开发如何进阶,薪资如何跟上年龄的脚步?,深度解读Netty
  15. 【新型密集采样网络:遥感超分】
  16. 如何用Diffusion models做interpolation插值任务?——原理解析和代码实战
  17. Vue3使用路由及配置vite.alias简化导入写法
  18. interview--- 帽子戏法
  19. 笔试逻辑智力题找规律题总结2
  20. 教育青少年计算机等级考试,《新编计算机等级考试培训教程 新一级》青少年素质教育丛书.pdf...

热门文章

  1. vulhub靶场sql注入漏洞复现
  2. netsh命令改IP和重置winsock(可解决能上QQ不能上网的问题)
  3. [Unity插件]Live2D插件学习
  4. 生于资本,死于泡沫,review ofo衰亡
  5. Python实战——为人脸照片添加口罩
  6. MFC学习心得第一篇
  7. Java基础知识笔记整理(零基础学Java)
  8. mysql 游标循环_MySQL 游标 循环
  9. idea 社区教育版需要安装的插件
  10. eweishop 人人商城区别_微擎开发之人人商城添加第三方支付系列