zoukankan      html  css  js  c++  java
  • 支持括号、分数计算的四则运算计算器

    用C语言实现的带括号四则运算计算器,原理简单,即模拟笔算,将每个运算符标记等级,计算时按照等级由高到低进行计算。加减运算为0级,乘除运算为1级,每进入一层括号等级加2。使用两个链表分别储存运算符与数字。主程序调用之前实现的两个模块,一个是链表,另一个是分数计算。链表代码在下一篇文章,只贴出主程序和分数计算部分。

    主程序,检查算式是否合法的函数未实现

      1 #include "list.h"
      2 #include "sz.h"
      3 
      4 /*内部类型、常量、函数*/
      5 
      6 #define LEVEL_NUM 20    //支持的运算级数
      7 
      8 typedef struct
      9 {
     10     List *oper;    //存运算符的链表,data段类型为Op *
     11     List *num;    //存数字的链表,data段类型为Fract *
     12     int oper_num[LEVEL_NUM];    //存每一级的运算符个数
     13 }Pack;
     14 
     15 typedef struct
     16 {
     17     char oper;
     18     int level;
     19 }Op;    //运算符及对应的级别,加减0级,乘除1级,每进入一层括号运算符对应的级别加2
     20 
     21 
     22 static void Convert(char equation[],Pack *pack);
     23 static int str2int(char str[],int start,int end);
     24 static int GetSE(char str[],int s,int flag);
     25 static void Compute(Pack *pack,Fract *ans);
     26 
     27 
     28 int main(void)
     29 {
     30     char equation[100];
     31     Fract ans;
     32     while(1)
     33     {
     34         scanf("%s",equation);
     35         calc(equation,&ans);
     36         printf("%d/%d
    ",ans.numer,ans.deno);
     37     }
     38     return 0;
     39 }
     40 
     41 void calc(char equation[],Fract *ans)
     42 {
     43     Pack pack;
     44 
     45     //检查及完善equation,该函数未实现!!
     46 
     47     //转换并存入链表
     48     Convert(equation,&pack);
     49 
     50     //使用链表计算,并释放
     51     Compute(&pack,ans);
     52 
     53 }
     54 
     55 //特别说明
     56 //对于"(-数字"这种形式,会导致str2int的参数start>end,正好会转化成"(0-数字"的形式
     57 //因此没有用库函数
     58 void Convert(char equation[],Pack *pack)
     59 {
     60     int i,base,start;
     61 
     62     Op *op;
     63     Fract *num;
     64 
     65     //初始化
     66     pack->num=CreateList();
     67     pack->oper=CreateList();
     68     for(i=0;i<LEVEL_NUM;i++)
     69         pack->oper_num[i]=0;
     70 
     71     start=GetSE(equation,0,1);
     72     base=0;    //存级别的基,每进入一层括号基加2
     73     for(i=0;equation[i];i++)
     74         switch(equation[i])
     75         {
     76         case '+':case '-':case '*':case '/':
     77             //添加运算符
     78             op=(Op *)malloc(sizeof(Op));
     79             op->oper=equation[i];
     80             op->level=base+
     81                 ( (equation[i]=='+'||equation[i]=='-')?0:1);
     82             AddNode(pack->oper,op,pack->oper->n);    //插入到链表尾
     83             pack->oper_num[op->level]++;
     84             
     85             //添加数字
     86             num=(Fract *)malloc(sizeof(Fract));
     87             num->numer=str2int(equation,start,GetSE(equation,i-1,-1));
     88             num->deno=1;
     89             AddNode(pack->num,num,pack->num->n);
     90             start=GetSE(equation,i+1,1);    //为下一个数字准备
     91             break;
     92         case '(':
     93             base+=2;
     94             break;
     95         case ')':
     96             base-=2;
     97             break;
     98         default:    //数字字符
     99             break;
    100         }
    101 
    102     //运算符和数字成对出现,存入最后多出的数字
    103     num=(Fract *)malloc(sizeof(Fract));
    104     num->numer=str2int(equation,start,GetSE(equation,i-1,-1));
    105     num->deno=1;
    106     AddNode(pack->num,num,pack->num->n);
    107 }
    108 
    109 
    110 //将由start和end脚标确定的字符串转换为整数
    111 int str2int(char str[],int start,int end)
    112 {
    113     int i,s=0;
    114     for(i=start;i<=end;i++)
    115         s=s*10+str[i]-'0';
    116     return s;
    117 }
    118 
    119 
    120 //从s开始向前或向后找第一个数字字符的角标
    121 //flag为1向后,-1向前
    122 int GetSE(char str[],int s,int flag)
    123 {
    124     int i;
    125     for(i=s;i>=0 && str[i] && !isdigit(str[i]);i+=flag)
    126         ;
    127     return i;
    128 }
    129 
    130 void Compute(Pack *pack,Fract *ans)
    131 {
    132     //前一运算符,运算符
    133     //第一个数字,第二个数字    
    134     Node *pop,*op,*num,*nnum;    
    135     int i;
    136 
    137     //找到最高不为0的一级
    138     for(i=LEVEL_NUM-1;i>=0 && !pack->oper_num[i];i--)
    139         ;
    140 
    141     for(;i>=0;i--)    //由高到低级依次计算
    142         for(pop=pack->oper->head,op=pack->oper->head->next,num=pack->num->head->next;
    143         pack->oper_num[i] ;    )
    144             if( ((Op*)(op->data))->level==i )    //找到级别为i的运算符
    145             {
    146                 pack->oper_num[i]--;
    147                 switch( ((Op*)(op->data))->oper)
    148                 {
    149                 //计算,结果存入第一个数中
    150                 case '+':Plus(num->data,num->next->data);
    151                     break;
    152                 case '-':Minus(num->data,num->next->data);
    153                     break;
    154                 case '*':Multiply(num->data,num->next->data);
    155                     break;
    156                 case '/':Divide(num->data,num->next->data);
    157                     break;
    158                 default:    
    159                     printf("
    Compute函数出现不可能运算符 %c
    ",((Op*)(op->data))->oper);
    160                     exit(0);
    161                     break;
    162                 }
    163 
    164                 //删除计算完成的运算符、数字
    165                 pack->num->n--;
    166                 pack->oper->n--;
    167                 pop->next=op->next;
    168                 nnum=num->next;
    169                 num->next=nnum->next;
    170                 free(nnum->data);free(op->data);
    171                 free(nnum);free(op);
    172 
    173                 op=pop->next;    //恢复op的指向
    174             }
    175             else    //没找到时继续遍历链表
    176                 pop=op,op=op->next,num=num->next;
    177 
    178     //计算完成后,仅剩一个的数字为结果,运算符链表没内容,储存运算符级别的个数的数组各元素为0
    179     if(pack->num->n!=1 || pack->oper->n || pack->oper_num[0])
    180     {
    181         printf("Compute函数内变量异常,数字个数 %d,运算符个数 %d,0级个数 %d",
    182                             pack->num->n,pack->oper->n,pack->oper_num[0]);
    183         exit(0);
    184     }
    185     (*ans)=*(Fract *)pack->num->head->next->data;
    186     DestroyList(pack->num);
    187     DestroyList(pack->oper);
    188 }
    sz.c
     1 #ifndef SZ_H
     2 #define SZ_H
     3 
     4 //只有calc函数对外,可以去掉主函数来当做一个计算模块使用
     5 //只要在项目中添加sz、list、fract
     6 
     7 #include <ctype.h>
     8 #include "fract.h"
     9 
    10 void calc(char equation[],Fract *ans);
    11 
    12 #endif
    sz.h

    分数计算部分

      1 #include "fract.h"
      2 
      3 static int commom_divisor(int a,int b);    //最大公约数
      4 static int common_multiple(int a,int b);//最小公倍数
      5 static void reduce(int *num1,int *num2);    //约分
      6 
      7 
      8 void Plus(Fract *num1,Fract *num2)
      9 {
     10     int deno;//公分母
     11     
     12     if(num1->numer==0)    //排除0值计算
     13     {
     14         *num1=*num2;
     15         return;
     16     }
     17     else if(num2->numer==0) return;
     18 
     19     deno=common_multiple(num1->deno,num2->deno);
     20     num1->numer=deno/num1->deno*num1->numer+deno/num2->deno*num2->numer;
     21     num1->deno=deno;
     22 
     23 }
     24 
     25 void Minus(Fract *num1,Fract *num2)
     26 {
     27     num2->numer=-num2->numer;
     28     Plus(num1,num2);
     29 }
     30 
     31 void Multiply(Fract *num1,Fract *num2)
     32 {
     33     if(num1->numer==0)return;
     34     else if(num2->numer==0)
     35     {
     36         num1->numer=0;
     37         return;
     38     }
     39 
     40     reduce(&num1->deno,&num2->numer);
     41     reduce(&num1->numer,&num2->deno);
     42 
     43     num1->numer*=num2->numer;
     44     num1->deno*=num2->deno;
     45 
     46 }
     47 
     48 void Divide(Fract *num1,Fract *num2)
     49 {
     50     int temp;
     51     if(num2->numer==0)
     52     {
     53         printf("除数不能为0
    ");
     54         exit(0);
     55     }
     56     temp=num2->numer;
     57     num2->numer=num2->deno;
     58     num2->deno=temp;
     59     Multiply(num1,num2);
     60 }
     61 
     62 
     63 static void reduce(int *num1,int *num2)    //约分并保持原来的正负号
     64 {
     65     int temp,i;
     66     
     67     /*i为0表示都为正,i为1表示num1为正,2表示num2为正,3表示都为负*/
     68     if(*num1<0)
     69     {
     70         *num1=-*num1;
     71         if(*num2<0)
     72         {
     73             *num2=-*num2;
     74             i=3;
     75         }
     76         else i=2;
     77     }
     78     else
     79         if(*num2<0)
     80         {
     81             *num2=-*num2;
     82             i=1;
     83         }
     84         else i=0;
     85 
     86     temp=commom_divisor(*num1,*num2);
     87     *num1/=temp;
     88     *num2/=temp;
     89 
     90     switch(i)
     91     {
     92         case 0:break;
     93         case 1:*num2=-*num2;break;
     94         case 2:*num1=-*num1;break;
     95         case 3:*num1=-*num1;*num2=-*num2;break;
     96     }
     97 }
     98 
     99 
    100 static int commom_divisor(int a,int b)
    101 {
    102      int temp,r;
    103      
    104     if(a<b)
    105     {
    106         temp=a;
    107         a=b;
    108         b=temp;
    109     }
    110     
    111     while((r=a%b))
    112     {
    113         a=b;
    114         b=r;
    115      }
    116      
    117     return b;
    118 }
    119 
    120 static int common_multiple(int a,int b)
    121 {
    122     return a*b/commom_divisor(a,b);
    123 }
    fract.c
     1 #ifndef FRACT_H
     2 #define FRACT_H
     3 
     4 #include <stdio.h>
     5 #include <stdlib.h>
     6 
     7 //如果有负号则在分子上
     8 typedef struct
     9 {
    10     int numer;    //分子
    11     int deno;    //分母
    12 }Fract;
    13 
    14 //分数的四则运算,结果存在num1中
    15 void Plus(Fract *num1,Fract *num2);
    16 void Minus(Fract *num1,Fract *num2);
    17 void Multiply(Fract *num1,Fract *num2);
    18 void Divide(Fract *num1,Fract *num2);
    19 
    20 #endif
    fract.h

    控制台程序源代码 sz.7z

    借用如鹏的对话框模版,及上面的计算器部分,实现的图形计算器

    代码及程序 calc.7z

  • 相关阅读:
    solr集群
    mybatis的逆向工程
    使用secureCRT上传下载
    Linux vim基本的使用方法
    非web下的PowerMockito单元测试
    打印日志
    集群
    免安装版tomcat安装成服务
    apache安装zip包安装(非exe)
    Java 性能优化(一)
  • 原文地址:https://www.cnblogs.com/zackcoder/p/3246384.html
Copyright © 2011-2022 走看看