| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 3596 人关注过本帖, 1 人收藏
标题:自己编的简易计算器,可以运算+ - * / ()的表达式,可以计算小数
只看楼主 加入收藏
zhu224039
Rank: 8Rank: 8
等 级:贵宾
威 望:17
帖 子:862
专家分:792
注 册:2012-7-29
结帖率:59.52%
收藏(1)
已结贴  问题点数:14 回复次数:31 
自己编的简易计算器,可以运算+ - * / ()的表达式,可以计算小数
  #include "unistd.h"  /*头文件瞎搞的,对这个一直不了解*/
#include "stdlib.h"
#include "stdio.h"
struct a   /*存放字符和字符运算优先级*/
{
char ax[10];
char *top1;
char *base1;
int p1;
};
struct b   /*存放运算数*/
{
float bx[10];
float *top;
float *base;
};
struct a *p;
struct b *s;
int pan(char c)   /*判断运算优先级别*/
{
int i;
switch(c)
{
case '+':
i=1;
break;
case '-':
i=1;
break;
case '*':
i=2;
break;
case '/':
i=2;
break;
case '(':
i=3;
break;
case ')':
i=4;
break;
default :
printf("表达式错误,你妹\n");
exit(0);
}
return(i);
}
void init1(struct a *p)   /*初始化站*/
{
p->base1=p->ax;
p->top1=p->ax;
}
void init(struct b *s)
{
s->base=s->bx;
s->top=s->bx;
}
void pusha(struct a *p,char c)
{
*(p->top1)=c;
p->top1++;
p->p1=pan(c);
}
void pushb(struct b *s,float c)
{
*(s->top)=c;
s->top++;
}
char popa(struct a *p)
{
char c;
p->top1-=1;
c=*(p->top1);
return(c);
}
float popb(struct b *s)
{
float c;
s->top-=1;
c=*(s->top);
return(c);
}
int qunfen(char *st,float num[],char *st1)      /*从字符串中分离出数和运算符分别放在NUM【】和STR数组中*/
{
int j=0,o=0,m=0,t,z=0,u,x=0,n=0,l=0;
float f,f1=0;
float num1[10];
if((*(st+j)<'0'&&*(st+j)!='(')||(*(st+j)>'9'&&*(st+j)!='('))
{
printf("表达式错误11111\n");             /*读入字符串,起手不是数字和符号‘(’,表达式就是错误的*/
exit(1);
}
if(*(st+j)=='(')             /*对表达式的处理分两种情况,‘(’是字符起头的,和不是字符起头的*/
{                            /*是字符起头的要对其进行初始话,有考虑不写这段*/
z=1;
*st1=*st;
m++;
j++;
}
while(*(st+j)!='\0')                           /*对字符的循环读入操作*/
{
if((*(st+j)>='0'&&*(st+j)<='9')||*(st+j)=='.')   /*判断是否为数字 数字组成是有0-9和.构成*/
   {
     num1[o]=*(st+j)-'0';     /*ASCII码是从0是从48开始的,所以要得到数字必须减掉48,才是ASCII码 0 1 23*/
     t=o;                                /*t=o 主要是对读入数字的个数进行计数*/
     o++;                             /*o记录的是当前读入数字的下标,NUM数组将这些数字进行存放*/
     z=0;                        /*“z”主要是记录读入字符的个数的,字符个数除去遇到‘)’时 其值会曾到1以上*/
   }
else
   {
    if(z!=0&&*(st+j)!='('&&*(st+j)!=')')
    {
    printf("表达式错误xxxx:\n");   /*不是因为因为字符’(‘’)‘引起的Z!=0的情况都是错误的表达式*/     
    exit(1);                       /*例如"*("或者")+" 是正常的*/
     }
    else
    {
    if(z==0)      /*在这个地方计算数的原因是 这个选择分支代表上面数的读入结束*/
    {
    f=num1[0];               /*先读入的数字是数的最高位的,数字*10可以提高数的位 21=10*2+1来的*/
    for(u=1;u<=t;u++)       /*t是代表读入数的数组的最大下标 对于num1[0]他是最高的位 */
    {                      /*f记录每次10*f的值  比如 num[t]={12345}  f=1 f=10*f+num[u] 就可以表达成*/
    if(num1[u]>=0)      /*  f=10*1+2 f=12 通过循环把数用f记录下来*/
    f=10*f+num1[u];      /* 为什么要判断 num1[u]的值是否》0 主要是小数点.的ASCII码为46当num[u]<0*/
    else                 /*就要跳出循环去计算小数点后面的值*/                                    
    break;
    }
    if(u<t)                 /*计算小数点的值,F1存放*/
    {
     f1=num1[t]/10;
     t=t-1;
    for(;t>u;t--)  
    f1=(f1+num1[t])/10;
    }
    f=f1+f;
    f1=0;                   /*你说的问题在这个地方要对f1清零,用在下次存放小数*/
    num[x]=f;
    x++;
    o=0;
    }
    if(*(st+j)=='(') n++;
    else if(*(st+j)==')') l++;
    *(st1+m)=*(st+j);                 /*这个地方是对字符做的处理*/
     m++;z++;          /*z,读入1个字符实现自加,如果不是'(',')'造成的z=2的情况的话 表达式就是错误的*/
    }
   }
   j++;
   }
    if(n!=l)
    {printf("表达式错误!!!!");
     exit(0);
    }               /*while(循环体结束后因为只读入了数 而没有处理数 所以这里要重新处理数)*/
    f=num1[0];
    for(u=1;u<=t;u++){
    if(num1[u]>=0)
    {
    f=10*f+num1[u];
    }
    else
    break;
    }
    if(u<t)
    {
     f1=num1[t]/10;
     t=t-1;
    for(;t>u;t--)  
    f1=(f1+num1[t])/10;
    }
    f=f1+f;
    num[x]=f;
    *(st1+m)='\0';       /*一点不要忘记存入的字符结束标志存入*/
}
float jisuan(char c,float a1,float a2 )   /*计算*/
{
switch(c)
{
case '+':
a1=a1+a2;
break;
case '-':
a1=a2-a1;
break;
case '*':
a1=a1*a2;
break;
case '/':
a1=a2/a1;
break;
}
return(a1);
}
float jieguo(char *st,float num[])   /*通过两个栈分别放运算符和数据来进行运算*/
{
float a1,a2,jg1;        /*a1 a2取出的运算数, jg1存放运算结果  jg 是多余的*/
char c;
int i=0,j=2,n;
init1(p);
init(s);
if(*st=='(')               /*同样表达式要分起手是’(‘和不是的情况,是的话就不用放入操作数到栈里面 记住1个 字符对应两个数*/
{
pusha(p,*st);
i++;
}
pusha(p,*(st+i));          /*进入循环体前 数据的初始化*/
pushb(s,num[0]);
pushb(s,num[1]);
i++;
while(*(st+i)!='\0')
{
  n=pan(*(st+i));         /*数的优先级别的判定,分成3中情况 ’(‘和’)‘和其他*/
  if(n!=3&&n!=4)
  {
   if(n>p->p1)            /*优先级别大于栈中的优先级别 那么从数据中放入一个数到栈中 后再取出两个数进行操作*/
   {
   pushb(s,num[j]);       /*有想过从栈取一个数然后在从数组中取一个数进行运算,这样省一步入栈,觉得麻烦就没这么做*/
   a1=popb(s);
   a2=popb(s);
   jg1=jisuan(*(st+i),a1,a2);
   pushb(s,jg1);
   }
   else
   {
   a1=popb(s);   /*优先级小于等于的话 就得从栈中取两个数运算后把结果放进去 这样栈中只有1个操作数,所以要放入一个数*/
   a2=popb(s);     /*运算符也少了1个,所以要进仓*/
   c=popa(p);
   jg1=jisuan(c,a1,a2);
   pushb(s,jg1);
   pushb(s,num[j]);
   pusha(p,*(st+i));
   }
   i++;          /*因为所以的操作都花掉了数据NUM和运算符一个, 所以都得指向下一个要操作的数和运算符*/
   j++;
  }
  if(n==3)
  {                         /*为'('的时候  不需要进行运算但是得放入两个数和一个运算符 为下一次运算初始话*/
   pusha(p,*(st+i));
   pusha(p,*(st+i+1));
   i=i+2;
   pushb(s,num[j]);         /*老师这个地方做了更改的,因为上面的操作已经放了一个数 所以这个地方只用放一个数字*/
   j++;
   }
   else if(n==4)             /*为')'的时候   '(' ‘)’里面肯定是有两个数和1个运算符 */
   {
    a1=popb(s);
    a2=popb(s);
    c=popa(p);
    jg1=jisuan(c,a1,a2);
    pushb(s,jg1);
    popa(p);
    i++;
    if(p->top1==p->base1)      /*运算完了就得判断表达式的情况了,如果没有运算符了,这个时候就只有1个数了*/        
      {
      if(*(st+i)!='\0')        /*判断还有木有运算符,有的话就放1个数 1个运算符*/
      {
      pusha(p,*(st+i));
      pushb(s,num[j]);
      j++;
      i++;
      }
      }
   }
}
if((s->top-s->base)!=1)    /*元算完后 要么只有1个数在栈中,要么就是2个数在数据栈中 1个操作符在运算符栈里*/
{                             /*因为+-/*都是双目运算符*/
a1=popb(s);
a2=popb(s);
c=popa(p);
jg1=jisuan(c,a1,a2);
}
return(jg1);
}

