C语言,简单计算器【上】
由于工作需要最近在研究PHP扩展,无可避免的涉及到了C语言。从出了学校以后C语言在实际工作中还没有用到过,所以必须要先进行一点复习工作。个人认为对于熟悉一样东西说最好的方法是上手实践。于是便想起了当时大学的时候老师布置过的一道题目,用C语言实现简单数学表达式的分析和求值,比较遗憾的是当初没能把题目完成。就想着从新试一试,算是补一下当初的作业。
还记得当初的思路是,循环C字符串。用链表将不同的计算项存储到链表中。然后在进行循环求值。如果遇到括号就递归调用。回忆并整理了一下当初的思路大致如下。
1.输入 3+5*(2-6)/2
2.解析为
3.计算 通过两次循环对不同优先级进行运算得出结果
第一次对*/进行计算,拿当前节点,和节点的next节点,求值后将值赋给next节点,并删除自身节点
第二次对+-进行求值,直到遇到end
最初也打算按这个思路去实现的,之后发现解析的步骤会比较复杂,涉及到多次的字符串搜索,比对。再加上C本身不支持正则表达式,所以就放弃了当初的思路。找了一些相关的资料后发现了一种更简单也更科学的方法,那就是将输入转换成后缀表达式再进行求值,这后缀表达式究竟是什么呢,请继续看下去。
一、后缀表达式
百度百科介绍: 不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则,如:(2 + 1) * 3 , 即2 1 + 3 *
了解了后缀表达式才知道,原来我们习以为常的数学表达式被称之为中缀表达式。花了点时间研究了一下发现后缀表达式的计算还蛮简单的,也更符合计算机运算。
计算方法,从左往右进行计算。取运算符号前两位数字进行运算,运算结果替代运算符以及前两位数字,持续运算到最右边得出结果。
这么说起来可能比较难理解,我们看几个例子
最简单的 21+
计算过程为 2 + 1 = 3
值为 3
普通的 325-2*+
计算过程 从左往右先计算 2-5=-3,-3取代前面的25-之后为 3-32*+,完整的计算步骤如下
计算2-5=3 计算完之后表达式为 3 -3 2 *+
计算-3*2=-6 计算完之后表达式为 3 -6 +
计算3+-6=-3 计算完之后表达式为 -3
值为 -3
稍微复杂一点的 21+3*5387-/*-
计算过程 从左往右先计算 2+1 = 3,4取代前面的21+之后为 33*5387-/*- 完整的计算步骤如下
计算2+1=3 计算完之后表达式为 3 3 *5 3 8 7 -/*-
计算3*3=9 计算完之后表达式为 9 5 3 8 7 -/*-
计算8-7=1 计算完之后表达式为 9 5 3 1 /*-
计算3/1=3 计算完之后表达式为 9 5 3 *-
计算5*3=15 计算完之后表达式为 9 15 -
计算9-15=-6 结果为 -6
值为 -6
看完了以上结果,我们会发现每一次参与计算的数字,都是最靠近运算符号的两位数字。然后由运算出来的结果代替参与运算的数字和运算符,直到表达式只剩下一个值,计算完成。
根据这样的规律,程序处理起来就简单了。
1.从左往右的循环整个输入。
2.判断是否是数字,如果是数字就保存起来。如果遇到符号,则把保存的前两个值取出来,计算后把本次计算结果存回去
3.循环完成之后,剩下的表达式便是计算结果了
根据如上规则不难发现每次参与计算的两个数字都是最后存进去的,这样一来我们便可以用栈轻松的完成这样一个程序了,下面跟大家简单介绍一下栈。
二、栈
百度百科的解释比较复杂,就不摘抄了。其实栈可以简单的理解为一个存放数据的空间,数据按照后进先出的原则进行存取。对数据的操作有push和pop,分别称之为压入,弹出。
由于比较简单,所以直接用代码实现了一个简单的栈,包含如下四个方法。

简单的进行测试,输入结果为
item is : 1.120000
item is : 2.800000
2.800000
1.120000
实现了预期输出,一个简单的栈就搞定了,接下来就可以利用整个简单的栈来完成求值的函数了。
三、后缀表达式求的具体实现
由于栈已经实现了,所以只需要按照后缀表达式求值的逻辑进行运算在配合栈就可以实现整个计算过程了。方法比较简单,用while循环整字符串,在配合switch对数字和运算符做不同的处理就能够完成一个简单的后缀表达式求值函数了。以下是第一版的实现代码

在第一个版本的过程中,遇到一个C语言知识点是 C语言的字符串指针指向的地址是字符串第一个字符的地址。
所以当i为0的时候,&str[i] = &str, atof 接收的是一个字符串指针,如果使用 STACKpush(atof(&str[i])),i为0时,会将整个字符串传入进去转换。采用了一个char变量,讲str[i]拷贝出来,然后传入&num,则可以解决这个问题。
其实这段程序里还涉及到一个指针运算的知识点,但是这里的程序里涉及还比较简单易懂,后续还有更难的地方涉及到这个知识点,所以先放到后面再跟大家分享。
对上面的方法进行了测试,输入我们之前分析的三个表达式,得出结果如下
printf("%f\n", calculate("21+")); //3
printf("%f\n", calculate("325-2*+")); //-3
printf("%f\n", calculate("21+3*5387-/*-")); //-6
测试通过,跟之前的计算结果一直。以上便是一个简单的后缀表达式的计算程序了。进行了多几次的测试发现了一个小问题,就是目前无法进行多位数的识别。因为程序没一次都将一位数压入站内了。思考了一下在表达式的每个计算项上加了一个空格符作为数字的区分。变为 21 3 +这种形式,于是动手将代码做了一点小改动
在 switch 中加入了对空格的处理,以及多位数的处理
//如果遇到空格,则重置标志位
这样一来就可以识别多位数了。经测试
printf("%f\n", calculate("21 1+")); //22
printf("%f\n", calculate("2 11+")); //13
得到了正确的结果,整个简单计算器的第一步计算后缀表达式完成。
有兴趣的可以测试一下上的代码,如果遇到什么问题可以通过微信公众号反馈给我。
当然这个程序还有一些有待完善的地方。如表达式合法性检查,对小数的处理,以及对负数的处理等,暂时先预留着后续再跟大家分享如何实现以及会用到的知识点。
下一篇将为大家介绍简单数学表达式计算的第二步,如何实现将中缀表达式转换为后缀表达式。
欢迎大家关注微信公众号~

C语言,简单计算器【上】的更多相关文章
- C语言 · 简单计算器
算法提高 简单计算器 时间限制:1.0s 内存限制:512.0MB 问题描述 编程模拟计算器的加.减.乘.除功能,根据用户输入的运算符,对两个数进行运算.(要求switch语句) 输 ...
- 手搓一个C语言简单计算器。
#include <stdio.h> void xing(int shu); void biaoti(int kong,char * title); void zhuyemian(char ...
- c 语言简单计算器源码
// main.c // 计算器 // Created by qianfeng on 14-7-15. // Copyright (c) 2014年 ___FGY___. All rights ...
- C语言实现简单计算器小项目
昨天刚安装上devc++,半夜想着练练C语言吧 于是就看到实验楼有一个计算器的项目 之前做过一次,这次写的主要是思路 首先我们先从原理思考jia,实现简单的计算器就要具备加减乘除这些,看普通的计算器也 ...
- 李洪强漫谈iOS开发[C语言-042]-简单计算器
李洪强漫谈iOS开发[C语言-042]-简单计算器
- Java语言编写计算器(简单的计算器)
Java编写的一个简单计算器,本人还比较菜,只能这样了,有点代码冗余,不能连续计算. import javax.swing.*; import java.awt.*; import java.awt. ...
- 简单计算器 (c语言课程设计)
可以实现简单的加减乘除四则运算 #include<stdio.h> #include<string.h> #define MAX 10100 int main() { int ...
- 大一C语言结课设计之《简单计算器》
/*===============================================*\ ** 设计目的:简单计算器,计算形如10*(20.2-30.6)+5.0/2的表达式值 ** 简 ...
- 1.C#WinForm基础制作简单计算器
利用c#语言编写简单计算器: 核心知识点: MessageBox.Show(Convert.ToString(comboBox1.SelectedIndex));//下拉序号 MessageBox.S ...
随机推荐
- Wmap5 测试80端口 Your port 80 is actually used by :Server: Microsoft-HTTPAPI/2.0
问题:win7系统! 在wamp5的apache启动不了: 目录下点击[测试80端口]的时候提示:Your port 80 is actually used by : Server: Microsof ...
- 实验五 burpsuite重放攻击实验
一.实验目的 使用burpsuite软件实现重放攻击. 二.实验准备 1.笔记本电脑一台,安装vmware虚拟机和windows XP系统,下载安装burpsuite professional v1. ...
- Idea连接服务器docker并部署代码到docker实现一键启动
好记性不如烂笔头,写笔记是为了回头看的. 谁要是不小心搜了看了,如有不足之处敬请谅解. 一.准备工作 虚拟机centos7.X,docker1.3.X,Win10 Idea2018.1 默认Idea已 ...
- Mondriaan's Dream(poj 2411)
题意:在n*m的方格里铺1*2的骨牌,有多少种方案 /* 第一次做插头DP,感觉和状压差不多. 这道题是利用上一行的状态来更新下一行的状态. 1代表上一行这个位置填了一个竖的(即本行可以填): 0代表 ...
- 慕课 python 操作数据库2 银行转账实例
CREATE TABLE `account` ( `acctid` ) DEFAULT NULL COMMENT '账户ID', `) DEFAULT NULL COMMENT '余额' ) ENGI ...
- sql server 2008导入和导出sql文件
导出表数据和表结构sql文件 在日常的开发过程中,经常需要导出某个数据库中,某些表数据:或者,需要对某个表的结构,数据进行修改的时候,就需要在数据库中导出表的sql结构,包括该表的建表语句和数据存储语 ...
- 关于vsftp所遇问题
问题:使用ftp工具上传文件时提示 553 Could not create file.错误: 严重文件传输错误解决方法:除了检查ftp服务外,需要使用 getsebool -a|grep ftp, ...
- Servlet 2.4 规范之第五篇:请求
request对象封装了来自客户端的所有请求信息.在HTTP协议中,客户端发给服务端的所有信息都是通过request对象的请求头和请求体来传送的. SRV.4.1 HTTP协 ...
- hdu 5701(区间查询思路题)
中位数计数 Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Subm ...
- Codeforces 553D Nudist Beach(二分答案 + BFS)
题目链接 Nudist Beach 来源 Codeforces Round #309 (Div. 1) Problem D 题目大意: 给定一篇森林(共$n$个点),你可以在$n$个点中选择若干个构 ...