支持括号、分数计算的四则运算计算器
用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\n",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("\nCompute函数出现不可能运算符 %c\n",((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 }
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
分数计算部分
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\n"); 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 }
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
控制台程序源代码 sz.7z
借用如鹏的对话框模版,及上面的计算器部分,实现的图形计算器
代码及程序 calc.7z