int main()
{
char *st,*st1,num4[20],num5[10];
float num[10],zjg;
st=num4;
st1=num5;
s=(struct b*)malloc(sizeof(struct b));
p=(struct a*)malloc(sizeof(struct a));
printf("请输入表达式:\n");
scanf("%s",st);
qunfen(st,num,st1);
zjg=jieguo(st1,num);
printf("%f\n",zjg);
}


老师您给再看看  这次 全改好了,自己的算法图 对着代码全部都检查过了,您给再挑挑毛病把。


[ 本帖最后由 zhu224039 于 2012-8-21 21:26 编辑 ]
搜索更多相关主题的帖子: default include 表达式 优先级 
2012-08-21 02:21
stophin
Rank: 7Rank: 7Rank: 7
等 级:黑侠
威 望:3
帖 子:227
专家分:618
注 册:2010-3-26
收藏
得分:0 
我也有用栈写过一个,握爪
我把qufen函数中处理完成的num和st1数组打印出来,
发现有好多bug,比如3.14+2结果它变成3.140000和2.140000相加,
图片附件: 游客没有浏览图片的权限,请 登录注册

看来是while循环中f1没有清0
另外3+2-(19*9-2),为什么会多出两个"2"来呢
图片附件: 游客没有浏览图片的权限,请 登录注册

