C语言,简单计算器【上】

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

 

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

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

 

    2.解析为 测试

        

    3.计算 经过两次循环对不一样优先级进行运算得出结果spa

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

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

 

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

 

1、后缀表达式递归

百度百科介绍: 不包含括号,运算符放在两个运算对象的后面,全部的计算按运算符出现的顺序,严格从左向右进行(再也不考虑运算符的优先规则,如:(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.循环完成以后,剩下的表达式即是计算结果了

    根据如上规则不难发现每次参与计算的两个数字都是最后存进去的,这样一来咱们即可以用栈轻松的完成这样一个程序了,下面跟你们简单介绍一下栈。

 

2、栈

    百度百科的解释比较复杂,就不摘抄了。其实栈能够简单的理解为一个存放数据的空间,数据按照后进先出的原则进行存取。对数据的操做有push和pop,分别称之为压入,弹出。

 

    因为比较简单,因此直接用代码实现了一个简单的栈,包含以下四个方法。

    

 

 

    简单的进行测试,输入结果为

    item is : 1.120000

    item is : 2.800000

    2.800000

    1.120000

    实现了预期输出,一个简单的栈就搞定了,接下来就能够利用整个简单的栈来完成求值的函数了。

 

3、后缀表达式求的具体实现

 

    因为栈已经实现了,因此只须要按照后缀表达式求值的逻辑进行运算在配合栈就能够实现整个计算过程了。方法比较简单,用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

    获得了正确的结果,整个简单计算器的第一步计算后缀表达式完成。

    有兴趣的能够测试一下上的代码,若是遇到什么问题能够经过微信公众号反馈给我。

    固然这个程序还有一些有待完善的地方。如表达式合法性检查,对小数的处理,以及对负数的处理等,暂时先预留着后续再跟你们分享如何实现以及会用到的知识点。

    下一篇将为你们介绍简单数学表达式计算的第二步,如何实现将中缀表达式转换为后缀表达式。

  

  欢迎你们关注微信公众号~

 

  

相关文章
相关标签/搜索