由于工作需要最近在研究PHP扩展,无可避免的涉及到了C语言。从出了学校以后C语言在实际工作中还没有用到过,所以必须要先进行一点复习工作。个人认为对于熟悉一样东西说最好的方法是上手实践。于是便想起了当时大学的时候老师布置过的一道题目,用C语言实现简单数学表达式的分析和求值,比较遗憾的是当初没能把题目完成。就想着从新试一试,算是补一下当初的作业。

还记得当初的思路是,循环C字符串。用链表将不同的计算项存储到链表中。然后在进行循环求值。如果遇到括号就递归调用。回忆并整理了一下当初的思路大致如下。

1.输入 3+5*(2-6)/2

2.解析为

3.计算 通过两次循环对不同优先级进行运算得出结果

第一次对*/进行计算,拿当前节点,和节点的next节点,求值后将值赋给next节点,并删除自身节点

第二次对+-进行求值,直到遇到end

最初也打算按这个思路去实现的,之后发现解析的步骤会比较复杂,涉及到多次的字符串搜索,比对。再加上C本身不支持正则表达式,所以就放弃了当初的思路。找了一些相关的资料后发现了一种更简单也更科学的方法,那就是将输入转换成后缀表达式再进行求值,这后缀表达式究竟是什么呢,请继续看下去。

一、后缀表达式

百度百科介绍: 不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则,如:(2 + 1) * 3 , 即2 1 + 3 *

了解了后缀表达式才知道,原来我们习以为常的数学表达式被称之为中缀表达式。花了点时间研究了一下发现后缀表达式的计算还蛮简单的,也更符合计算机运算。

计算方法,从左往右进行计算。取运算符号前两位数字进行运算,运算结果替代运算符以及前两位数字,持续运算到最右边得出结果。

这么说起来可能比较难理解,我们看几个例子

  1. 最简单的  21+

    1. 计算过程为 2 + 1 = 3

    2. 值为 3

  2. 普通的 325-2*+

    1. 计算过程 从左往右先计算 2-5=-3,-3取代前面的25-之后为 3-32*+,完整的计算步骤如下

    2. 计算2-5=3    计算完之后表达式为 3 -3 2 *+

    3. 计算-3*2=-6  计算完之后表达式为 3 -6 +

    4. 计算3+-6=-3  计算完之后表达式为 -3

    5. 值为 -3

  3. 稍微复杂一点的  21+3*5387-/*-

    1. 计算过程 从左往右先计算 2+1 = 3,4取代前面的21+之后为 33*5387-/*- 完整的计算步骤如下

    2. 计算2+1=3    计算完之后表达式为 3  3 *5 3 8 7 -/*-

    3. 计算3*3=9     计算完之后表达式为 9  5  3  8 7 -/*-

    4. 计算8-7=1     计算完之后表达式为 9  5  3  1 /*-

    5. 计算3/1=3     计算完之后表达式为 9  5 3  *-

    6. 计算5*3=15   计算完之后表达式为 9 15 -

    7. 计算9-15=-6 结果为 -6

    8. 值为 -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语言,简单计算器【上】的更多相关文章

  1. C语言 · 简单计算器

    算法提高 简单计算器   时间限制:1.0s   内存限制:512.0MB      问题描述 编程模拟计算器的加.减.乘.除功能,根据用户输入的运算符,对两个数进行运算.(要求switch语句) 输 ...

  2. 手搓一个C语言简单计算器。

    #include <stdio.h> void xing(int shu); void biaoti(int kong,char * title); void zhuyemian(char ...

  3. c 语言简单计算器源码

    //  main.c //  计算器 //  Created by qianfeng on 14-7-15. //  Copyright (c) 2014年 ___FGY___. All rights ...

  4. C语言实现简单计算器小项目

    昨天刚安装上devc++,半夜想着练练C语言吧 于是就看到实验楼有一个计算器的项目 之前做过一次,这次写的主要是思路 首先我们先从原理思考jia,实现简单的计算器就要具备加减乘除这些,看普通的计算器也 ...

  5. 李洪强漫谈iOS开发[C语言-042]-简单计算器

    李洪强漫谈iOS开发[C语言-042]-简单计算器

  6. Java语言编写计算器(简单的计算器)

    Java编写的一个简单计算器,本人还比较菜,只能这样了,有点代码冗余,不能连续计算. import javax.swing.*; import java.awt.*; import java.awt. ...

  7. 简单计算器 (c语言课程设计)

    可以实现简单的加减乘除四则运算 #include<stdio.h> #include<string.h> #define MAX 10100 int main() { int ...

  8. 大一C语言结课设计之《简单计算器》

    /*===============================================*\ ** 设计目的:简单计算器,计算形如10*(20.2-30.6)+5.0/2的表达式值 ** 简 ...

  9. 1.C#WinForm基础制作简单计算器

    利用c#语言编写简单计算器: 核心知识点: MessageBox.Show(Convert.ToString(comboBox1.SelectedIndex));//下拉序号 MessageBox.S ...

随机推荐

  1. C语言实验报告二

    实验一:第11次实验作业报告 题目:方阵循环右移 实验要求:将给定n×n方阵中的每个元素循环向右移m个位置,即将第0.1.⋯.n−1列变换为第n−m.n−m+1.⋯.n−1.0.1.⋯.n−m−1列. ...

  2. 网易2016 实习研发工程师 [编程题]寻找第K大 and leetcode 215. Kth Largest Element in an Array

    传送门 有一个整数数组,请你根据快速排序的思路,找出数组中第K大的数. 给定一个整数数组a,同时给定它的大小n和要找的K(K在1到n之间),请返回第K大的数,保证答案存在. 测试样例: [1,3,5, ...

  3. 标准C程序设计七---32

    Linux应用             编程深入            语言编程 标准C程序设计七---经典C11程序设计    以下内容为阅读:    <标准C程序设计>(第7版) 作者 ...

  4. 變更 cut-off,termination current,截止電流 對 battery capacity 的影響

    依之前的經驗 2700mAh 電池 cut-off 由 128 降至 64 mA,充電時間延長 20 分鐘, (128 + 64)/2 = 96 取平均充電流, 96 * (20/60) = 32 m ...

  5. (3)unity3d 地形

    在Hierarchy(层次) 建一个Terrain(地形) Terrain属性按钮 第一个按钮:抬升与下陷地面.单击抬升地形,同时按住shift下陷地形 第二个按钮:绘制高度.同时按住shift绘制等 ...

  6. make makefile cmake qmake都是什么,有什么区别

    原文:https://www.zhihu.com/question/27455963 作者:玟清链接:https://www.zhihu.com/question/27455963/answer/36 ...

  7. (入门SpringBoot)SpringBoot结合redis(四)

    SpringBoot整合redis: 1.引入jar <!--  引入redis依赖 --><dependency>    <groupId>org.springf ...

  8. 访问权限修饰符Protected专题

    上图描述:A类在a包下,m()方法被protected修饰 上图描述:B类也在a包下,B类是A类的子类. 解析:B类和A类是同包类,B类是A类的子类,因此b对象可以调用m()方法. 上图描述:C类也在 ...

  9. 关于编写Windows程序中启动兼容性问题

    之前用qt4编写Windows程序的时候遇到了一个软件在系统的兼容性问题:用户在win10系统下使用这个程序的时候,如果没有用低于win10版本的兼容模式运行的时候,存在运行某部分功能的时候无法使用的 ...

  10. c++中.dll与.lib文件的生成与使用的详解

    两种库: • 包含了函数所在的DLL文件和文件中函数位置的信息(入口),代码由运行时加载在进程空间中的DLL提供,称为动态链接库dynamic link library.• 包含函数代码本身,在编译时 ...