上面的6是num数组最大下标,但实际是只有4,做到最后会出现问题:
本来是5-169的,但括号中计算出169后,入栈169,但因为后面还有一个2,
所以将2入栈,最后应该计算-,那么就是最后入栈的2减去169,最后计算出错。
所以我帮你如下改:
图片附件: 游客没有浏览图片的权限,请 登录注册

看来是"2-("这样时,"-"做一次,存入2,"("再做一次,再存入2。循环最后面判断'2'!=')',存入2,循环结束再存入2。
改正确后结果错了,可能是计算算法有问题。
2012-08-21 13:03
zhu224039
Rank: 8Rank: 8
等 级:贵宾
威 望:17
帖 子:862
专家分:792
注 册:2012-7-29
收藏
得分:0 
谢谢提醒,昨晚编完就用整数测试了下

我要成为嘿嘿的黑客,替天行道
2012-08-21 15:54
zhu224039
Rank: 8Rank: 8
等 级:贵宾
威 望:17
帖 子:862
专家分:792
注 册:2012-7-29
收藏
得分:0 
你说的问题 我大体知道了,算法上没问题,主要还是区分数据上有所错误

我要成为嘿嘿的黑客,替天行道
2012-08-21 15:55
zhu224039
Rank: 8Rank: 8
等 级:贵宾
威 望:17
帖 子:862
专家分:792
注 册:2012-7-29
收藏
得分:0 
你说的一点没错哟,是计算小数的变量f1 没有清零导致的

我要成为嘿嘿的黑客,替天行道
2012-08-21 15:58
zhu224039
Rank: 8Rank: 8
等 级:贵宾
威 望:17
帖 子:862
专家分:792
注 册:2012-7-29
收藏
得分:0 
跟一句 为什么要用WINDOWS呢,这是为什么!!!!!!!!!!!

我要成为嘿嘿的黑客,替天行道
2012-08-21 17:41
stophin
Rank: 7Rank: 7Rank: 7
等 级:黑侠
威 望:3
帖 子:227
专家分:618
注 册:2010-3-26
收藏
得分:0 
unistd.h是在linux下用的
跟windows.h相同,把它改成windows.h就可以在windows下编译运行
为什么要用windows,是因为我只有windows没有linux
2012-08-21 19:58
zhu224039
Rank: 8Rank: 8
等 级:贵宾
威 望:17
帖 子:862
专家分:792
注 册:2012-7-29
收藏
得分:0 
老师   老师  我头要爆炸了,我还在调试程序


我要成为嘿嘿的黑客,替天行道
2012-08-21 20:15
zhu224039
Rank: 8Rank: 8
等 级:贵宾
威 望:17
帖 子:862
专家分:792
注 册:2012-7-29
收藏
得分:0 
回复 6楼 zhu224039
给再看看   我这次修改了,你举例的算术结果对上了,自己也捏造了好几个公式 还可以。初学C语言的,浏览了下书就看的数据结构,这个代码写出来,也是磕磕绊绊的,大部分都浪费在语法调试上了。有什么编程方面的经验多教教徒弟我塞。

我要成为嘿嘿的黑客,替天行道
2012-08-21 21:34
stophin
Rank: 7Rank: 7Rank: 7
等 级:黑侠
威 望:3
帖 子:227
专家分:618
注 册:2010-3-26
收藏
得分:0 
初学c语言,这个代码写出来已经很了不起了
还有,貌似没有多少儿人回嘛,欢迎使用BCCN单机版....
2012-08-22 09:07
快速回复:自己编的简易计算器,可以运算+ - * / ()的表达式,可以计算小数
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.028484 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved